pax_global_header00006660000000000000000000000064146665502270014527gustar00rootroot0000000000000052 comment=567dc09fd3859de3d9c09456ee7b366c0d327eb6 gmmlib-intel-gmmlib-22.5.2/000077500000000000000000000000001466655022700154445ustar00rootroot00000000000000gmmlib-intel-gmmlib-22.5.2/.gitignore000066400000000000000000000000611466655022700174310ustar00rootroot00000000000000# compiled source# *.o *.a *.exe # *.orig *.rej gmmlib-intel-gmmlib-22.5.2/CMakeLists.txt000066400000000000000000000003701466655022700202040ustar00rootroot00000000000000cmake_minimum_required (VERSION 3.1 FATAL_ERROR) if (NOT DEFINED RUN_TEST_SUITE) option (RUN_TEST_SUITE "run test suite after install" ON) endif (NOT DEFINED RUN_TEST_SUITE) project(igfx_gmmumd) enable_testing() add_subdirectory(Source/GmmLib) gmmlib-intel-gmmlib-22.5.2/LICENSE.md000077500000000000000000000071331466655022700170570ustar00rootroot00000000000000MIT License Copyright (c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. Includes spdlog utility licensed under MIT The MIT License (MIT) Copyright (c) 2016 Gabi Melman. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. Copyright 2008, Google Inc. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of Google Inc. nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. gmmlib-intel-gmmlib-22.5.2/README.rst000066400000000000000000000060651466655022700171420ustar00rootroot00000000000000 Intel(R) Graphics Memory Management Library ******************************************* Introduction ============= The Intel(R) Graphics Memory Management Library provides device specific and buffer management for the Intel(R) Graphics Compute Runtime for OpenCL(TM) and the Intel(R) Media Driver for VAAPI. License ======== The Intel(R) Graphics Memory Management Library is distributed under the MIT Open Source license. You may obtain a copy of the License at: https://opensource.org/licenses/MIT Building ======== 1) Get gmmlib repository git clone https://github.com/intel/gmmlib.git 2) Change it to root directory ``$ cd gmmlib`` 3) Make a build directory ``$ mkdir build && cd build`` 4) Run the cmake command to prepare build files | ``$ cmake [-DCMAKE_BUILD_TYPE=Release | Debug | ReleaseInternal] ..`` | where, | -DCMAKE_BUILD_TYPE can be set to one build type flag at a time. | Example: | ``$ cmake -DCMAKE_BUILD_TYPE=Release ..``, For Release build 5) Build the project ``$ make -j"$(nproc)" (Also performs compile time ULT)`` Install ======= ``$ sudo make install`` This will install the following files (e.g. on Ubuntu): | -- Install configuration: "Release" | -- Installing: /usr/local/lib/libigdgmm.so.12.1.0 | -- Installing: /usr/local/lib/libigdgmm.so.12 | Not a stand alone software component. GmmLib is built as dynamic library for Intel media driver and Compute runtime for OpenCL Supported Platforms ------------------- Intel Atom and Core Processors supporting Gen8/Gen9/Gen10 graphics devices BDW (Broadwell) SKL (Skylake, Kaby Lake, Coffee Lake) BXTx (BXT: Broxton, APL: Apollo Lake, GLK: Gemini Lake) KBLx (KBL: Kaby Lake, CFL: Coffe Lake, WHL: Whiskey Lake, CML: Comet Lake, AML: Amber Lake) CNL (Cannonlake) ICL (Icelake) TGLx (TGL: Tiger Lake, RKL: Rocket Lake) ADLx (ADL-S: Alder Lake S, ADL-P: Alder Lake P, ADL-N: Alder Lake N) XE_LP (DG1) XE_HP (XE_HP_SDV) XE_HPC (PVC: Ponte Vecchio) XE_HPG (DG2, ACM: Alchemist) Xe_LPG (MTL: Meteor Lake, ARL: Arrow Lake) Xe2_HPG (BMG: Battlemage, LNL: Lunar Lake) Release Tags ============ Gmmlib Release tag versioning schema follows: | Tag ``intel-gmmlib-..`` will be stable release series with the same API and ABI version with only bug fixes where, | x = GMMLIB_API_MAJOR_VERSION + 10, | y = GMMLIB_API_MINOR_VERSION, | z = RELEASE NUMBER which is incremented as 0,1,2,...n for changes including new flag, bug fixes, etc. | | Example: | For GMM library ``libigdgmm.so.12.0.0``, | Tag = ``intel-gmmlib-22.0.0`` where, | 22 = GMMLIB_API_MAJOR_VERSION + 10 = 12 + 10 | 0 = GMMLIB_API_MINOR_VERSION | 0 = RELEASE NUMBER | On potential ABI break changes, | Tag ``intel-gmmlib-..`` becomes ``intel-gmmlib-.0.0`` | i.e ``intel-gmmlib-22.5.3`` becomes ``intel-gmmlib-23.0.0`` Known Issues and Limitations ============================ Current Gmmlib support only limited to Linux (*) Other names and brands may be claimed as property of others. --------------------------------------------------------------- gmmlib-intel-gmmlib-22.5.2/Security.md000066400000000000000000000006261466655022700176010ustar00rootroot00000000000000# Security Policy Intel is committed to rapidly addressing security vulnerabilities affecting our customers and providing clear guidance on the solution, impact, severity and mitigation. ## Reporting a Vulnerability Please report any security vulnerabilities in this project utilizing the guidelines [here](https://www.intel.com/content/www/us/en/security-center/vulnerability-handling-guidelines.html). gmmlib-intel-gmmlib-22.5.2/Source/000077500000000000000000000000001466655022700167045ustar00rootroot00000000000000gmmlib-intel-gmmlib-22.5.2/Source/Common/000077500000000000000000000000001466655022700201345ustar00rootroot00000000000000gmmlib-intel-gmmlib-22.5.2/Source/Common/AssertTracer/000077500000000000000000000000001466655022700225365ustar00rootroot00000000000000gmmlib-intel-gmmlib-22.5.2/Source/Common/AssertTracer/AssertTracer.cpp000066400000000000000000000313701466655022700256500ustar00rootroot00000000000000/*============================================================================== Copyright(c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ============================================================================*/ /* File Name: AssertTracer.cpp Abstract: These functions enables reporting asserts to system log in the debug driver build. Notes: \*****************************************************************************/ #if defined( _WIN32 ) && (defined( _DEBUG ) || defined( _RELEASE_INTERNAL )) #include "AssertTracer.h" #ifndef NOMINMAX #define NOMINMAX #endif #include // Windows.h defines MemoryFence as _mm_mfence, but this conflicts with llvm::sys::MemoryFence #undef MemoryFence #include #include #if defined( __GMM_KMD__ ) || defined( STATIC_DRIVER_MODEL ) #include"BufferedDbg.h" #include "igdKrnlEtwMacros.h" #endif //__GMM_KMD__ || STATIC_DRIVER_MODEL #if _DEBUG /*****************************************************************************\ Function: ReportAsserts Description: Sends message to the system log. Input: const char *expr - The expression passed to function. const char *file - The name of the file that is the origin of the expression. const char *func - The function from which call to this function was made. const unsigned long line - The line number from file, which caused this function call. const char *msg - Message passed to the system log. Output: void - None. \*****************************************************************************/ void __stdcall ReportAssert( const char *expr, const char *file, const char *func, const unsigned long line, const char *msg ) { #if !defined( __GMM_KMD__ ) && !defined( STATIC_DRIVER_MODEL )//We are in UMD, use the UMD implementation #if 0 HANDLE hEventLog = RegisterEventSourceA( NULL, "GFX Driver AssertTracer" ); char *wideMessage; if ( hEventLog != NULL ) { // Calculate length with hard coded max unsigned long length plus some safe space. size_t length = strlen( expr ) + strlen( file ) + strlen( func ) + strlen( msg ) + 15; // Checks against maximum string size for ReportEvent lpStrings parameter. // Cuts string to the limit size. uint32_t maxSizeReached = 0; if ( length > 31839 ) { length = 31839; maxSizeReached = 1; } wideMessage = ( char * ) malloc( sizeof( char ) * length ); if( wideMessage != NULL ) { // snprintf spec: "The resulting character string will be terminated with a null character" _snprintf_s( wideMessage, length, length / sizeof( char ), "%s:%lu\n%s\n%s\n%s", file, line, expr, func, msg); ReportEventA( hEventLog, EVENTLOG_INFORMATION_TYPE, 0, 0, NULL, 1, 0, ( LPCSTR* ) &wideMessage, NULL ); free( wideMessage ); } DeregisterEventSource( hEventLog ); } #endif //!define( WINDOWS_MOBILE ) // Windows Mobile has no implementation. Reference the parameters to remove the unreference param warnings. (void)expr; (void)file; (void)func; (void)line; (void)msg; #else //We are in KMD, use the KMD implementation BufDbgPrint("ASSERT_TRACE: %s::%s:%i : %s : %s\n", file, func, line, expr, msg); #endif //!defined( __GMM_KMD__ ) && !defined( STATIC_DRIVER_MODEL ) } #endif /*****************************************************************************\ Function: ReportAssertsETW Description: Sends message to the system log. Input: const unsigned long ComponentMask Contains the component id for which raised assert (KMD, MINIPORT..) const char *expr - The expression passed to function. const char *file - The name of the file that is the origin of the expression. const char *func - The function from which call to this function was made. const unsigned long line - The line number from file, which caused this function call. const char *msg - Message passed to the system log. Output: void - None. \*****************************************************************************/ void __stdcall ReportAssertETW( const unsigned short compId, const unsigned long compMsk, const char *expr, const char *file, const char *func, const unsigned long line, const char *msg) { #if !defined( __GMM_KMD__ ) && !defined( STATIC_DRIVER_MODEL ) //We are in UMD, use the UMD implementation // TODO: Add UMD code for ETW here. // Reference the parameters to remove the unreference param warnings. (void)compId; (void)compMsk; (void)expr; (void)file; (void)func; (void)line; (void)msg; #else //We are in KMD, use the KMD implementation // Log event if ETW session is active if (g_ulHDGraphics_SessionActive) { EtwAssertPrint(compId, compMsk, expr, file, func, line, msg); } #endif } #elif defined( __linux__ ) && defined( _RELEASE_INTERNAL ) && !defined( __ANDROID__ ) #include #include #include #include #include #include #include #include #include #define CALL_STACK_REPORT_SIZE 50 // maximal limit of call stack to be reported in case of assertion #define MAX_FUNCTION_NAME_LENGTH 100 // no worries it can be extended (relocated by driver if needed) #define MAX_SYSLOG_ENTRY_LENGTH 1000 // Syslog protocol recommends minimum entry length 1KB (ubuntu rsyslog message limit is about 2K) void LogAssertion( const char *function_name, const char *file_name, unsigned int line_number, const char *expr ) { std::string stack; std::string part1; std::string part2; std::size_t pos; void *buffer[CALL_STACK_REPORT_SIZE]; char *function_name_buffer = NULL; int nframes; // numer of frames to be returned char **strings; int i; int status; size_t length; const size_t stringLength = 4096; std::string oclAppCmdLine; nframes = backtrace( buffer, CALL_STACK_REPORT_SIZE ); strings = backtrace_symbols( buffer, nframes ); if( strings == NULL ) { perror( "Getting backtrace symbols error:" ); nframes = 0; } else { // Get Commandline of process (in that case OCL app) // from process info itself eg. /proc/self/cmdline oclAppCmdLine.reserve( stringLength ); std::ifstream fileCmdline( "/proc/self/cmdline", std::ifstream::binary ); if( fileCmdline.is_open() ) { oclAppCmdLine = std::string( std::istreambuf_iterator< char >( fileCmdline ), std::istreambuf_iterator< char >() ); if( oclAppCmdLine.size() > 0 ) { // Trim last \0 character oclAppCmdLine.resize( oclAppCmdLine.size() - 1 ); // Format of /proc/self/cmdline is that args are separated with '\0' // so for nicer printing we replace zeros with spaces (without terminating 0) std::replace( oclAppCmdLine.begin(), oclAppCmdLine.end(), '\0', ' ' ); } else { fprintf( stderr, "Getting Commandline of OCL app error: Error reading /proc/self/cmdline\n" ); } } else { fprintf( stderr, "Getting Commandline of OCL app error:" ); } } // allocation by malloc is suggessted by documentation as abi function may do some relocation function_name_buffer = ( char * )malloc( MAX_FUNCTION_NAME_LENGTH ); if( function_name_buffer == NULL ) { // Not enough memory to get small allocation then do not print stack nframes = 0; } else { length = MAX_FUNCTION_NAME_LENGTH; memset( function_name_buffer, 0, length ); } for( i = 0; i < nframes; ++i ) { // Generate signature of given stack frame eg. #0 #1 etc... std::stringstream framePromptBuilder; framePromptBuilder << "#" << i << " "; const std::string &framePrompt = framePromptBuilder.str(); // demangle name eg. split stack frame into two pieces part1 = strings[i]; pos = part1.find( "(" ); if( pos != std::string::npos ) { // For final level instead of binary print whole commandline // if were able to get one if( ( i == nframes - 1 ) && ( !oclAppCmdLine.empty() ) ) { //..call stack's part1 contains "(" so we add it here manualy stack.append( ( oclAppCmdLine.insert( 0, "COMMANDLINE(" ) ).c_str() ); } else { // part1 contains everything before section to be demangled part1 = part1.substr( 0, pos + 1 ); stack.append(framePrompt); stack.append( part1 ); } // part2 contains string to be demangled part2 = strings[i]; part2 = part2.substr( pos + 1 ); pos = part2.find( "+" ); // Final level may not have any function (static functions are not exposed) if( pos != std::string::npos ) { part2 = part2.substr( 0, pos ); function_name_buffer = abi::__cxa_demangle( part2.c_str(), function_name_buffer, &length, &status ); // in case of error during demangling attach mangled name if( status != 0 ) { stack.append( part2 ); } else { stack.append( function_name_buffer ); } stack.append( "())" ); free( function_name_buffer ); function_name_buffer = NULL; } else { // if there was no function then attach ")" stack.append( ")" ); } } else { if( ( i == nframes - 1 ) && ( !oclAppCmdLine.empty() ) ) { stack.append( ( oclAppCmdLine.insert( 0, "COMMANDLINE(" ) ).c_str() ); stack.append( ")" ); } else { stack.append(framePrompt); stack.append( strings[i] ); } } stack.append( " " ); } //Compose full message.. std::string fullMsg = "File: "; std::string syslogEntry; fullMsg += file_name; fullMsg += " line: "; std::stringstream lineStr; lineStr << line_number; fullMsg += lineStr.str(); fullMsg += " function: "; fullMsg += function_name; fullMsg += " expr: "; fullMsg += expr; fullMsg += " "; fullMsg += stack.c_str(); // split it into chunks we can send openlog( "OpenCL", LOG_PID, LOG_USER ); pos = 0; int numberOfChunks = ( fullMsg.length() / MAX_SYSLOG_ENTRY_LENGTH ) + 1; while( pos < fullMsg.length() ) { syslogEntry = fullMsg.substr( pos, MAX_SYSLOG_ENTRY_LENGTH ); // Add chunk ID / part number and send to syslog syslog( LOG_MAKEPRI( LOG_USER, LOG_ERR ), "[%zd/%d]%s", ( pos / MAX_SYSLOG_ENTRY_LENGTH + 1 ), numberOfChunks, syslogEntry.c_str() ); pos += MAX_SYSLOG_ENTRY_LENGTH; } closelog(); // backtrace_symbols allocates memory in a malloc like way sop it should be freed free( strings ); strings = NULL; } #endif //defined( _WIN32 ) && defined( _DEBUG ) gmmlib-intel-gmmlib-22.5.2/Source/Common/AssertTracer/AssertTracer.h000066400000000000000000000121161466655022700253120ustar00rootroot00000000000000/*============================================================================== Copyright(c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ============================================================================*/ /* File Name: AssertTracer.h Abstract: These functions enables reporting asserts to system log in the debug driver build. Notes: \*****************************************************************************/ #ifndef _ASSERT_TRACER_H_ #define _ASSERT_TRACER_H_ #if defined( _WIN32 ) && (defined( _DEBUG ) || defined(_RELEASE_INTERNAL)) #if !defined( __GMM_KMD__ ) && !defined( STATIC_DRIVER_MODEL ) && !defined( LHDM ) #include // Windows.h defines MemoryFence as _mm_mfence, but this conflicts with llvm::sys::MemoryFence #undef MemoryFence #include #include #endif #undef REPORT_ASSERT_MSG #define REPORT_ASSERT_MSG( expr, msg ) \ if ( !( expr ) ) \ { \ ReportAssert( #expr, __FILE__, __FUNCTION__, __LINE__, #msg ); \ } #undef REPORT_ASSERT #define REPORT_ASSERT( expr ) \ if ( !( expr ) ) \ { \ ReportAssert( #expr, __FILE__, __FUNCTION__, __LINE__, "" ); \ } #undef REPORT_ASSERT_MSG_ETW #define REPORT_ASSERT_MSG_ETW( compId, compMsk, expr, msg ) \ if (!(expr)) \ { \ ReportAssertETW( compId, compMsk, #expr, __FILE__, __FUNCTION__, __LINE__, #msg ); \ } #undef REPORT_ASSERT_ETW #define REPORT_ASSERT_ETW( compId, compMsk, expr ) \ if (!(expr)) \ { \ ReportAssertETW( compId, compMsk, #expr, __FILE__, __FUNCTION__, __LINE__, "" ); \ } #ifdef __cplusplus extern "C" { #endif void __stdcall ReportAssert( const char *expr, const char *file, const char *func, const unsigned long line, const char *msg ); void __stdcall ReportAssertETW(const unsigned short compId, const unsigned long compMsk, const char *expr, const char *file, const char *func, const unsigned long line, const char *msg ); #ifdef __cplusplus } #endif #elif defined( __linux__ ) && defined( _RELEASE_INTERNAL ) && !defined( __ANDROID__ ) // do while() is missing ";" at the end and this is intentional // As invoking assert looks like this: assert(expr); So semicolon will // be stuck to do.. while() and that way sorting out possible // problems when assert is used as block in one liner conditions #define REPORT_ASSERT( expr ) \ do { \ if( !( expr ) ) \ { \ LogAssertion( __FUNCTION__, __FILE__, __LINE__, #expr ); \ } \ } while( 0 ) #define REPORT_ASSERT_MSG( expr, msg ) REPORT_ASSERT( expr ) #define REPORT_ASSERT_ETW( CompId, compMsk, expr) void LogAssertion( const char *function_name, const char *file_name, unsigned int line_number, const char *expr ); #else #define REPORT_ASSERT_MSG( expr, msg ) #define REPORT_ASSERT( expr ) #define REPORT_ASSERT_MSG_ETW( compMsk, expr, msg ) #define REPORT_ASSERT_ETW( CompId, compMsk, expr ) #endif // defined( _WIN32 ) && defined( _DEBUG ) #endif //_ASSERT_TRACER_H_ gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/000077500000000000000000000000001466655022700200535ustar00rootroot00000000000000gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/CMakeLists.txt000066400000000000000000000653771466655022700226350ustar00rootroot00000000000000 # Copyright(c) 2017 Intel Corporation # Permission is hereby granted, free of charge, to any person obtaining a # copy of this software and associated documentation files(the "Software"), # to deal in the Software without restriction, including without limitation # the rights to use, copy, modify, merge, publish, distribute, sublicense, # and / or sell copies of the Software, and to permit persons to whom the # Software is furnished to do so, subject to the following conditions: # The above copyright notice and this permission notice shall be included # in all copies or substantial portions of the Software. # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS # OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL # THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR # OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, # ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR # OTHER DEALINGS IN THE SOFTWARE. cmake_minimum_required(VERSION 3.5) project(igfx_gmmumd) # GmmLib Api Version used for so naming set(GMMLIB_API_MAJOR_VERSION 12) set(GMMLIB_API_MINOR_VERSION 5) if(NOT DEFINED MAJOR_VERSION) set(MAJOR_VERSION 12) endif() if(NOT DEFINED MINOR_VERSION) set(MINOR_VERSION 5) endif() if(NOT DEFINED PATCH_VERSION) set(PATCH_VERSION 0) endif() if(NOT DEFINED GMMLIB_API_PATCH_VERSION) set(GMMLIB_API_PATCH_VERSION ${PATCH_VERSION}) endif() # The Gmmlib dll is generated as libigdgmm.so... where, # = GMMLIB_API_MAJOR_VERSION # = GMMLIB_API_MINOR_VERSION # = GMMLIB_API_PATCH_VERSION # # Example: libigdgmm.so.12.0.0 # 12 = GMMLIB_API_MAJOR_VERSION # 0 = GMMLIB_API_MINOR_VERSION # 0 = GMMLIB_API_PATCH_VERSION # # Library version update # - increment major for any ABI change # - increment minor for any interface change (e.g. new/modified function) # # Example: # On potential ABI break changes # # libigdgmm.so..y.z becomes libigdgmm.so..0.0 # i.e libigdgmm.so.12.5.0 becomes libigdgmm.so.13.0.0 message(STATUS "API version: ${GMMLIB_API_MAJOR_VERSION}.${GMMLIB_API_MINOR_VERSION}.${GMMLIB_API_PATCH_VERSION}") message(STATUS "Package version: ${MAJOR_VERSION}.${MINOR_VERSION}.${PATCH_VERSION}") if(NOT DEFINED BS_USE_OSDM_BUILD_SYSTEM) if(DEFINED ENV{BS_USE_OSDM_BUILD_SYSTEM}) set(BS_USE_OSDM_BUILD_SYSTEM "$ENV{BS_USE_OSDM_BUILD_SYSTEM}") else() set(BS_USE_OSDM_BUILD_SYSTEM FALSE) endif() endif() # begin -- label bldsys file prologue # WARNING: The "project" statement triggers reading of CMAKE_TOOLCHAIN_FILE # and so must precede the inclusion below of bs_init.cmake . function(bs_find_build_system gfx_dev_dir build_sys_dir build_sys_inc) # If we are not building as a standalone project if(DEFINED GFX_DEVELOPMENT_DIR) set(_bs_gfx_development_dir "${GFX_DEVELOPMENT_DIR}") elseif(DEFINED ENV{GFX_DEVELOPMENT_DIR}) set(_bs_gfx_development_dir "$ENV{GFX_DEVELOPMENT_DIR}") else() get_filename_component(_bs_cur_cmake_dir "${CMAKE_CURRENT_LIST_FILE}" PATH) get_filename_component(_bs_parent_dir "${_bs_cur_cmake_dir}" DIRECTORY) set(_bs_gfx_dir_found false) while(NOT _bs_gfx_dir_found) set(_bs_bldsys_dir "${_bs_parent_dir}/Tools/bldsys") if(EXISTS ${_bs_bldsys_dir}) set(_bs_gfx_development_dir ${_bs_parent_dir}) set(_bs_gfx_dir_found true) break() endif() get_filename_component(_bs_parent_dir "${_bs_parent_dir}" DIRECTORY) if(${_bs_parent_dir} STREQUAL "/") break() endif() endwhile(NOT _bs_gfx_dir_found) if (NOT _bs_gfx_development_dir) message(FATAL_ERROR "GFX_DEVELOPMENT_DIR not found (${_bs_gfx_development_dir}) - exiting!") exit(1) endif() endif() set(${gfx_dev_dir} "${_bs_gfx_development_dir}" PARENT_SCOPE) set(${build_sys_dir} "${_bs_gfx_development_dir}/Tools/bldsys" PARENT_SCOPE) set(${build_sys_inc} "${_bs_gfx_development_dir}/Tools/bldsys/include" PARENT_SCOPE) endfunction(bs_find_build_system) bs_find_build_system(GFX_DEVELOPMENT_DIR BUILD_SYS_DIR BUILD_SYS_INC) include(${BUILD_SYS_DIR}/bs_init.cmake) include(${BUILD_SYS_INC}/bs_dir_names.cmake) # file prologue done set(CMAKE_DISABLE_SOURCE_CHANGES ON) set(CMAKE_DISABLE_IN_SOURCE_BUILD ON) ################################################################################ # Define GMM_DLL Target ################################################################################ set (GMM_LIB_DLL_NAME igfx_gmmumd_dll) macro(GmmLibSetTargetConfig libTarget) if(TARGET ${libTarget}) set_property(TARGET ${libTarget} APPEND PROPERTY COMPILE_DEFINITIONS $<$: _RELEASE> $<$: _RELEASE_INTERNAL> $<$: _DEBUG> ) endif() endmacro() if(CMAKE_CONFIGURATION_TYPES) set( CMAKE_CONFIGURATION_TYPES "Debug" "Release" "ReleaseInternal") set( CMAKE_CONFIGURATION_TYPES "${CMAKE_CONFIGURATION_TYPES}" CACHE STRING "Reset the configurations to what we need" FORCE) else() if("${BUILD_TYPE}" STREQUAL "release") set(CMAKE_BUILD_TYPE "Release") elseif("${BUILD_TYPE}" STREQUAL "release-internal") set(CMAKE_BUILD_TYPE "ReleaseInternal") elseif("${BUILD_TYPE}" STREQUAL "debug") set(CMAKE_BUILD_TYPE "Debug") elseif("${BUILD_TYPE}" STREQUAL "RelWithDebInfo") set(CMAKE_BUILD_TYPE "RelWithDebInfo") elseif("${BUILD_TYPE}" STREQUAL "MinSizeRel") set(CMAKE_BUILD_TYPE "MinSizeRel") endif() endif() set(GMMLIB_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}) if(CMAKE_SIZEOF_VOID_P EQUAL 8) set (GMMLIB_ARCH "64") else() set (GMMLIB_ARCH "32") endif() if (${CMAKE_SYSTEM_PROCESSOR} MATCHES "^aarch") set(GMMLIB_MARCH "armv8-a+fp+simd") elseif("${GMMLIB_MARCH}" STREQUAL "") set(GMMLIB_MARCH "corei7") endif() MESSAGE("platform: ${CMAKE_HOST_SYSTEM_NAME}") MESSAGE("source_dir: ${BS_DIR_GMMLIB}") MESSAGE("arch: ${GMMLIB_ARCH}") MESSAGE("build type: ${CMAKE_BUILD_TYPE}") MESSAGE("SourceConfiguration:") MESSAGE("CommonDir: ${BS_DIR_COMMON}") MESSAGE("IncDir: ${BS_DIR_INC}") # If '-DGMM_DYNAMIC_MOCS_TABLE=TRUE' (default is FALSE) passed to cmake # configure command gmmlib will generate MOCS table dynamically depending on # usage requests (Gen9). In this case on Linux user responsibility is to # make sure that generated MOCS table is programmed on KMD level. if (GMM_DYNAMIC_MOCS_TABLE) MESSAGE("MOCS table: Dynamic") add_definitions(-DGMM_DYNAMIC_MOCS_TABLE) else() MESSAGE("MOCS table: Static") endif() if(DEFINED UFO_DRIVER_OPTIMIZATION_LEVEL) if(${UFO_DRIVER_OPTIMIZATION_LEVEL} GREATER 0) add_definitions(-DGMM_GFX_GEN=${GFXGEN}) endif() endif() set(HEADERS_ ${BS_DIR_GMMLIB}/CachePolicy/GmmCachePolicyConditionals.h ${BS_DIR_GMMLIB}/CachePolicy/GmmCachePolicyResourceUsageDefinitions.h ${BS_DIR_GMMLIB}/CachePolicy/GmmCachePolicyUndefineConditionals.h ${BS_DIR_GMMLIB}/CachePolicy/GmmGen10CachePolicy.h ${BS_DIR_GMMLIB}/CachePolicy/GmmGen11CachePolicy.h ${BS_DIR_GMMLIB}/CachePolicy/GmmGen12CachePolicy.h ${BS_DIR_GMMLIB}/CachePolicy/GmmXe_LPGCachePolicy.h ${BS_DIR_GMMLIB}/CachePolicy/GmmXe2_LPGCachePolicy.h ${BS_DIR_GMMLIB}/CachePolicy/GmmGen12dGPUCachePolicy.h ${BS_DIR_GMMLIB}/CachePolicy/GmmGen8CachePolicy.h ${BS_DIR_GMMLIB}/CachePolicy/GmmGen9CachePolicy.h ${BS_DIR_GMMLIB}/inc/External/Common/CachePolicy/GmmCachePolicyGen10.h ${BS_DIR_GMMLIB}/inc/External/Common/CachePolicy/GmmCachePolicyGen11.h ${BS_DIR_GMMLIB}/inc/External/Common/CachePolicy/GmmCachePolicyGen12.h ${BS_DIR_GMMLIB}/inc/External/Common/CachePolicy/GmmCachePolicyXe_LPG.h ${BS_DIR_GMMLIB}/inc/External/Common/CachePolicy/GmmCachePolicyXe2_LPG.h ${BS_DIR_GMMLIB}/inc/External/Common/CachePolicy/GmmCachePolicyGen12dGPU.h ${BS_DIR_GMMLIB}/inc/External/Common/CachePolicy/GmmCachePolicyGen8.h ${BS_DIR_GMMLIB}/inc/External/Common/CachePolicy/GmmCachePolicyGen9.h ${BS_DIR_GMMLIB}/inc/External/Common/GmmCachePolicy.h ${BS_DIR_GMMLIB}/inc/External/Common/GmmCachePolicyCommon.h ${BS_DIR_GMMLIB}/inc/External/Common/GmmCachePolicyExt.h ${BS_DIR_GMMLIB}/inc/External/Common/GmmCommonExt.h ${BS_DIR_GMMLIB}/inc/External/Common/GmmConst.h ${BS_DIR_GMMLIB}/inc/External/Common/GmmDebug.h ${BS_DIR_GMMLIB}/inc/External/Common/GmmFormatTable.h ${BS_DIR_GMMLIB}/inc/External/Common/GmmHw.h ${BS_DIR_GMMLIB}/inc/External/Common/GmmInfo.h ${BS_DIR_GMMLIB}/inc/External/Common/GmmInfoExt.h ${BS_DIR_GMMLIB}/inc/External/Common/GmmInternal.h ${BS_DIR_GMMLIB}/inc/External/Common/GmmMemAllocator.hpp ${BS_DIR_GMMLIB}/inc/External/Common/GmmPlatformExt.h ${BS_DIR_GMMLIB}/inc/External/Common/GmmProto.h ${BS_DIR_GMMLIB}/inc/External/Common/GmmResourceFlags.h ${BS_DIR_GMMLIB}/inc/External/Common/GmmResourceInfo.h ${BS_DIR_GMMLIB}/inc/External/Common/GmmResourceInfoCommon.h ${BS_DIR_GMMLIB}/inc/External/Common/GmmResourceInfoExt.h ${BS_DIR_GMMLIB}/inc/External/Common/GmmTextureExt.h ${BS_DIR_GMMLIB}/inc/External/Common/GmmUtil.h ${BS_DIR_GMMLIB}/inc/External/Linux/GmmResourceInfoLin.h ${BS_DIR_GMMLIB}/inc/External/Linux/GmmResourceInfoLinExt.h ${BS_DIR_GMMLIB}/inc/Internal/Common/Platform/GmmGen10Platform.h ${BS_DIR_GMMLIB}/inc/Internal/Common/Platform/GmmGen11Platform.h ${BS_DIR_GMMLIB}/inc/Internal/Common/Platform/GmmGen12Platform.h ${BS_DIR_GMMLIB}/inc/Internal/Common/Platform/GmmGen8Platform.h ${BS_DIR_GMMLIB}/inc/Internal/Common/Platform/GmmGen9Platform.h ${BS_DIR_GMMLIB}/inc/Internal/Common/Texture/GmmGen10TextureCalc.h ${BS_DIR_GMMLIB}/inc/Internal/Common/Texture/GmmGen11TextureCalc.h ${BS_DIR_GMMLIB}/inc/Internal/Common/Texture/GmmGen12TextureCalc.h ${BS_DIR_GMMLIB}/inc/Internal/Common/Texture/GmmXe_LPGTextureCalc.h ${BS_DIR_GMMLIB}/inc/Internal/Common/Texture/GmmGen7TextureCalc.h ${BS_DIR_GMMLIB}/inc/Internal/Common/Texture/GmmGen8TextureCalc.h ${BS_DIR_GMMLIB}/inc/Internal/Common/Texture/GmmGen9TextureCalc.h ${BS_DIR_GMMLIB}/inc/Internal/Common/Texture/GmmTextureCalc.h ${BS_DIR_GMMLIB}/inc/Internal/Common/GmmCommonInt.h ${BS_DIR_GMMLIB}/inc/Internal/Common/GmmLibInc.h ${BS_DIR_GMMLIB}/inc/GmmLib.h ${BS_DIR_GMMLIB}/inc/Internal/Common/GmmLogger.h ) set(UMD_HEADERS ${HEADERS_} ${BS_DIR_GMMLIB}/inc/External/Common/GmmPageTableMgr.h ${BS_DIR_GMMLIB}/inc/External/Common/GmmClientContext.h ${BS_DIR_GMMLIB}/inc/External/Common/GmmLibDll.h ${BS_DIR_GMMLIB}/inc/External/Common/GmmLibDllName.h ) set(SOURCES_ ${BS_DIR_COMMON}/AssertTracer/AssertTracer.cpp ${BS_DIR_GMMLIB}/CachePolicy/GmmCachePolicy.cpp ${BS_DIR_GMMLIB}/CachePolicy/GmmCachePolicyCommon.cpp ${BS_DIR_GMMLIB}/CachePolicy/GmmGen8CachePolicy.cpp ${BS_DIR_GMMLIB}/CachePolicy/GmmGen9CachePolicy.cpp ${BS_DIR_GMMLIB}/CachePolicy/GmmGen10CachePolicy.cpp ${BS_DIR_GMMLIB}/CachePolicy/GmmGen11CachePolicy.cpp ${BS_DIR_GMMLIB}/CachePolicy/GmmGen12CachePolicy.cpp ${BS_DIR_GMMLIB}/CachePolicy/GmmXe_LPGCachePolicy.cpp ${BS_DIR_GMMLIB}/CachePolicy/GmmXe2_LPGCachePolicy.cpp ${BS_DIR_GMMLIB}/CachePolicy/GmmGen12dGPUCachePolicy.cpp ${BS_DIR_GMMLIB}/Platform/GmmGen11Platform.cpp ${BS_DIR_GMMLIB}/Platform/GmmGen12Platform.cpp ${BS_DIR_GMMLIB}/Platform/GmmGen8Platform.cpp ${BS_DIR_GMMLIB}/Platform/GmmGen9Platform.cpp ${BS_DIR_GMMLIB}/Platform/GmmGen10Platform.cpp ${BS_DIR_GMMLIB}/Platform/GmmPlatform.cpp ${BS_DIR_GMMLIB}/Resource/GmmResourceInfo.cpp ${BS_DIR_GMMLIB}/Resource/GmmResourceInfoCommon.cpp ${BS_DIR_GMMLIB}/Resource/GmmResourceInfoCommonEx.cpp ${BS_DIR_GMMLIB}/Resource/GmmRestrictions.cpp ${BS_DIR_GMMLIB}/Resource/Linux/GmmResourceInfoLinCWrapper.cpp ${BS_DIR_GMMLIB}/Texture/GmmGen7Texture.cpp ${BS_DIR_GMMLIB}/Texture/GmmGen8Texture.cpp ${BS_DIR_GMMLIB}/Texture/GmmGen9Texture.cpp ${BS_DIR_GMMLIB}/Texture/GmmGen10Texture.cpp ${BS_DIR_GMMLIB}/Texture/GmmGen11Texture.cpp ${BS_DIR_GMMLIB}/Texture/GmmGen12Texture.cpp ${BS_DIR_GMMLIB}/Texture/GmmXe_LPGTexture.cpp ${BS_DIR_GMMLIB}/Texture/GmmTexture.cpp ${BS_DIR_GMMLIB}/Texture/GmmTextureAlloc.cpp ${BS_DIR_GMMLIB}/Texture/GmmTextureSpecialCases.cpp ${BS_DIR_GMMLIB}/Texture/GmmTextureOffset.cpp ${BS_DIR_GMMLIB}/GlobalInfo/GmmInfo.cpp ${BS_DIR_GMMLIB}/Utility/CpuSwizzleBlt/CpuSwizzleBlt.c ${BS_DIR_GMMLIB}/Utility/GmmLog/GmmLog.cpp ${BS_DIR_GMMLIB}/Utility/GmmUtility.cpp ) set(UMD_SOURCES ${SOURCES_} ${BS_DIR_GMMLIB}/TranslationTable/GmmAuxTable.cpp ${BS_DIR_GMMLIB}/TranslationTable/GmmPageTableMgr.cpp ${BS_DIR_GMMLIB}/TranslationTable/GmmUmdTranslationTable.cpp ${BS_DIR_GMMLIB}/GlobalInfo/GmmClientContext.cpp ${BS_DIR_GMMLIB}/GlobalInfo/GmmLibDllMain.cpp ) source_group("Source Files\\Cache Policy\\Client Files" FILES ${BS_DIR_GMMLIB}/CachePolicy/GmmCachePolicyResourceUsageDefinitions.h ${BS_DIR_GMMLIB}/CachePolicy/GmmGen10CachePolicy.h ${BS_DIR_GMMLIB}/CachePolicy/GmmGen11CachePolicy.h ${BS_DIR_GMMLIB}/CachePolicy/GmmGen12CachePolicy.h ${BS_DIR_GMMLIB}/CachePolicy/GmmXe_LPGCachePolicy.h ${BS_DIR_GMMLIB}/CachePolicy/GmmXe2_LPGCachePolicy.h ${BS_DIR_GMMLIB}/CachePolicy/GmmGen12dGPUCachePolicy.h ${BS_DIR_GMMLIB}/CachePolicy/GmmGen8CachePolicy.h ${BS_DIR_GMMLIB}/CachePolicy/GmmGen9CachePolicy.h ) source_group("Source Files\\Cache Policy" ${BS_DIR_GMMLIB}/CachePolicy/*.cpp) source_group("Source Files\\Global" ${BS_DIR_GMMLIB}/GlobalInfo/.*) source_group("Source Files\\Platform" ${BS_DIR_GMMLIB}/Platform/.*) source_group("Source Files\\Texture" ${BS_DIR_GMMLIB}/Texture/.*) source_group("Source Files\\Translation Table" ${BS_DIR_GMMLIB}/TranslationTable/.*) source_group("Source Files\\Utility" ${BS_DIR_GMMLIB}/Utility/.*) source_group("Source Files\\Resource" FILES ${BS_DIR_GMMLIB}/Resource/GmmResourceInfo.cpp ${BS_DIR_GMMLIB}/Resource/GmmResourceInfoCommon.cpp ${BS_DIR_GMMLIB}/Resource/GmmResourceInfoCommonEx.cpp ${BS_DIR_GMMLIB}/Resource/GmmRestrictions.cpp) source_group("Source Files\\Resource\\Linux" FILES ${BS_DIR_GMMLIB}/Resource/Linux/GmmResourceInfoLinCWrapper.cpp ) source_group("Source Files\\TranslationTable\\Windows" FILES ${BS_DIR_GMMLIB}/TranslationTable/GmmAuxTable.cpp ${BS_DIR_GMMLIB}/TranslationTable/GmmPageTableMgr.cpp ${BS_DIR_GMMLIB}/TranslationTable/GmmUmdTranslationTable.cpp) source_group("Source Files\\TranslationTable" FILES ${BS_DIR_GMMLIB}/TranslationTable/GmmUmdTranslationTable.h) source_group("Header Files\\External\\Common" FILES ${BS_DIR_GMMLIB}/inc/External/Common/GmmCachePolicy.h ${BS_DIR_GMMLIB}/inc/External/Common/GmmCachePolicyCommon.h ${BS_DIR_GMMLIB}/inc/External/Common/GmmCachePolicyExt.h ${BS_DIR_GMMLIB}/inc/External/Common/GmmCommonExt.h ${BS_DIR_GMMLIB}/inc/External/Common/GmmConst.h ${BS_DIR_GMMLIB}/inc/External/Common/GmmDebug.h ${BS_DIR_GMMLIB}/inc/External/Common/GmmFormatTable.h ${BS_DIR_GMMLIB}/inc/External/Common/GmmHw.h ${BS_DIR_GMMLIB}/inc/External/Common/GmmInfo.h ${BS_DIR_GMMLIB}/inc/External/Common/GmmInfoExt.h ${BS_DIR_GMMLIB}/inc/External/Common/GmmInternal.h ${BS_DIR_GMMLIB}/inc/External/Common/GmmMemAllocator.hpp ${BS_DIR_GMMLIB}/inc/External/Common/GmmPageTableMgr.h ${BS_DIR_GMMLIB}/inc/External/Common/GmmPlatformExt.h ${BS_DIR_GMMLIB}/inc/External/Common/GmmResourceFlags.h ${BS_DIR_GMMLIB}/inc/External/Common/GmmResourceInfo.h ${BS_DIR_GMMLIB}/inc/External/Common/GmmResourceInfoCommon.h ${BS_DIR_GMMLIB}/inc/External/Common/GmmResourceInfoExt.h ${BS_DIR_GMMLIB}/inc/External/Common/GmmTextureExt.h ${BS_DIR_GMMLIB}/inc/External/Common/GmmUtil.h ${BS_DIR_GMMLIB}/inc/External/Common/GmmClientContext.h ) source_group("Header Files" FILES ${BS_DIR_GMMLIB}/inc/GmmLib.h ) source_group("Header Files\\External\\Common\\Cache Policy" FILES ${BS_DIR_GMMLIB}/inc/External/Common/CachePolicy/GmmCachePolicyGen10.h ${BS_DIR_GMMLIB}/inc/External/Common/CachePolicy/GmmCachePolicyGen11.h ${BS_DIR_GMMLIB}/inc/External/Common/CachePolicy/GmmCachePolicyGen12.h ${BS_DIR_GMMLIB}/inc/External/Common/CachePolicy/GmmCachePolicyXe_LPG.h ${BS_DIR_GMMLIB}/inc/External/Common/CachePolicy/GmmCachePolicyXe2_LPG.h ${BS_DIR_GMMLIB}/inc/External/Common/CachePolicy/GmmCachePolicyGen12dGPU.h ${BS_DIR_GMMLIB}/inc/External/Common/CachePolicy/GmmCachePolicyGen8.h ${BS_DIR_GMMLIB}/inc/External/Common/CachePolicy/GmmCachePolicyGen9.h ) source_group("Header Files\\External\\Linux" FILES ${BS_DIR_GMMLIB}/inc/External/Linux/GmmResourceInfoLin.h ${BS_DIR_GMMLIB}/inc/External/Linux/GmmResourceInfoLinExt.h ) source_group("Header Files\\Internal\\Common" FILES ${BS_DIR_GMMLIB}/inc/Internal/Common/GmmLibInc.h ${BS_DIR_GMMLIB}/inc/Internal/Common/GmmProto.h ) source_group("Header Files\\Internal\\Common\\Platform" FILES ${BS_DIR_GMMLIB}/inc/Internal/Common/Platform/GmmGen10Platform.h ${BS_DIR_GMMLIB}/inc/Internal/Common/Platform/GmmGen11Platform.h ${BS_DIR_GMMLIB}/inc/Internal/Common/Platform/GmmGen12Platform.h ${BS_DIR_GMMLIB}/inc/Internal/Common/Platform/GmmGen8Platform.h ${BS_DIR_GMMLIB}/inc/Internal/Common/Platform/GmmGen9Platform.h ) source_group("Header Files\\Internal\\Common\\Texture" FILES ${BS_DIR_GMMLIB}/inc/Internal/Common/Texture/GmmGen10TextureCalc.h ${BS_DIR_GMMLIB}/inc/Internal/Common/Texture/GmmGen11TextureCalc.h ${BS_DIR_GMMLIB}/inc/Internal/Common/Texture/GmmGen12TextureCalc.h ${BS_DIR_GMMLIB}/inc/Internal/Common/Texture/GmmXe_LPGTextureCalc.h ${BS_DIR_GMMLIB}/inc/Internal/Common/Texture/GmmGen7TextureCalc.h ${BS_DIR_GMMLIB}/inc/Internal/Common/Texture/GmmGen8TextureCalc.h ${BS_DIR_GMMLIB}/inc/Internal/Common/Texture/GmmGen9TextureCalc.h ${BS_DIR_GMMLIB}/inc/Internal/Common/Texture/GmmTextureCalc.h ) include_directories(BEFORE ${BS_DIR_GMMLIB}/) include_directories(BEFORE ${PROJECT_SOURCE_DIR}) include_directories( ${BS_DIR_GMMLIB} ${BS_DIR_GMMLIB}/Utility/GmmLog ${BS_DIR_GMMLIB}/inc ${BS_DIR_GMMLIB}/Utility ${BS_DIR_GMMLIB}/GlobalInfo ${BS_DIR_GMMLIB}/Texture ${BS_DIR_GMMLIB}/Resource ${BS_DIR_GMMLIB}/Platform ${BS_DIR_UTIL} ${BS_DIR_INC} ${BS_DIR_INC}/common ${BS_DIR_INC}/umKmInc ${BS_DIR_INSTALL} #${BS_DIR_ANDROID}/include ) if(${CMAKE_SYSTEM_PROCESSOR} MATCHES "^aarch") include_directories(${GFX_DEVELOPMENT_DIR}/third_party/sse2neon) endif() set(headers ${HEADERS_} ) set(SOURCES ${SOURCES_} ) # set compiler options include(Linux.cmake) ################################################################################### # create dll library ################################################################################### add_library( ${GMM_LIB_DLL_NAME} SHARED igdgmm.rc ${UMD_SOURCES} ${UMD_HEADERS}) GmmLibSetTargetConfig(${GMM_LIB_DLL_NAME}) if(MSVC) set_target_properties(${GMM_LIB_DLL_NAME} PROPERTIES OUTPUT_NAME "igdgmm${GMMLIB_ARCH}") bs_set_wdk(${GMM_LIB_DLL_NAME}) set_target_properties(${GMM_LIB_DLL_NAME} PROPERTIES VS_GLOBAL_DriverTargetPlatform Universal) set_target_properties(${GMM_LIB_DLL_NAME} PROPERTIES VS_PLATFORM_TOOLSET WindowsApplicationForDrivers10.0) windows_umd_props_universal(${GMM_LIB_DLL_NAME}) target_link_libraries( ${GMM_LIB_DLL_NAME} onecoreuap.lib ) else() set_target_properties(${GMM_LIB_DLL_NAME} PROPERTIES OUTPUT_NAME "igdgmm") set_target_properties(${GMM_LIB_DLL_NAME} PROPERTIES VERSION ${GMMLIB_API_MAJOR_VERSION}.${GMMLIB_API_MINOR_VERSION}.${GMMLIB_API_PATCH_VERSION}) set_target_properties(${GMM_LIB_DLL_NAME} PROPERTIES SOVERSION ${GMMLIB_API_MAJOR_VERSION}) set(THREADS_PREFER_PTHREAD_FLAG ON) find_package(Threads REQUIRED) target_link_libraries(${GMM_LIB_DLL_NAME} Threads::Threads) endif() ################################################################################### # End of DLL create library ################################################################################### bs_set_defines() bs_set_force_exceptions() bs_set_post_target() ################################################################################### # Set common macros for DLL ################################################################################### bs_set_extra_target_properties(${GMM_LIB_DLL_NAME} _ATL_NO_WIN_SUPPORT SMALL_POOL_ALLOC __GMM __GFX_MACRO_C__ UNUSED_ISTDLIB_MT __UMD GMM_UNIFY_DAF_API ) if(CMAKE_BUILD_TYPE STREQUAL "ReleaseInternal") bs_set_extra_target_properties(${GMM_LIB_DLL_NAME} _RELEASE_INTERNAL) endif() target_include_directories(${GMM_LIB_DLL_NAME} INTERFACE ${BS_DIR_GMMLIB}/inc ${BS_DIR_INC} ${BS_DIR_INC}/common) ################################################################################### # End of Set macros DLL ################################################################################### bs_set_extra_target_properties(${GMM_LIB_DLL_NAME} ISTDLIB_UMD UNUSED_ISTDLIB_MT GMM_UNIFIED_LIB GMM_LIB_DLL GMM_LIB_DLL_EXPORTS ) if("${GMMLIB_ARCH}" MATCHES "64") bs_set_extra_target_properties(${GMM_LIB_DLL_NAME} _X64) endif() if(NOT DEFINED RUN_TEST_SUITE OR RUN_TEST_SUITE) add_subdirectory(ULT) endif() set (GMM_UMD_DLL "igdgmm") include(os_release_info.cmake) get_os_release_info(os_name os_version) if("${os_name}" STREQUAL "clear-linux-os") # clear-linux-os distribution avoids /etc for distribution defaults. # Set this variable explicitly before including GNUInstallDirs. set(CMAKE_INSTALL_SYSCONFDIR "usr/share/defaults/etc") endif() if(UNIX) include(GNUInstallDirs) configure_file(${BS_DIR_GMMLIB}/igdgmm.h.in ${CMAKE_BINARY_DIR}/igdgmm.h) configure_file(${BS_DIR_GMMLIB}/igdgmm.pc.in ${CMAKE_BINARY_DIR}/igdgmm.pc @ONLY) file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/tmp/postinst "/sbin/ldconfig\n") file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/tmp/postrm "/sbin/ldconfig\n") file(COPY ${CMAKE_CURRENT_BINARY_DIR}/tmp/postinst DESTINATION ${CMAKE_CURRENT_BINARY_DIR} FILE_PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE) file(COPY ${CMAKE_CURRENT_BINARY_DIR}/tmp/postrm DESTINATION ${CMAKE_CURRENT_BINARY_DIR} FILE_PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE) install(TARGETS ${GMM_LIB_DLL_NAME} LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT gmmlib NAMELINK_SKIP) install(TARGETS ${GMM_LIB_DLL_NAME} LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT gmmlib-devel NAMELINK_ONLY) install(DIRECTORY ${BS_DIR_GMMLIB} DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/igdgmm COMPONENT gmmlib-devel FILES_MATCHING PATTERN "*.h" PATTERN "*.hpp" PATTERN "Internal" EXCLUDE PATTERN "ULT" EXCLUDE PATTERN "spdlog" EXCLUDE) install (DIRECTORY ${BS_DIR_INC} DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/igdgmm COMPONENT gmmlib-devel FILES_MATCHING PATTERN "*.h" PATTERN "*.hpp") install (DIRECTORY ${BS_DIR_UTIL} DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/igdgmm COMPONENT gmmlib-devel FILES_MATCHING PATTERN "*.h" PATTERN "*.hpp") install (FILES ${BS_DIR_GMMLIB}/Utility/CpuSwizzleBlt/CpuSwizzleBlt.c DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/igdgmm/GmmLib/Utility/CpuSwizzleBlt/ COMPONENT gmmlib-devel) install(FILES ${CMAKE_BINARY_DIR}/igdgmm.pc DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig COMPONENT gmmlib-devel) install(FILES ${CMAKE_BINARY_DIR}/igdgmm.h DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/igdgmm COMPONENT gmmlib-devel) if(GMMLIB_CPACK_GENERATOR) set(CPACK_GENERATOR "${GMMLIB_CPACK_GENERATOR}") else() # If generators list was not define build native package for current distro if(EXISTS "/etc/debian_version") set(CPACK_GENERATOR "DEB") elseif(EXISTS "/etc/redhat-release") set(CPACK_GENERATOR "RPM") else() set(CPACK_GENERATOR "TXZ") endif() endif() set(CPACK_PACKAGE_NAME "intel") set(CPACK_PACKAGE_VENDOR "Intel Corporation") set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "Intel(R) Graphics Memory Management Library Package") set(CPACK_PACKAGE_ARCHITECTURE "x86_64") set(CPACK_PACKAGE_VERSION_MAJOR ${MAJOR_VERSION}) set(CPACK_PACKAGE_VERSION_MINOR ${MINOR_VERSION}) set(CPACK_PACKAGE_VERSION_PATCH ${PATCH_VERSION}) set(CPACK_PACKAGE_VERSION "${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_MINOR}.${CPACK_PACKAGE_VERSION_PATCH}") set(CPACK_PACKAGE_INSTALL_DIRECTORY ${GMMLIB_INSTALL_TIME_ROOT_DIR}) set(CPACK_SET_DESTDIR TRUE) set(CPACK_PACKAGE_RELOCATABLE FALSE) set(CPACK_DEBIAN_PACKAGE_ARCHITECTURE "amd64") set(CPACK_DEBIAN_PACKAGE_MAINTAINER "Intel") set(CPACK_DEBIAN_COMPRESSION_TYPE "xz") set(CPACK_DEBIAN_PACKAGE_CONTROL_EXTRA "${CMAKE_CURRENT_BINARY_DIR}/postinst;${CMAKE_CURRENT_BINARY_DIR}/postrm") set(CPACK_RPM_PACKAGE_ARCHITECTURE "x86_64") set(CPACK_RPM_PACKAGE_RELEASE 1) set(CPACK_RPM_COMPRESSION_TYPE "xz") set(CPACK_RPM_POST_INSTALL_SCRIPT_FILE "${CMAKE_CURRENT_BINARY_DIR}/postinst") set(CPACK_RPM_POST_UNINSTALL_SCRIPT_FILE "${CMAKE_CURRENT_BINARY_DIR}/postrm") if(CMAKE_VERSION VERSION_GREATER 3.6 OR CMAKE_VERSION VERSION_EQUAL 3.6) set(CPACK_DEBIAN_GMMLIB_FILE_NAME "intel-gmmlib_${CPACK_PACKAGE_VERSION}_${CPACK_DEBIAN_PACKAGE_ARCHITECTURE}.deb") set(CPACK_DEBIAN_GMMLIB-DEVEL_FILE_NAME "intel-gmmlib-devel_${CPACK_PACKAGE_VERSION}_${CPACK_DEBIAN_PACKAGE_ARCHITECTURE}.deb") set(CPACK_RPM_GMMLIB_FILE_NAME "intel-gmmlib-${CPACK_PACKAGE_VERSION}-${CPACK_RPM_PACKAGE_RELEASE}%{?dist}.${CPACK_RPM_PACKAGE_ARCHITECTURE}.rpm") set(CPACK_RPM_GMMLIB-DEVEL_FILE_NAME "intel-gmmlib-devel-${CPACK_PACKAGE_VERSION}-${CPACK_RPM_PACKAGE_RELEASE}%{?dist}.${CPACK_RPM_PACKAGE_ARCHITECTURE}.rpm") set(CPACK_ARCHIVE_GMMLIB_FILE_NAME "intel-gmmlib-${CPACK_PACKAGE_VERSION}-${CPACK_PACKAGE_ARCHITECTURE}") set(CPACK_ARCHIVE_GMMLIB-DEVEL_FILE_NAME "intel-gmmlib-devel-${CPACK_PACKAGE_VERSION}-${CPACK_PACKAGE_ARCHITECTURE}") else() if(CPACK_GENERATOR STREQUAL "DEB") set(CPACK_PACKAGE_FILE_NAME "intel-gmmlib_${CPACK_PACKAGE_VERSION}_${CPACK_DEBIAN_PACKAGE_ARCHITECTURE}") elseif(CPACK_GENERATOR STREQUAL "RPM") set(CPACK_PACKAGE_FILE_NAME "intel-gmmlib-${CPACK_PACKAGE_VERSION}-${CPACK_RPM_PACKAGE_RELEASE}%{?dist}.${CPACK_RPM_PACKAGE_ARCHITECTURE}.rpm") else() set(CPACK_PACKAGE_FILE_NAME "intel-gmmlib-${CPACK_PACKAGE_VERSION}-${CPACK_PACKAGE_ARCHITECTURE}") endif() endif() set(CPACK_DEBIAN_GMMLIB-DEVEL_PACKAGE_DEPENDS "intel-gmmlib(=${CPACK_PACKAGE_VERSION})") set(CPACK_RPM_GMMLIB-DEVEL_PACKAGE_REQUIRES "intel-gmmlib = ${CPACK_PACKAGE_VERSION}") set(CPACK_COMPONENT_INSTALL ON) set(CPACK_DEB_COMPONENT_INSTALL ON) set(CPACK_RPM_COMPONENT_INSTALL ON) set(CPACK_ARCHIVE_COMPONENT_INSTALL ON) set(CPACK_COMPONENTS_ALL gmmlib gmmlib-devel) include (CPack) endif() gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/CachePolicy/000077500000000000000000000000001466655022700222365ustar00rootroot00000000000000gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/CachePolicy/GmmCachePolicy.cpp000066400000000000000000000250041466655022700255670ustar00rootroot00000000000000/*============================================================================== Copyright(c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ============================================================================*/ #include "Internal/Common/GmmLibInc.h" #include "External/Common/GmmCachePolicy.h" ///////////////////////////////////////////////////////////////////////////////////// /// C Wrapper function for GmmLib::GmmCachePolicyGetPteType /// @see GmmLib::GmmCachePolicyCommon::CachePolicyGetPteType() // /// @param[in] pLibContext: pGmmLibContext /// @param[in] Usage: type of usage /// /// @return GMM_PTE_CACHE_CONTROL_BITS:Populated PTE /// ///////////////////////////////////////////////////////////////////////////////////// GMM_PTE_CACHE_CONTROL_BITS GMM_STDCALL GmmCachePolicyGetPteType(void *pLibContext, GMM_RESOURCE_USAGE_TYPE Usage) { GMM_LIB_CONTEXT *pGmmLibContext = (GMM_LIB_CONTEXT *)pLibContext; return pGmmLibContext->GetCachePolicyObj()->CachePolicyGetPteType(Usage); } ///////////////////////////////////////////////////////////////////////////////////// /// C Wrapper function for GmmLib::GmmCachePolicyGetPATIndex /// @see GmmLib::GmmCachePolicyCommon::CachePolicyGetPATIndex() /// /// @param[in] pLibContext: pGmmLibContext /// @param[in] Usage: type of usage /// @param[Optional] Usage: for Compression Enable /// /// @return uint32_t /// ///////////////////////////////////////////////////////////////////////////////////// uint32_t GMM_STDCALL GmmCachePolicyGetPATIndex(void *pLibContext, GMM_RESOURCE_USAGE_TYPE Usage, bool *pCompressionEnable, bool IsCpuCacheable) { GMM_LIB_CONTEXT *pGmmLibContext = (GMM_LIB_CONTEXT *)pLibContext; return pGmmLibContext->GetCachePolicyObj()->CachePolicyGetPATIndex(NULL, Usage, pCompressionEnable, IsCpuCacheable); } ///////////////////////////////////////////////////////////////////////////////////// /// C Wrapper function for GmmLib::GmmCachePolicyIsUsagePTECached /// @see GmmLib::GmmCachePolicyCommon::CachePolicyIsUsagePTECached() /// /// @param[in] pLibContext: pGmmLibContext /// @param[in] Usage: type of usage /// /// @return 1 if the usage PTE entry is set for cached, 0 otherwise. ///////////////////////////////////////////////////////////////////////////////////// uint8_t GMM_STDCALL GmmCachePolicyIsUsagePTECached(void *pLibContext, GMM_RESOURCE_USAGE_TYPE Usage) { GMM_LIB_CONTEXT *pGmmLibContext = (GMM_LIB_CONTEXT *)pLibContext; return pGmmLibContext->GetCachePolicyObj()->CachePolicyIsUsagePTECached(Usage); } ///////////////////////////////////////////////////////////////////////////////////// /// C Wrapper function to return L1 Cache Control on DG2 for a given resource type /// /// @param[in] pLibContext: pGmmLibContext /// @param[in] Usage: type of usage /// /// @return Value of L1 Cache control. ///////////////////////////////////////////////////////////////////////////////////// uint8_t GMM_STDCALL GmmGetSurfaceStateL1CachePolicy(void *pLibContext, GMM_RESOURCE_USAGE_TYPE Usage) { GMM_LIB_CONTEXT *pGmmLibContext = (GMM_LIB_CONTEXT *)pLibContext; return (uint8_t)pGmmLibContext->GetCachePolicyObj()->GetSurfaceStateL1CachePolicy(Usage); } ///////////////////////////////////////////////////////////////////////////////////// /// C Wrapper function to return L2 Cache Control on MTL for a given resource type /// /// @param[in] pLibContext: pGmmLibContext /// @param[in] Usage: type of usage ///Value of L2 Cache support ///////////////////////////////////////////////////////////////////////////////////// uint8_t GMM_STDCALL GmmGetSurfaceStateL2CachePolicy(void *pLibContext, GMM_RESOURCE_USAGE_TYPE Usage) { GMM_LIB_CONTEXT *pGmmLibContext = (GMM_LIB_CONTEXT *)pLibContext; return pGmmLibContext->GetCachePolicyElement(Usage).L2CC; } ///////////////////////////////////////////////////////////////////////////////////// /// C wrapper for GmmLib::GmmResourceInfoCommon::GetCachePolicyUsage. /// @see GmmLib::GmmResourceInfoCommon::GetCachePolicyUsage() /// /// @param[in] pGmmResource: Pointer to the GmmResourceInfo class /// @return Cache policy usage ///////////////////////////////////////////////////////////////////////////////////// GMM_RESOURCE_USAGE_TYPE GMM_STDCALL GmmCachePolicyGetResourceUsage(GMM_RESOURCE_INFO *pResInfo) { __GMM_ASSERT(pResInfo); return pResInfo->GetCachePolicyUsage(); } ///////////////////////////////////////////////////////////////////////////////////// /// C wrapper for GmmLib::GmmResourceInfoCommon::OverrideCachePolicyUsage. /// @see GmmLib::GmmResourceInfoCommon::OverrideCachePolicyUsage() /// /// @param[in] pGmmResource: Pointer to the GmmResourceInfo class /// @param[in] Cache policy usage ///////////////////////////////////////////////////////////////////////////////////// void GMM_STDCALL GmmCachePolicyOverrideResourceUsage(GMM_RESOURCE_INFO *pResInfo, GMM_RESOURCE_USAGE_TYPE Usage) { pResInfo->OverrideCachePolicyUsage(Usage); } ///////////////////////////////////////////////////////////////////////////////////// /// C Wrapper function for GmmLib::GmmCachePolicyGetMemoryObject /// @see GmmLib::GmmCachePolicyCommon::CachePolicyGetMemoryObject() /// /// param[in] pResInfo: Resource info for resource, can be NULL. /// param[in] Usage: Current usage for resource. /// /// @return MEMORY_OBJECT_CONTROL_STATE: Gen adjusted MOCS structure (cache /// policy) for the given buffer use. ///////////////////////////////////////////////////////////////////////////////////// MEMORY_OBJECT_CONTROL_STATE GMM_STDCALL GmmCachePolicyGetMemoryObject(void *pLibContext, GMM_RESOURCE_INFO *pResInfo, GMM_RESOURCE_USAGE_TYPE Usage) { GMM_LIB_CONTEXT *pGmmLibContext = (GMM_LIB_CONTEXT *)pLibContext; return pGmmLibContext->GetCachePolicyObj()->CachePolicyGetMemoryObject(pResInfo, Usage); } ///////////////////////////////////////////////////////////////////////////////////// /// C Wrapper function for GmmLib::GmmCachePolicyGetOriginalMemoryObject /// @see GmmLib::GmmCachePolicyCommon::CachePolicyGetOriginalMemoryObject() /// /// @param[in] pResInfo: Resource info for resource , can be null /// @param[in] Usage: Current usage for resource /// /// @return MEMORY_OBJECT_CONTROL_STATE: Populated memory object /// ///////////////////////////////////////////////////////////////////////////////////// MEMORY_OBJECT_CONTROL_STATE GMM_STDCALL GmmCachePolicyGetOriginalMemoryObject(void *pLibContext, GMM_RESOURCE_INFO *pResInfo) { GMM_LIB_CONTEXT *pGmmLibContext = (GMM_LIB_CONTEXT *)pLibContext; return pGmmLibContext->GetCachePolicyObj()->CachePolicyGetOriginalMemoryObject(pResInfo); } ///////////////////////////////////////////////////////////////////////////////////// /// C Wrapper function for GmmCachePolicy::GmmGetWantedMemoryType. /// @see GmmLib::GmmCachePolicy::GetWantedMemoryType() /// /// @param[in] pLibContext: pGmmLibContext /// @param[in] CachePolicy:cache policy for a usage /// /// @return wanted memory type ///////////////////////////////////////////////////////////////////////////////////// GMM_GFX_MEMORY_TYPE GmmGetWantedMemoryType(void *pLibContext, GMM_CACHE_POLICY_ELEMENT CachePolicy) { GMM_LIB_CONTEXT *pGmmLibContext = (GMM_LIB_CONTEXT *)pLibContext; return pGmmLibContext->GetCachePolicyObj()->GetWantedMemoryType(CachePolicy); } ///////////////////////////////////////////////////////////////////////////////////// /// Returns count of current MOCS values for MOCS Table programming at GMM boot /// /// @param[in] pLibContext: pGmmLibContext /// @return uint32_t no of mocs register required to program ///////////////////////////////////////////////////////////////////////////////////// uint32_t GMM_STDCALL GmmCachePolicyGetMaxMocsIndex(void *pLibContext) { GMM_LIB_CONTEXT * pGmmLibContext = (GMM_LIB_CONTEXT *)pLibContext; GMM_CACHE_POLICY * pCachePolicy = pGmmLibContext->GetCachePolicyObj(); GmmLib::GmmGen9CachePolicy *ptr = static_cast(pCachePolicy); return ptr->CurrentMaxMocsIndex; } ///////////////////////////////////////////////////////////////////////////////////// /// Returns count of current L1 HDC MOCS values for MOCS Table programming at GMM boot /// /// @param[in] pLibContext: pGmmLibContext /// @return uint32_t max L1 hdc mocs index needed to program ///////////////////////////////////////////////////////////////////////////////////// uint32_t GMM_STDCALL GmmCachePolicyGetMaxL1HdcMocsIndex(void *pLibContext) { GMM_LIB_CONTEXT * pGmmLibContext = (GMM_LIB_CONTEXT *)pLibContext; GMM_CACHE_POLICY * pCachePolicy = pGmmLibContext->GetCachePolicyObj(); GmmLib::GmmGen9CachePolicy *ptr = static_cast(pCachePolicy); return ptr->CurrentMaxL1HdcMocsIndex; } ///////////////////////////////////////////////////////////////////////////////////// /// Returns count of current Special MOCS values for MOCS Table programming at GMM boot /// /// @param[in] pLibContext: pGmmLibContext /// @return uint32_t max special mocs index needed to program ///////////////////////////////////////////////////////////////////////////////////// uint32_t GMM_STDCALL GmmCachePolicyGetMaxSpecialMocsIndex(void *pLibContext) { GMM_LIB_CONTEXT * pGmmLibContext = (GMM_LIB_CONTEXT *)pLibContext; GMM_CACHE_POLICY *pCachePolicy = pGmmLibContext->GetCachePolicyObj(); return pCachePolicy->GetMaxSpecialMocsIndex(); } gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/CachePolicy/GmmCachePolicyCommon.cpp000066400000000000000000000165271466655022700267520ustar00rootroot00000000000000/*============================================================================== Copyright(c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ============================================================================*/ #include "Internal/Common/GmmLibInc.h" #include "External/Common/GmmCachePolicy.h" ///////////////////////////////////////////////////////////////////////////////////// /// Constructor for the GmmCachePolicyCommon Class, initializes the CachePolicy /// @param[in] pCachePolicy ///////////////////////////////////////////////////////////////////////////////////// GmmLib::GmmCachePolicyCommon::GmmCachePolicyCommon(GMM_CACHE_POLICY_ELEMENT *pCachePolicy, Context *pGmmLibContext) { this->pCachePolicy = pCachePolicy; this->pGmmLibContext = pGmmLibContext; NumPATRegisters = GMM_NUM_PAT_ENTRIES_LEGACY; NumMOCSRegisters = GMM_MAX_NUMBER_MOCS_INDEXES; } ///////////////////////////////////////////////////////////////////////////////////// /// Returns the wanted memory type for this usage. /// /// @param[in] CachePolicy: cache policy for a usage /// /// @return wanted memory type ///////////////////////////////////////////////////////////////////////////////////// GMM_GFX_MEMORY_TYPE GmmLib::GmmCachePolicyCommon::GetWantedMemoryType(GMM_CACHE_POLICY_ELEMENT CachePolicy) { GMM_GFX_MEMORY_TYPE WantedMemoryType = GMM_GFX_UC_WITH_FENCE; if(CachePolicy.WT) { WantedMemoryType = GMM_GFX_WT; } else if(!(CachePolicy.LLC || CachePolicy.ELLC)) { WantedMemoryType = GMM_GFX_UC_WITH_FENCE; } else { WantedMemoryType = GMM_GFX_WB; } return WantedMemoryType; } ///////////////////////////////////////////////////////////////////////////////////// /// Generates memory object based on resource usage /// /// @param[in] pResInfo: Resource info for resource , can be null /// @param[in] Usage: Current usage for resource /// /// @return MEMORY_OBJECT_CONTROL_STATE: Populated memory object /// ///////////////////////////////////////////////////////////////////////////////////// MEMORY_OBJECT_CONTROL_STATE GMM_STDCALL GmmLib::GmmCachePolicyCommon::CachePolicyGetOriginalMemoryObject(GMM_RESOURCE_INFO *pResInfo) { MEMORY_OBJECT_CONTROL_STATE MOCS = pGmmLibContext->GetCachePolicyElement(GMM_RESOURCE_USAGE_UNKNOWN).MemoryObjectOverride; if(pResInfo) { MOCS = pResInfo->GetMOCS(); } return MOCS; } ///////////////////////////////////////////////////////////////////////////////////// /// A simple getter function returning the MOCS (cache policy) for a given /// use Usage of the named resource pResInfo. /// Typically used to populate a SURFACE_STATE for a GPU task. /// /// @param[in] pResInfo: Resource info for resource, can be NULL. /// @param[in] Usage: Current usage for resource. /// /// @return MEMORY_OBJECT_CONTROL_STATE: Gen adjusted MOCS structure (cache /// policy) for the given buffer use. ///////////////////////////////////////////////////////////////////////////////////// MEMORY_OBJECT_CONTROL_STATE GMM_STDCALL GmmLib::GmmCachePolicyCommon::CachePolicyGetMemoryObject(GMM_RESOURCE_INFO *pResInfo, GMM_RESOURCE_USAGE_TYPE Usage) { const GMM_CACHE_POLICY_ELEMENT *CachePolicy = NULL; __GMM_ASSERT(pGmmLibContext->GetCachePolicyElement(Usage).Initialized); CachePolicy = pGmmLibContext->GetCachePolicyUsage(); // Prevent wrong Usage for XAdapter resources. UMD does not call GetMemoryObject on shader resources but, // when they add it someone could call it without knowing the restriction. if(pResInfo && pResInfo->GetResFlags().Info.XAdapter && (Usage != GMM_RESOURCE_USAGE_XADAPTER_SHARED_RESOURCE)) { __GMM_ASSERT(false); } if(!pResInfo || (CachePolicy[Usage].Override & CachePolicy[pResInfo->GetCachePolicyUsage()].IDCode) || (CachePolicy[Usage].Override == ALWAYS_OVERRIDE)) { return CachePolicy[Usage].MemoryObjectOverride; } else { return CachePolicy[Usage].MemoryObjectNoOverride; } } ///////////////////////////////////////////////////////////////////////////////////// /// A simple getter function returning the PAT (cache policy) for a given /// use Usage of the named resource pResInfo. /// Typically used to populate PPGTT/GGTT. /// /// @param[in] pResInfo: Resource info for resource, can be NULL. /// @param[in] Usage: Current usage for resource. /// /// @return PATIndex ///////////////////////////////////////////////////////////////////////////////////// uint32_t GMM_STDCALL GmmLib::GmmCachePolicyCommon::CachePolicyGetPATIndex(GMM_RESOURCE_INFO *pResInfo, GMM_RESOURCE_USAGE_TYPE Usage, bool *pCompressionEnable, bool IsCpuCacheable) { GMM_UNREFERENCED_PARAMETER(pResInfo); GMM_UNREFERENCED_PARAMETER(Usage); GMM_UNREFERENCED_PARAMETER(pCompressionEnable); GMM_UNREFERENCED_PARAMETER(IsCpuCacheable); return GMM_PAT_ERROR; } ///////////////////////////////////////////////////////////////////////////////////// /// Generates PTE based on resource usage /// /// @param[in] Usage: type of usage /// /// @return GMM_PTE_CACHE_CONTROL_BITS: Populated PTE ///////////////////////////////////////////////////////////////////////////////////// GMM_PTE_CACHE_CONTROL_BITS GMM_STDCALL GmmLib::GmmCachePolicyCommon::CachePolicyGetPteType(GMM_RESOURCE_USAGE_TYPE Usage) { __GMM_ASSERT(pGmmLibContext->GetCachePolicyElement(Usage).Initialized); return pGmmLibContext->GetCachePolicyElement(Usage).PTE; } ///////////////////////////////////////////////////////////////////////////////////// /// Returns number of PAT entries possible on that platform /// /// @return uint32_t ///////////////////////////////////////////////////////////////////////////////////// uint32_t GMM_STDCALL GmmLib::GmmCachePolicyCommon::CachePolicyGetNumPATRegisters() { return NumPATRegisters; } ///////////////////////////////////////////////////////////////////////////////////// /// Returns L1 cache attribute based on resource usage /// /// @return uint32_t ///////////////////////////////////////////////////////////////////////////////////// uint32_t GMM_STDCALL GmmLib::GmmCachePolicyCommon::GetSurfaceStateL1CachePolicy(GMM_RESOURCE_USAGE_TYPE Usage) { __GMM_ASSERT(pCachePolicy[Usage].Initialized); return pCachePolicy[Usage].L1CC; } gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/CachePolicy/GmmCachePolicyConditionals.h000066400000000000000000000040571466655022700276100ustar00rootroot00000000000000/*============================================================================== Copyright(c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ============================================================================*/ #define ISPRODUCT(X) (GFX_GET_CURRENT_PRODUCT(pGmmLibContext->GetPlatformInfo().Platform) == IGFX_##X) #define FROMPRODUCT(X) (GFX_GET_CURRENT_PRODUCT(pGmmLibContext->GetPlatformInfo().Platform) >= IGFX_##X) #define SKU(FtrXxx) (pGmmLibContext->GetSkuTable().FtrXxx != 0) #define WA(WaXxx) (pGmmLibContext->GetWaTable().WaXxx != 0) // Underscored to prevent name collision with the GMM_CACHE_POLICY_ELEMENT fields named L3 and LLC #define _L3 (pGmmLibContext->GetGtSysInfo()->L3CacheSizeInKb) #define _LLC (pGmmLibContext->GetGtSysInfo()->LLCCacheSizeInKb) #define _ELLC (pGmmLibContext->GetGtSysInfo()->EdramSizeInKb) #define CAM$ (SKU(FtrCameraCaptureCaching)) // Units are already in KB in the system information, so these helper macros need to account for that #define KB(N) (N) #define MB(N) (1024 * KB(N)) gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/CachePolicy/GmmCachePolicyResourceUsageDefinitions.h000066400000000000000000000506321466655022700321320ustar00rootroot00000000000000/*============================================================================== Copyright(c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ============================================================================*/ // Generic Usages // KMD Usages DEFINE_RESOURCE_USAGE( GMM_RESOURCE_USAGE_BATCH_BUFFER ) DEFINE_RESOURCE_USAGE( GMM_RESOURCE_USAGE_COMP_FRAME_BUFFER ) DEFINE_RESOURCE_USAGE( GMM_RESOURCE_USAGE_CONTEXT_SWITCH_BUFFER ) DEFINE_RESOURCE_USAGE( GMM_RESOURCE_USAGE_CURSOR ) DEFINE_RESOURCE_USAGE( GMM_RESOURCE_USAGE_DISPLAY_STATIC_IMG_FOR_SMOOTH_ROTATION_BUFFER ) DEFINE_RESOURCE_USAGE( GMM_RESOURCE_USAGE_DUMMY_PAGE ) DEFINE_RESOURCE_USAGE( GMM_RESOURCE_USAGE_GDI_SURFACE ) DEFINE_RESOURCE_USAGE( GMM_RESOURCE_USAGE_GENERIC_KMD_RESOURCE ) DEFINE_RESOURCE_USAGE( GMM_RESOURCE_USAGE_GFX_RING ) DEFINE_RESOURCE_USAGE( GMM_RESOURCE_USAGE_GTT_TRANSFER_REGION ) DEFINE_RESOURCE_USAGE( GMM_RESOURCE_USAGE_HW_CONTEXT ) DEFINE_RESOURCE_USAGE( GMM_RESOURCE_USAGE_KMD_STAGING_SURFACE ) DEFINE_RESOURCE_USAGE( GMM_RESOURCE_USAGE_MBM_BUFFER ) DEFINE_RESOURCE_USAGE( GMM_RESOURCE_USAGE_NNDI_BUFFER ) DEFINE_RESOURCE_USAGE( GMM_RESOURCE_USAGE_OVERLAY_MBM ) DEFINE_RESOURCE_USAGE( GMM_RESOURCE_USAGE_PRIMARY_SURFACE ) DEFINE_RESOURCE_USAGE( GMM_RESOURCE_USAGE_SCREEN_PROTECTION_INTERMEDIATE_SURFACE ) DEFINE_RESOURCE_USAGE( GMM_RESOURCE_USAGE_SHADOW_SURFACE ) DEFINE_RESOURCE_USAGE( GMM_RESOURCE_USAGE_SM_SCRATCH_STATE ) DEFINE_RESOURCE_USAGE( GMM_RESOURCE_USAGE_STATE_MANAGER_KERNEL_STATE ) DEFINE_RESOURCE_USAGE( GMM_RESOURCE_USAGE_STATUS_PAGE ) DEFINE_RESOURCE_USAGE( GMM_RESOURCE_USAGE_TIMER_PERF_QUEUE ) DEFINE_RESOURCE_USAGE( GMM_RESOURCE_USAGE_UNMAP_PAGING_RESERVED_GTT_DMA_BUFFER ) DEFINE_RESOURCE_USAGE( GMM_RESOURCE_USAGE_VSC_BATCH_BUFFER ) DEFINE_RESOURCE_USAGE( GMM_RESOURCE_USAGE_WA_BATCH_BUFFER ) DEFINE_RESOURCE_USAGE( GMM_RESOURCE_USAGE_KMD_OCA_BUFFER) // // 3D Usages // DEFINE_RESOURCE_USAGE( GMM_RESOURCE_USAGE_UMD_BATCH_BUFFER ) DEFINE_RESOURCE_USAGE( GMM_RESOURCE_USAGE_BINDING_TABLE_POOL ) DEFINE_RESOURCE_USAGE( GMM_RESOURCE_USAGE_CCS ) DEFINE_RESOURCE_USAGE( GMM_RESOURCE_USAGE_CONSTANT_BUFFER_POOL ) DEFINE_RESOURCE_USAGE( GMM_RESOURCE_USAGE_DEPTH_BUFFER ) DEFINE_RESOURCE_USAGE( GMM_RESOURCE_USAGE_DISPLAYABLE_RENDER_TARGET ) DEFINE_RESOURCE_USAGE( GMM_RESOURCE_USAGE_GEN9_UNENCRYPTED_DISPLAYABLE ) DEFINE_RESOURCE_USAGE( GMM_RESOURCE_USAGE_GATHER_POOL ) DEFINE_RESOURCE_USAGE( GMM_RESOURCE_USAGE_HEAP_SURFACE_STATE ) DEFINE_RESOURCE_USAGE( GMM_RESOURCE_USAGE_HEAP_DYNAMIC_STATE ) DEFINE_RESOURCE_USAGE( GMM_RESOURCE_USAGE_HEAP_GENERAL_STATE ) DEFINE_RESOURCE_USAGE( GMM_RESOURCE_USAGE_HEAP_GENERAL_STATE_UC ) DEFINE_RESOURCE_USAGE( GMM_RESOURCE_USAGE_HEAP_STATELESS_DATA_PORT ) DEFINE_RESOURCE_USAGE( GMM_RESOURCE_USAGE_HEAP_STATELESS_DATA_PORT_L1_CACHED ) DEFINE_RESOURCE_USAGE( GMM_RESOURCE_USAGE_HEAP_INDIRECT_OBJECT ) DEFINE_RESOURCE_USAGE( GMM_RESOURCE_USAGE_HEAP_INSTRUCTION ) DEFINE_RESOURCE_USAGE( GMM_RESOURCE_USAGE_HIZ ) DEFINE_RESOURCE_USAGE( GMM_RESOURCE_USAGE_INDEX_BUFFER ) DEFINE_RESOURCE_USAGE( GMM_RESOURCE_USAGE_INDEX_BUFFER_L3_COHERENT_UC) DEFINE_RESOURCE_USAGE( GMM_RESOURCE_USAGE_INDEX_BUFFER_L3_CACHED) DEFINE_RESOURCE_USAGE( GMM_RESOURCE_USAGE_MCS ) DEFINE_RESOURCE_USAGE( GMM_RESOURCE_USAGE_PUSH_CONSTANT_BUFFER ) DEFINE_RESOURCE_USAGE( GMM_RESOURCE_USAGE_PULL_CONSTANT_BUFFER ) DEFINE_RESOURCE_USAGE( GMM_RESOURCE_USAGE_QUERY ) DEFINE_RESOURCE_USAGE( GMM_RESOURCE_USAGE_RENDER_TARGET ) DEFINE_RESOURCE_USAGE( GMM_RESOURCE_USAGE_SHADER_RESOURCE ) DEFINE_RESOURCE_USAGE( GMM_RESOURCE_USAGE_STAGING ) DEFINE_RESOURCE_USAGE( GMM_RESOURCE_USAGE_STENCIL_BUFFER ) DEFINE_RESOURCE_USAGE( GMM_RESOURCE_USAGE_STREAM_OUTPUT_BUFFER ) DEFINE_RESOURCE_USAGE( GMM_RESOURCE_USAGE_TILE_POOL ) DEFINE_RESOURCE_USAGE( GMM_RESOURCE_USAGE_MOCS_62 ) DEFINE_RESOURCE_USAGE( GMM_RESOURCE_USAGE_L3_EVICTION ) DEFINE_RESOURCE_USAGE( GMM_RESOURCE_USAGE_L3_EVICTION_SPECIAL ) DEFINE_RESOURCE_USAGE( GMM_RESOURCE_USAGE_CCS_MEDIA_WRITABLE ) //TODO: To substitute with Interface to set SCF once its available for UMDs DEFINE_RESOURCE_USAGE( GMM_RESOURCE_USAGE_SHADER_RESOURCE_LLC_BYPASS ) DEFINE_RESOURCE_USAGE( GMM_RESOURCE_USAGE_PROCEDURAL_TEXTURE ) DEFINE_RESOURCE_USAGE( GMM_RESOURCE_USAGE_UNCACHED ) // Tiled Resource DEFINE_RESOURCE_USAGE( GMM_RESOURCE_USAGE_TILED_CCS ) DEFINE_RESOURCE_USAGE( GMM_RESOURCE_USAGE_TILED_DEPTH_BUFFER ) DEFINE_RESOURCE_USAGE( GMM_RESOURCE_USAGE_TILED_HIZ ) DEFINE_RESOURCE_USAGE( GMM_RESOURCE_USAGE_TILED_MCS ) DEFINE_RESOURCE_USAGE( GMM_RESOURCE_USAGE_TILED_RENDER_TARGET ) DEFINE_RESOURCE_USAGE( GMM_RESOURCE_USAGE_TILED_RENDER_TARGET_AND_SHADER_RESOURCE ) DEFINE_RESOURCE_USAGE( GMM_RESOURCE_USAGE_TILED_SHADER_RESOURCE ) DEFINE_RESOURCE_USAGE( GMM_RESOURCE_USAGE_TILED_UAV ) DEFINE_RESOURCE_USAGE( GMM_RESOURCE_USAGE_VERTEX_BUFFER ) DEFINE_RESOURCE_USAGE( GMM_RESOURCE_USAGE_VERTEX_BUFFER_L3_COHERENT_UC) DEFINE_RESOURCE_USAGE( GMM_RESOURCE_USAGE_VERTEX_BUFFER_L3_CACHED) DEFINE_RESOURCE_USAGE( GMM_RESOURCE_USAGE_OGL_WSTN_VERTEX_BUFFER ) DEFINE_RESOURCE_USAGE(GMM_RESOURCE_USAGE_POSH_VERTEX_BUFFER) DEFINE_RESOURCE_USAGE( GMM_RESOURCE_USAGE_UAV ) DEFINE_RESOURCE_USAGE( GMM_RESOURCE_USAGE_RENDER_TARGET_AND_SHADER_RESOURCE ) DEFINE_RESOURCE_USAGE( GMM_RESOURCE_USAGE_RENDER_TARGET_AND_SHADER_RESOURCE_PARTIALENCSURFACES ) DEFINE_RESOURCE_USAGE( GMM_RESOURCE_USAGE_WDDM_HISTORY_BUFFER ) DEFINE_RESOURCE_USAGE( GMM_RESOURCE_USAGE_CONTEXT_SAVE_RESTORE ) DEFINE_RESOURCE_USAGE( GMM_RESOURCE_USAGE_PTBR_PAGE_POOL ) DEFINE_RESOURCE_USAGE( GMM_RESOURCE_USAGE_PTBR_BATCH_BUFFER ) // // CM USAGES // DEFINE_RESOURCE_USAGE( CM_RESOURCE_USAGE_SurfaceState ) DEFINE_RESOURCE_USAGE( CM_RESOURCE_USAGE_StateHeap) DEFINE_RESOURCE_USAGE( CM_RESOURCE_USAGE_NO_L3_SurfaceState ) DEFINE_RESOURCE_USAGE( CM_RESOURCE_USAGE_NO_LLC_ELLC_SurfaceState ) DEFINE_RESOURCE_USAGE( CM_RESOURCE_USAGE_NO_LLC_SurfaceState ) DEFINE_RESOURCE_USAGE( CM_RESOURCE_USAGE_NO_ELLC_SurfaceState ) DEFINE_RESOURCE_USAGE( CM_RESOURCE_USAGE_NO_LLC_L3_SurfaceState ) DEFINE_RESOURCE_USAGE( CM_RESOURCE_USAGE_NO_ELLC_L3_SurfaceState ) DEFINE_RESOURCE_USAGE( CM_RESOURCE_USAGE_NO_CACHE_SurfaceState ) DEFINE_RESOURCE_USAGE( CM_RESOURCE_USAGE_L1_Enabled_SurfaceState ) // // MP USAGES // DEFINE_RESOURCE_USAGE( MP_RESOURCE_USAGE_BEGIN ) DEFINE_RESOURCE_USAGE( MP_RESOURCE_USAGE_DEFAULT ) DEFINE_RESOURCE_USAGE( MP_RESOURCE_USAGE_DEFAULT_FF ) DEFINE_RESOURCE_USAGE( MP_RESOURCE_USAGE_DEFAULT_RCS ) DEFINE_RESOURCE_USAGE( MP_RESOURCE_USAGE_SurfaceState ) DEFINE_RESOURCE_USAGE( MP_RESOURCE_USAGE_SurfaceState_FF ) DEFINE_RESOURCE_USAGE( MP_RESOURCE_USAGE_SurfaceState_RCS ) DEFINE_RESOURCE_USAGE( MP_RESOURCE_USAGE_AGE3_SurfaceState ) DEFINE_RESOURCE_USAGE( MP_RESOURCE_USAGE_EDRAM_SurfaceState ) DEFINE_RESOURCE_USAGE( MP_RESOURCE_USAGE_EDRAM_AGE3_SurfaceState ) DEFINE_RESOURCE_USAGE( MP_RESOURCE_USAGE_No_L3_SurfaceState ) DEFINE_RESOURCE_USAGE( MP_RESOURCE_USAGE_No_LLC_L3_SurfaceState ) DEFINE_RESOURCE_USAGE( MP_RESOURCE_USAGE_No_LLC_L3_AGE_SurfaceState ) DEFINE_RESOURCE_USAGE( MP_RESOURCE_USAGE_No_LLC_eLLC_L3_AGE_SurfaceState ) DEFINE_RESOURCE_USAGE( MP_RESOURCE_USAGE_PartialEnc_No_LLC_L3_AGE_SurfaceState ) DEFINE_RESOURCE_USAGE( MP_RESOURCE_USAGE_END ) // MHW - SFC USAGES DEFINE_RESOURCE_USAGE( MHW_RESOURCE_USAGE_Sfc_CurrentOutputSurface ) // SFC Output Surface DEFINE_RESOURCE_USAGE( MHW_RESOURCE_USAGE_Sfc_CurrentOutputSurface_PartialEncSurface ) // SFC Output Surface for partial encrypted surfaces DEFINE_RESOURCE_USAGE( MHW_RESOURCE_USAGE_Sfc_AvsLineBufferSurface ) // SFC AVS Line buffer Surface DEFINE_RESOURCE_USAGE( MHW_RESOURCE_USAGE_Sfc_IefLineBufferSurface ) // SFC IEF Line buffer Surface // // CODEC USAGES // DEFINE_RESOURCE_USAGE( GMM_RESOURCE_USAGE_BEGIN_CODEC ) DEFINE_RESOURCE_USAGE( GMM_RESOURCE_USAGE_PRE_DEBLOCKING_CODEC ) DEFINE_RESOURCE_USAGE( GMM_RESOURCE_USAGE_PRE_DEBLOCKING_CODEC_PARTIALENCSURFACE ) DEFINE_RESOURCE_USAGE( GMM_RESOURCE_USAGE_POST_DEBLOCKING_CODEC ) DEFINE_RESOURCE_USAGE( GMM_RESOURCE_USAGE_ORIGINAL_UNCOMPRESSED_PICTURE_ENCODE ) DEFINE_RESOURCE_USAGE( GMM_RESOURCE_USAGE_ORIGINAL_UNCOMPRESSED_PICTURE_DECODE ) DEFINE_RESOURCE_USAGE( GMM_RESOURCE_USAGE_STREAMOUT_DATA_CODEC ) DEFINE_RESOURCE_USAGE( GMM_RESOURCE_USAGE_INTRA_ROWSTORE_SCRATCH_BUFFER_CODEC ) DEFINE_RESOURCE_USAGE( GMM_RESOURCE_USAGE_DEBLOCKINGFILTER_ROWSTORE_SCRATCH_BUFFER_CODEC ) DEFINE_RESOURCE_USAGE( GMM_RESOURCE_USAGE_REFERENCE_PICTURE_CODEC ) DEFINE_RESOURCE_USAGE( GMM_RESOURCE_USAGE_MACROBLOCK_STATUS_BUFFER_CODEC ) DEFINE_RESOURCE_USAGE( GMM_RESOURCE_USAGE_MFX_INDIRECT_BITSTREAM_OBJECT_DECODE ) DEFINE_RESOURCE_USAGE( GMM_RESOURCE_USAGE_MFX_INDIRECT_MV_OBJECT_CODEC ) DEFINE_RESOURCE_USAGE( GMM_RESOURCE_USAGE_MFD_INDIRECT_IT_COEF_OBJECT_DECODE ) DEFINE_RESOURCE_USAGE( GMM_RESOURCE_USAGE_MFC_INDIRECT_PAKBASE_OBJECT_CODEC ) DEFINE_RESOURCE_USAGE( GMM_RESOURCE_USAGE_BSDMPC_ROWSTORE_SCRATCH_BUFFER_CODEC ) DEFINE_RESOURCE_USAGE( GMM_RESOURCE_USAGE_MPR_ROWSTORE_SCRATCH_BUFFER_CODEC ) DEFINE_RESOURCE_USAGE( GMM_RESOURCE_USAGE_BITPLANE_READ_CODEC) DEFINE_RESOURCE_USAGE( GMM_RESOURCE_USAGE_AACSBIT_VECTOR_CODEC) DEFINE_RESOURCE_USAGE( GMM_RESOURCE_USAGE_DIRECTMV_BUFFER_CODEC ) DEFINE_RESOURCE_USAGE( GMM_RESOURCE_USAGE_SURFACE_CURR_ENCODE ) DEFINE_RESOURCE_USAGE( GMM_RESOURCE_USAGE_SURFACE_REF_ENCODE ) DEFINE_RESOURCE_USAGE( GMM_RESOURCE_USAGE_SURFACE_MV_DATA_ENCODE ) DEFINE_RESOURCE_USAGE( GMM_RESOURCE_USAGE_SURFACE_HME_DOWNSAMPLED_ENCODE ) DEFINE_RESOURCE_USAGE( GMM_RESOURCE_USAGE_SURFACE_HME_DOWNSAMPLED_ENCODE_FF) DEFINE_RESOURCE_USAGE( GMM_RESOURCE_USAGE_SURFACE_HME_DOWNSAMPLED_ENCODE_DST ) DEFINE_RESOURCE_USAGE( GMM_RESOURCE_USAGE_SURFACE_ME_DISTORTION_ENCODE ) DEFINE_RESOURCE_USAGE( GMM_RESOURCE_USAGE_SURFACE_BRC_ME_DISTORTION_ENCODE ) DEFINE_RESOURCE_USAGE( GMM_RESOURCE_USAGE_PAK_OBJECT_ENCODE ) DEFINE_RESOURCE_USAGE( GMM_RESOURCE_USAGE_SURFACE_FLATNESS_CHECK_ENCODE ) DEFINE_RESOURCE_USAGE( GMM_RESOURCE_USAGE_SURFACE_MBENC_CURBE_ENCODE ) DEFINE_RESOURCE_USAGE( GMM_RESOURCE_USAGE_SURFACE_MAD_ENCODE ) DEFINE_RESOURCE_USAGE( GMM_RESOURCE_USAGE_VP8_BLOCK_MODE_COST_ENCODE ) DEFINE_RESOURCE_USAGE( GMM_RESOURCE_USAGE_VP8_MB_MODE_COST_ENCODE ) DEFINE_RESOURCE_USAGE( GMM_RESOURCE_USAGE_VP8_MBENC_OUTPUT_ENCODE ) DEFINE_RESOURCE_USAGE( GMM_RESOURCE_USAGE_VP8_HISTOGRAM_ENCODE ) DEFINE_RESOURCE_USAGE( GMM_RESOURCE_USAGE_VP8_L3_LLC_ENCODE ) DEFINE_RESOURCE_USAGE( GMM_RESOURCE_USAGE_MBDISABLE_SKIPMAP_CODEC) DEFINE_RESOURCE_USAGE( GMM_RESOURCE_USAGE_MFX_STANDALONE_DEBLOCKING_CODEC ) DEFINE_RESOURCE_USAGE( GMM_RESOURCE_USAGE_HCP_MD_CODEC ) DEFINE_RESOURCE_USAGE( GMM_RESOURCE_USAGE_HCP_SAO_CODEC ) DEFINE_RESOURCE_USAGE( GMM_RESOURCE_USAGE_HCP_MV_CODEC ) DEFINE_RESOURCE_USAGE( GMM_RESOURCE_USAGE_HCP_STATUS_ERROR_CODEC ) DEFINE_RESOURCE_USAGE( GMM_RESOURCE_USAGE_HCP_LCU_ILDB_STREAMOUT_CODEC ) DEFINE_RESOURCE_USAGE( GMM_RESOURCE_USAGE_VP9_PROBABILITY_BUFFER_CODEC ) DEFINE_RESOURCE_USAGE( GMM_RESOURCE_USAGE_VP9_SEGMENT_ID_BUFFER_CODEC ) DEFINE_RESOURCE_USAGE( GMM_RESOURCE_USAGE_VP9_HVD_ROWSTORE_BUFFER_CODEC ) DEFINE_RESOURCE_USAGE( GMM_RESOURCE_USAGE_VDENC_ROW_STORE_BUFFER_CODEC ) DEFINE_RESOURCE_USAGE( GMM_RESOURCE_USAGE_VDENC_STREAMIN_CODEC ) DEFINE_RESOURCE_USAGE( GMM_RESOURCE_USAGE_SURFACE_MB_QP_CODEC ) DEFINE_RESOURCE_USAGE( GMM_RESOURCE_USAGE_MACROBLOCK_ILDB_STREAM_OUT_BUFFER_CODEC ) DEFINE_RESOURCE_USAGE( GMM_RESOURCE_USAGE_SSE_SRC_PIXEL_ROW_STORE_BUFFER_CODEC ) DEFINE_RESOURCE_USAGE( GMM_RESOURCE_USAGE_SLICE_STATE_STREAM_OUT_BUFFER_CODEC ) DEFINE_RESOURCE_USAGE( GMM_RESOURCE_USAGE_CABAC_SYNTAX_STREAM_OUT_BUFFER_CODEC ) DEFINE_RESOURCE_USAGE( GMM_RESOURCE_USAGE_PRED_COL_STORE_BUFFER_CODEC ) DEFINE_RESOURCE_USAGE( GMM_RESOURCE_USAGE_SURFACE_PAK_IMAGESTATE_ENCODE) DEFINE_RESOURCE_USAGE( GMM_RESOURCE_USAGE_SURFACE_MBENC_BRC_ENCODE) DEFINE_RESOURCE_USAGE( GMM_RESOURCE_USAGE_SURFACE_MB_BRC_CONST_ENCODE) DEFINE_RESOURCE_USAGE( GMM_RESOURCE_USAGE_SURFACE_BRC_MB_QP_ENCODE) DEFINE_RESOURCE_USAGE( GMM_RESOURCE_USAGE_SURFACE_BRC_ROI_ENCODE) DEFINE_RESOURCE_USAGE( GMM_RESOURCE_USAGE_SURFACE_SLICE_MAP_ENCODE) DEFINE_RESOURCE_USAGE( GMM_RESOURCE_USAGE_SURFACE_WP_DOWNSAMPLED_ENCODE) DEFINE_RESOURCE_USAGE( GMM_RESOURCE_USAGE_SURFACE_VDENC_IMAGESTATE_ENCODE) DEFINE_RESOURCE_USAGE( GMM_RESOURCE_USAGE_SURFACE_UNCACHED ) DEFINE_RESOURCE_USAGE( GMM_RESOURCE_USAGE_SURFACE_ELLC_ONLY ) DEFINE_RESOURCE_USAGE( GMM_RESOURCE_USAGE_SURFACE_ELLC_LLC_ONLY ) DEFINE_RESOURCE_USAGE( GMM_RESOURCE_USAGE_SURFACE_ELLC_LLC_L3 ) DEFINE_RESOURCE_USAGE( GMM_RESOURCE_USAGE_SURFACE_BRC_HISTORY_ENCODE ) DEFINE_RESOURCE_USAGE( GMM_RESOURCE_USAGE_SURFACE_SOFTWARE_SCOREBOARD_ENCODE ) DEFINE_RESOURCE_USAGE( GMM_RESOURCE_USAGE_SURFACE_ME_MV_DATA_ENCODE ) DEFINE_RESOURCE_USAGE( GMM_RESOURCE_USAGE_SURFACE_MV_DISTORTION_ENCODE ) DEFINE_RESOURCE_USAGE( GMM_RESOURCE_USAGE_SURFACE_4XME_DISTORTION_ENCODE ) DEFINE_RESOURCE_USAGE( GMM_RESOURCE_USAGE_SURFACE_INTRA_DISTORTION_ENCODE ) DEFINE_RESOURCE_USAGE( GMM_RESOURCE_USAGE_MB_STATS_ENCODE ) DEFINE_RESOURCE_USAGE( GMM_RESOURCE_USAGE_SURFACE_PAK_STATS_ENCODE ) DEFINE_RESOURCE_USAGE( GMM_RESOURCE_USAGE_SURFACE_PIC_STATE_READ_ENCODE ) DEFINE_RESOURCE_USAGE( GMM_RESOURCE_USAGE_SURFACE_PIC_STATE_WRITE_ENCODE ) DEFINE_RESOURCE_USAGE( GMM_RESOURCE_USAGE_SURFACE_COMBINED_ENC_ENCODE ) DEFINE_RESOURCE_USAGE( GMM_RESOURCE_USAGE_SURFACE_BRC_CONSTANT_DATA_ENCODE ) DEFINE_RESOURCE_USAGE( GMM_RESOURCE_USAGE_SURFACE_INTERMEDIATE_CU_RECORD_SURFACE_ENCODE ) DEFINE_RESOURCE_USAGE( GMM_RESOURCE_USAGE_SURFACE_SCRATCH_ENCODE ) DEFINE_RESOURCE_USAGE( GMM_RESOURCE_USAGE_SURFACE_LCU_LEVEL_DATA_ENCODE ) DEFINE_RESOURCE_USAGE( GMM_RESOURCE_USAGE_SURFACE_ENC_HISTORY_INPUT_ENCODE ) DEFINE_RESOURCE_USAGE( GMM_RESOURCE_USAGE_SURFACE_ENC_HISTORY_OUTPUT_ENCODE ) DEFINE_RESOURCE_USAGE( GMM_RESOURCE_USAGE_SURFACE_DEBUG_ENCODE ) DEFINE_RESOURCE_USAGE( GMM_RESOURCE_USAGE_SURFACE_ENC_CONSTANT_TABLE_ENCODE ) DEFINE_RESOURCE_USAGE( GMM_RESOURCE_USAGE_SURFACE_ENC_CU_RECORD_ENCODE ) DEFINE_RESOURCE_USAGE( GMM_RESOURCE_USAGE_SURFACE_ENC_MV_TEMPORAL_BUFFER_ENCODE ) DEFINE_RESOURCE_USAGE( GMM_RESOURCE_USAGE_SURFACE_ENC_CU_PACKET_FOR_PAK_ENCODE ) DEFINE_RESOURCE_USAGE( GMM_RESOURCE_USAGE_SURFACE_ENC_BCOMBINED1_ENCODE ) DEFINE_RESOURCE_USAGE( GMM_RESOURCE_USAGE_SURFACE_ENC_BCOMBINED2_ENCODE ) DEFINE_RESOURCE_USAGE( GMM_RESOURCE_USAGE_FRAME_STATS_STREAMOUT_DATA_CODEC ) DEFINE_RESOURCE_USAGE( GMM_RESOURCE_USAGE_DEBLOCKINGFILTER_ROWSTORE_TILE_LINE_BUFFER_CODEC ) DEFINE_RESOURCE_USAGE( GMM_RESOURCE_USAGE_DEBLOCKINGFILTER_ROWSTORE_TILE_COLUMN_BUFFER_CODEC ) DEFINE_RESOURCE_USAGE( GMM_RESOURCE_USAGE_HCP_MD_TILE_LINE_CODEC ) DEFINE_RESOURCE_USAGE( GMM_RESOURCE_USAGE_HCP_MD_TILE_COLUMN_CODEC ) DEFINE_RESOURCE_USAGE( GMM_RESOURCE_USAGE_HCP_SAO_TILE_LINE_CODEC ) DEFINE_RESOURCE_USAGE( GMM_RESOURCE_USAGE_HCP_SAO_TILE_COLUMN_CODEC ) DEFINE_RESOURCE_USAGE( GMM_RESOURCE_USAGE_VP9_PROBABILITY_COUNTER_BUFFER_CODEC ) DEFINE_RESOURCE_USAGE( GMM_RESOURCE_USAGE_HUC_VIRTUAL_ADDR_REGION_BUFFER_CODEC ) DEFINE_RESOURCE_USAGE( GMM_RESOURCE_USAGE_SIZE_STREAMOUT_CODEC ) DEFINE_RESOURCE_USAGE( GMM_RESOURCE_USAGE_COMPRESSED_HEADER_BUFFER_CODEC ) DEFINE_RESOURCE_USAGE( GMM_RESOURCE_USAGE_PROBABILITY_DELTA_BUFFER_CODEC ) DEFINE_RESOURCE_USAGE( GMM_RESOURCE_USAGE_TILE_RECORD_BUFFER_CODEC ) DEFINE_RESOURCE_USAGE( GMM_RESOURCE_USAGE_TILE_SIZE_STAS_BUFFER_CODEC ) DEFINE_RESOURCE_USAGE( GMM_RESOURCE_USAGE_END_CODEC ) // OCL Usages DEFINE_RESOURCE_USAGE( GMM_RESOURCE_USAGE_OCL_BUFFER ) DEFINE_RESOURCE_USAGE( GMM_RESOURCE_USAGE_OCL_BUFFER_CONST ) DEFINE_RESOURCE_USAGE( GMM_RESOURCE_USAGE_OCL_BUFFER_CSR_UC ) DEFINE_RESOURCE_USAGE( GMM_RESOURCE_USAGE_OCL_BUFFER_CACHELINE_MISALIGNED ) DEFINE_RESOURCE_USAGE( GMM_RESOURCE_USAGE_OCL_IMAGE ) DEFINE_RESOURCE_USAGE( GMM_RESOURCE_USAGE_OCL_INLINE_CONST ) DEFINE_RESOURCE_USAGE( GMM_RESOURCE_USAGE_OCL_INLINE_CONST_HDC ) DEFINE_RESOURCE_USAGE( GMM_RESOURCE_USAGE_OCL_SCRATCH ) DEFINE_RESOURCE_USAGE( GMM_RESOURCE_USAGE_OCL_PRIVATE_MEM ) DEFINE_RESOURCE_USAGE( GMM_RESOURCE_USAGE_OCL_PRINTF_BUFFER ) DEFINE_RESOURCE_USAGE( GMM_RESOURCE_USAGE_OCL_STATE_HEAP_BUFFER ) DEFINE_RESOURCE_USAGE( GMM_RESOURCE_USAGE_OCL_SYSTEM_MEMORY_BUFFER ) DEFINE_RESOURCE_USAGE( GMM_RESOURCE_USAGE_OCL_SYSTEM_MEMORY_BUFFER_CACHELINE_MISALIGNED ) DEFINE_RESOURCE_USAGE( GMM_RESOURCE_USAGE_OCL_ISH_HEAP_BUFFER ) DEFINE_RESOURCE_USAGE( GMM_RESOURCE_USAGE_OCL_TAG_MEMORY_BUFFER ) DEFINE_RESOURCE_USAGE( GMM_RESOURCE_USAGE_OCL_TEXTURE_BUFFER ) DEFINE_RESOURCE_USAGE( GMM_RESOURCE_USAGE_OCL_IMAGE_FROM_BUFFER ) DEFINE_RESOURCE_USAGE( GMM_RESOURCE_USAGE_OCL_SELF_SNOOP_BUFFER ) DEFINE_RESOURCE_USAGE( GMM_RESOURCE_USAGE_OCL_BUFFER_NO_LLC_CACHING ) DEFINE_RESOURCE_USAGE( GMM_RESOURCE_USAGE_OCL_IMAGE_NO_LLC_CACHING ) // Cross Adapter DEFINE_RESOURCE_USAGE( GMM_RESOURCE_USAGE_XADAPTER_SHARED_RESOURCE ) // BCS usages DEFINE_RESOURCE_USAGE( GMM_RESOURCE_USAGE_BLT_SOURCE ) DEFINE_RESOURCE_USAGE( GMM_RESOURCE_USAGE_BLT_DESTINATION ) DEFINE_RESOURCE_USAGE( GMM_RESOURCE_USAGE_CAMERA_CAPTURE ) // Xe_LPG+ Media Usages DEFINE_RESOURCE_USAGE(GMM_RESOURCE_USAGE_MEDIA_BATCH_BUFFERS) // DECODE DEFINE_RESOURCE_USAGE(GMM_RESOURCE_USAGE_DECODE_INPUT_BITSTREAM) DEFINE_RESOURCE_USAGE(GMM_RESOURCE_USAGE_DECODE_INPUT_REFERENCE) DEFINE_RESOURCE_USAGE(GMM_RESOURCE_USAGE_DECODE_INTERNAL_READ) DEFINE_RESOURCE_USAGE(GMM_RESOURCE_USAGE_DECODE_INTERNAL_WRITE) DEFINE_RESOURCE_USAGE(GMM_RESOURCE_USAGE_DECODE_INTERNAL_READ_WRITE_CACHE) DEFINE_RESOURCE_USAGE(GMM_RESOURCE_USAGE_DECODE_INTERNAL_READ_WRITE_NOCACHE) DEFINE_RESOURCE_USAGE(GMM_RESOURCE_USAGE_DECODE_OUTPUT_PICTURE) DEFINE_RESOURCE_USAGE(GMM_RESOURCE_USAGE_DECODE_OUTPUT_STATISTICS_WRITE) DEFINE_RESOURCE_USAGE(GMM_RESOURCE_USAGE_DECODE_OUTPUT_STATISTICS_READ_WRITE) // ENCODE DEFINE_RESOURCE_USAGE(GMM_RESOURCE_USAGE_ENCODE_INPUT_RAW) DEFINE_RESOURCE_USAGE(GMM_RESOURCE_USAGE_ENCODE_INPUT_RECON) DEFINE_RESOURCE_USAGE(GMM_RESOURCE_USAGE_ENCODE_INTERNAL_READ) DEFINE_RESOURCE_USAGE(GMM_RESOURCE_USAGE_ENCODE_INTERNAL_WRITE) DEFINE_RESOURCE_USAGE(GMM_RESOURCE_USAGE_ENCODE_INTERNAL_READ_WRITE_CACHE) DEFINE_RESOURCE_USAGE(GMM_RESOURCE_USAGE_ENCODE_INTERNAL_READ_WRITE_NOCACHE) DEFINE_RESOURCE_USAGE(GMM_RESOURCE_USAGE_ENCODE_EXTERNAL_READ) DEFINE_RESOURCE_USAGE(GMM_RESOURCE_USAGE_ENCODE_OUTPUT_PICTURE) DEFINE_RESOURCE_USAGE(GMM_RESOURCE_USAGE_ENCODE_OUTPUT_BITSTREAM) DEFINE_RESOURCE_USAGE(GMM_RESOURCE_USAGE_ENCODE_OUTPUT_STATISTICS_WRITE) DEFINE_RESOURCE_USAGE(GMM_RESOURCE_USAGE_ENCODE_OUTPUT_STATISTICS_READ_WRITE) // VP DEFINE_RESOURCE_USAGE(GMM_RESOURCE_USAGE_VP_INPUT_PICTURE_FF) DEFINE_RESOURCE_USAGE(GMM_RESOURCE_USAGE_VP_INPUT_REFERENCE_FF) DEFINE_RESOURCE_USAGE(GMM_RESOURCE_USAGE_VP_INTERNAL_READ_FF) DEFINE_RESOURCE_USAGE(GMM_RESOURCE_USAGE_VP_INTERNAL_WRITE_FF) DEFINE_RESOURCE_USAGE(GMM_RESOURCE_USAGE_VP_INTERNAL_READ_WRITE_FF) DEFINE_RESOURCE_USAGE(GMM_RESOURCE_USAGE_VP_OUTPUT_PICTURE_FF) DEFINE_RESOURCE_USAGE(GMM_RESOURCE_USAGE_VP_INPUT_PICTURE_RENDER) DEFINE_RESOURCE_USAGE(GMM_RESOURCE_USAGE_VP_INPUT_REFERENCE_RENDER) DEFINE_RESOURCE_USAGE(GMM_RESOURCE_USAGE_VP_INTERNAL_READ_RENDER) DEFINE_RESOURCE_USAGE(GMM_RESOURCE_USAGE_VP_INTERNAL_WRITE_RENDER) DEFINE_RESOURCE_USAGE(GMM_RESOURCE_USAGE_VP_INTERNAL_READ_WRITE_RENDER) DEFINE_RESOURCE_USAGE(GMM_RESOURCE_USAGE_VP_OUTPUT_PICTURE_RENDER) // CP DEFINE_RESOURCE_USAGE(GMM_RESOURCE_USAGE_CP_EXTERNAL_READ) DEFINE_RESOURCE_USAGE(GMM_RESOURCE_USAGE_CP_INTERNAL_WRITE) DEFINE_RESOURCE_USAGE(GMM_RESOURCE_USAGE_GSC_KMD_RESOURCE) DEFINE_RESOURCE_USAGE(GMM_RESOURCE_USAGE_KMD_NULL_CONTEXT_BB) DEFINE_RESOURCE_USAGE(GMM_RESOURCE_USAGE_COMMAND_STREAMER) //Uncacheable copies DEFINE_RESOURCE_USAGE(GMM_RESOURCE_USAGE_COPY_SOURCE) DEFINE_RESOURCE_USAGE(GMM_RESOURCE_USAGE_COPY_DEST) // Shader resource uncachable, needed for WA_18013889147 DEFINE_RESOURCE_USAGE(GMM_RESOURCE_USAGE_SHADER_RESOURCE_L1_NOT_CACHED) DEFINE_RESOURCE_USAGE(GMM_RESOURCE_USAGE_UMD_OCA_BUFFER) gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/CachePolicy/GmmCachePolicyUndefineConditionals.h000066400000000000000000000024421466655022700312620ustar00rootroot00000000000000/*============================================================================== Copyright(c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ============================================================================*/ #undef PRODUCT #undef SKU #undef WA #undef _L3 #undef _LLC #undef _ELLC #undef KB #undef MB gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/CachePolicy/GmmGen10CachePolicy.cpp000066400000000000000000000445761466655022700264010ustar00rootroot00000000000000/*============================================================================== Copyright(c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ============================================================================*/ #include "Internal/Common/GmmLibInc.h" #include "External/Common/GmmCachePolicy.h" #include "External/Common/CachePolicy/GmmCachePolicyGen10.h" //============================================================================= // // Function: __GmmGen10InitCachePolicy // // Desc: This function initializes the cache policy // // Parameters: pCachePolicy -> Ptr to array to be populated with the // mapping of usages -> cache settings. // // Return: GMM_STATUS // //----------------------------------------------------------------------------- GMM_STATUS GmmLib::GmmGen10CachePolicy::InitCachePolicy() { __GMM_ASSERTPTR(pCachePolicy, GMM_ERROR); #define DEFINE_CACHE_ELEMENT(usage, llc, ellc, l3, wt, age, lecc_scc, l3_scc, sso, cos, hdcl1) DEFINE_CP_ELEMENT(usage, llc, ellc, l3, wt, age, 0, lecc_scc, l3_scc, 0, sso, cos, hdcl1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) #include "GmmGen10CachePolicy.h" #define TC_LLC (1) #define TC_ELLC (0) //Is this supported anymore in TargetCache? #define TC_LLC_ELLC (2) #define LeCC_UNCACHEABLE (0x1) #define LeCC_WT_CACHEABLE (0x2) //Only used as MemPushWRite disqualifier if set along with eLLC-only #define LeCC_WB_CACHEABLE (0x3) #define L3_UNCACHEABLE (0x1) #define L3_WB_CACHEABLE (0x3) #define DISABLE_SKIP_CACHING_CONTROL (0x0) #define ENABLE_SKIP_CACHING_CONTROL (0x1) #define DISABLE_SELF_SNOOP_OVERRIDE (0x0) #define ENABLE_SELF_SNOOP_OVERRIDE (0x1) #define ENABLE_SELF_SNOOP_ALWAYS (0x3) #define CLASS_SERVICE_ZERO 0 { // Define index of cache element uint32_t Usage = 0; uint32_t CurrentMaxIndex = 0; uint32_t CurrentMaxHDCL1Index = GMM_GEN10_HDCL1_MOCS_INDEX_START - 1; // define constant GMM_CACHE_POLICY_TBL_ELEMENT *pCachePolicyTlbElement = pGmmLibContext->GetCachePolicyTlbElement(); // index 0 is uncached. { GMM_CACHE_POLICY_TBL_ELEMENT *Entry0 = &(pCachePolicyTlbElement[0]); Entry0->LeCC.Cacheability = LeCC_UNCACHEABLE; Entry0->LeCC.TargetCache = TC_LLC_ELLC; Entry0->LeCC.LRUM = 0; Entry0->LeCC.ESC = DISABLE_SKIP_CACHING_CONTROL; Entry0->LeCC.SCC = 0; Entry0->LeCC.CoS = CLASS_SERVICE_ZERO; Entry0->LeCC.SelfSnoop = DISABLE_SELF_SNOOP_OVERRIDE; Entry0->L3.Cacheability = L3_UNCACHEABLE; Entry0->L3.ESC = DISABLE_SKIP_CACHING_CONTROL; Entry0->L3.SCC = 0; Entry0->HDCL1 = 0; } // Process the cache policy and fill in the look up table for(; Usage < GMM_RESOURCE_USAGE_MAX; Usage++) { bool CachePolicyError = false; int32_t CPTblIdx = -1; uint32_t j = 0; uint64_t PTEValue = 0; GMM_CACHE_POLICY_TBL_ELEMENT UsageEle = {0}; UsageEle.LeCC.Reserved = 0; // Reserved bits zeroe'd, this is so we // we can compare the unioned LeCC.DwordValue. UsageEle.LeCC.SelfSnoop = DISABLE_SELF_SNOOP_OVERRIDE; UsageEle.LeCC.CoS = CLASS_SERVICE_ZERO; UsageEle.LeCC.SCC = 0; UsageEle.LeCC.ESC = 0; if(pCachePolicy[Usage].SSO & ENABLE_SELF_SNOOP_OVERRIDE) { UsageEle.LeCC.SelfSnoop = pCachePolicy[Usage].SSO & ENABLE_SELF_SNOOP_ALWAYS; } if(pCachePolicy[Usage].CoS) { UsageEle.LeCC.CoS = pCachePolicy[Usage].CoS; } if(pCachePolicy[Usage].HDCL1) { UsageEle.HDCL1 = 1; } if(pCachePolicy[Usage].LeCC_SCC) { UsageEle.LeCC.SCC = pCachePolicy[Usage].LeCC_SCC; UsageEle.LeCC.ESC = ENABLE_SKIP_CACHING_CONTROL; } UsageEle.LeCC.LRUM = pCachePolicy[Usage].AGE; // default to LLC/ELLC target cache. UsageEle.LeCC.TargetCache = TC_LLC_ELLC; UsageEle.LeCC.Cacheability = LeCC_WB_CACHEABLE; if(pCachePolicy[Usage].LLC && pCachePolicy[Usage].ELLC) { UsageEle.LeCC.TargetCache = TC_LLC_ELLC; } else if(pCachePolicy[Usage].LLC) { UsageEle.LeCC.TargetCache = TC_LLC; } else if(pCachePolicy[Usage].ELLC) { UsageEle.LeCC.TargetCache = TC_ELLC; if(pCachePolicy[Usage].WT) { UsageEle.LeCC.Cacheability = LeCC_WT_CACHEABLE; } } else { UsageEle.LeCC.Cacheability = LeCC_UNCACHEABLE; } UsageEle.L3.Reserved = 0; // Reserved bits zeroe'd, this is so we // we can compare the unioned L3.UshortValue. UsageEle.L3.ESC = DISABLE_SKIP_CACHING_CONTROL; UsageEle.L3.SCC = 0; UsageEle.L3.Cacheability = pCachePolicy[Usage].L3 ? L3_WB_CACHEABLE : L3_UNCACHEABLE; if(pCachePolicy[Usage].L3_SCC) { UsageEle.L3.ESC = ENABLE_SKIP_CACHING_CONTROL; UsageEle.L3.SCC = (uint16_t)pCachePolicy[Usage].L3_SCC; } //For HDC L1 caching, MOCS Table index 48-61 should be used if(UsageEle.HDCL1) { for(j = GMM_GEN10_HDCL1_MOCS_INDEX_START; j <= CurrentMaxHDCL1Index; j++) { GMM_CACHE_POLICY_TBL_ELEMENT *TblEle = &pCachePolicyTlbElement[j]; if(TblEle->LeCC.DwordValue == UsageEle.LeCC.DwordValue && TblEle->L3.UshortValue == UsageEle.L3.UshortValue && TblEle->HDCL1 == UsageEle.HDCL1) { CPTblIdx = j; break; } } } else { for(j = 0; j <= CurrentMaxIndex; j++) { GMM_CACHE_POLICY_TBL_ELEMENT *TblEle = &pCachePolicyTlbElement[j]; if(TblEle->LeCC.DwordValue == UsageEle.LeCC.DwordValue && TblEle->L3.UshortValue == UsageEle.L3.UshortValue && TblEle->HDCL1 == UsageEle.HDCL1) { CPTblIdx = j; break; } } } // Didn't find the caching settings in one of the already programmed lookup table entries. // Need to add a new lookup table entry. if(CPTblIdx == -1) { if(UsageEle.HDCL1 && CurrentMaxHDCL1Index < GMM_GEN9_MAX_NUMBER_MOCS_INDEXES - 1) { GMM_CACHE_POLICY_TBL_ELEMENT *TblEle = &(pCachePolicyTlbElement[++CurrentMaxHDCL1Index]); CPTblIdx = CurrentMaxHDCL1Index; TblEle->LeCC.DwordValue = UsageEle.LeCC.DwordValue; TblEle->L3.UshortValue = UsageEle.L3.UshortValue; TblEle->HDCL1 = UsageEle.HDCL1; } else if(CurrentMaxIndex < GMM_GEN10_HDCL1_MOCS_INDEX_START) { GMM_CACHE_POLICY_TBL_ELEMENT *TblEle = &(pCachePolicyTlbElement[++CurrentMaxIndex]); CPTblIdx = CurrentMaxIndex; TblEle->LeCC.DwordValue = UsageEle.LeCC.DwordValue; TblEle->L3.UshortValue = UsageEle.L3.UshortValue; TblEle->HDCL1 = UsageEle.HDCL1; } else { // Too many unique caching combinations to program the // MOCS lookup table. CachePolicyError = true; GMM_ASSERTDPF( "Cache Policy Init Error: Invalid Cache Programming, too many unique caching combinations" "(we only support GMM_GEN_MAX_NUMBER_MOCS_INDEXES = %d)", GMM_GEN9_MAX_NUMBER_MOCS_INDEXES - 1); // Set cache policy index to uncached. CPTblIdx = 0; } } // PTE entries do not control caching on SKL+ (for legacy context) if(!GetUsagePTEValue(pCachePolicy[Usage], Usage, &PTEValue)) { CachePolicyError = true; } pCachePolicy[Usage].PTE.DwordValue = PTEValue & 0xFFFFFFFF; pCachePolicy[Usage].PTE.HighDwordValue = 0; pCachePolicy[Usage].MemoryObjectOverride.Gen10.Index = CPTblIdx; pCachePolicy[Usage].Override = ALWAYS_OVERRIDE; if(CachePolicyError) { GMM_ASSERTDPF("Cache Policy Init Error: Invalid Cache Programming - Element %d", Usage); } } CurrentMaxMocsIndex = CurrentMaxIndex; CurrentMaxL1HdcMocsIndex = CurrentMaxHDCL1Index; } return GMM_SUCCESS; } ///////////////////////////////////////////////////////////////////////////////////// /// Initializes WA's needed for setting up the Private PATs /// WaNoMocsEllcOnly, WaGttPat0, WaGttPat0GttWbOverOsIommuEllcOnly, WaGttPat0WB /// /// @return GMM_STATUS /// ///////////////////////////////////////////////////////////////////////////////////// GMM_STATUS GmmLib::GmmGen10CachePolicy::SetPATInitWA() { GMM_STATUS Status = GMM_SUCCESS; #if(defined(__GMM_KMD__)) if(pGmmLibContext->GetGtSysInfoPtr()->EdramSizeInKb) { const_cast(pGmmLibContext->GetWaTable()).WaNoMocsEllcOnly = 1; } #else Status = GMM_ERROR; #endif return Status; } ///////////////////////////////////////////////////////////////////////////////////// /// Returns the PAT idx that best matches the cache policy for this usage. /// /// @param: CachePolicy: cache policy for a usage /// /// @return PAT Idx to use in the PTE ///////////////////////////////////////////////////////////////////////////////////// uint32_t GmmLib::GmmGen10CachePolicy::BestMatchingPATIdx(GMM_CACHE_POLICY_ELEMENT CachePolicy) { uint32_t i; uint32_t PATIdx = 0; GMM_GFX_MEMORY_TYPE WantedMemoryType = GMM_GFX_UC_WITH_FENCE, MemoryType; GMM_GFX_TARGET_CACHE WantedTC = GMM_GFX_TC_ELLC_LLC; WantedMemoryType = GetWantedMemoryType(CachePolicy); if(CachePolicy.LLC && CachePolicy.ELLC) { WantedTC = GMM_GFX_TC_ELLC_LLC; } else if(CachePolicy.LLC) { WantedTC = GMM_GFX_TC_LLC_ONLY; } else if(CachePolicy.ELLC) { WantedTC = GMM_GFX_TC_ELLC_ONLY; // Note: this overrides the MOCS target cache selection. } for(i = 1; i < NumPATRegisters; i++) { GMM_PRIVATE_PAT PAT1 = GetPrivatePATEntry(PATIdx); GMM_PRIVATE_PAT PAT2 = GetPrivatePATEntry(i); if(SelectNewPATIdx(WantedMemoryType, WantedTC, (GMM_GFX_MEMORY_TYPE)PAT1.Gen10.MemoryType, (GMM_GFX_TARGET_CACHE)PAT1.Gen10.TargetCache, (GMM_GFX_MEMORY_TYPE)PAT2.Gen10.MemoryType, (GMM_GFX_TARGET_CACHE)PAT2.Gen10.TargetCache)) { PATIdx = i; } } MemoryType = (GMM_GFX_MEMORY_TYPE)GetPrivatePATEntry(PATIdx).Gen10.MemoryType; if(MemoryType != WantedMemoryType) { // Failed to find a matching PAT entry return GMM_PAT_ERROR; } return PATIdx; } ///////////////////////////////////////////////////////////////////////////////////// /// Initializes the Gfx PAT tables for AdvCtx and Gfx MMIO/Private PAT /// PAT0 = WB_COHERENT or UC depending on WaGttPat0WB /// PAT1 = UC or WB_COHERENT depending on WaGttPat0WB /// PAT2 = WB_MOCSLESS, with TC = eLLC+LLC /// PAT3 = WB /// PAT4 = WT /// PAT5 = WC /// PAT6 = WC /// PAT7 = WC /// HLD says to set to PAT0/1 to WC, but since we don't have a WC in GPU, /// WC option is same as UC. Hence setting PAT0 or PAT1 to UC. /// Unused PAT's (5,6,7) are set to WC. /// /// @return GMM_STATUS ///////////////////////////////////////////////////////////////////////////////////// GMM_STATUS GmmLib::GmmGen10CachePolicy::SetupPAT() { GMM_STATUS Status = GMM_SUCCESS; #if(defined(__GMM_KMD__)) uint32_t i = 0; GMM_GFX_MEMORY_TYPE GfxMemType = GMM_GFX_UC_WITH_FENCE; // No optional selection on Age or Target Cache because for an SVM-OS Age and // Target Cache would not work [for an SVM-OS the Page Table is shared with IA // and we don't have control of the PAT Idx]. If there is a strong ask from D3D // or the performance analysis team, Age could be added. // Add Class of Service when required. GMM_GFX_TARGET_CACHE GfxTargetCache = GMM_GFX_TC_ELLC_LLC; uint8_t Age = 1; uint8_t ServiceClass = 0; int32_t * pPrivatePATTableMemoryType = NULL; pPrivatePATTableMemoryType = pGmmLibContext->GetPrivatePATTableMemoryType(); __GMM_ASSERT(pGmmLibContext->GetSkuTable().FtrIA32eGfxPTEs); for(i = 0; i < GMM_NUM_GFX_PAT_TYPES; i++) { pPrivatePATTableMemoryType[i] = -1; } // Set values for GmmGlobalInfo PrivatePATTable for(i = 0; i < NumPATRegisters; i++) { GMM_PRIVATE_PAT PAT = {0}; if(pGmmLibContext->GetWaTable().WaNoMocsEllcOnly) { GfxTargetCache = GMM_GFX_TC_ELLC_ONLY; } else { GfxTargetCache = GMM_GFX_TC_ELLC_LLC; } switch(i) { case PAT0: if(pGmmLibContext->GetWaTable().WaGttPat0) { if(pGmmLibContext->GetWaTable().WaGttPat0WB) { GfxMemType = GMM_GFX_WB; if(GFX_IS_ATOM_PLATFORM(pGmmLibContext)) { PAT.PreGen10.Snoop = 1; } pPrivatePATTableMemoryType[GMM_GFX_PAT_WB_COHERENT] = PAT0; } else { GfxMemType = GMM_GFX_UC_WITH_FENCE; pPrivatePATTableMemoryType[GMM_GFX_PAT_UC] = PAT0; } } else // if GTT is not tied to PAT0 then WaGttPat0WB is NA { GfxMemType = GMM_GFX_WB; if(GFX_IS_ATOM_PLATFORM(pGmmLibContext)) { PAT.PreGen10.Snoop = 1; } pPrivatePATTableMemoryType[GMM_GFX_PAT_WB_COHERENT] = PAT0; } break; case PAT1: if(pGmmLibContext->GetWaTable().WaGttPat0 && !pGmmLibContext->GetWaTable().WaGttPat0WB) { GfxMemType = GMM_GFX_WB; if(GFX_IS_ATOM_PLATFORM(pGmmLibContext)) { PAT.PreGen10.Snoop = 1; } pPrivatePATTableMemoryType[GMM_GFX_PAT_WB_COHERENT] = PAT1; } else { GfxMemType = GMM_GFX_UC_WITH_FENCE; pPrivatePATTableMemoryType[GMM_GFX_PAT_UC] = PAT1; } break; case PAT2: // This PAT idx shall be used for MOCS'Less resources like Page Tables // Page Tables have TC hardcoded to eLLC+LLC in Adv Ctxt. Hence making this to have same in Leg Ctxt. // For BDW-H, due to Perf issue, TC has to be eLLC only for Page Tables when eDRAM is present. GfxMemType = GMM_GFX_WB; GfxTargetCache = GMM_GFX_TC_ELLC_LLC; pPrivatePATTableMemoryType[GMM_GFX_PAT_WB_MOCSLESS] = PAT2; break; case PAT3: GfxMemType = GMM_GFX_WB; pPrivatePATTableMemoryType[GMM_GFX_PAT_WB] = PAT3; break; case PAT4: GfxMemType = GMM_GFX_WT; pPrivatePATTableMemoryType[GMM_GFX_PAT_WT] = PAT4; break; case PAT5: case PAT6: case PAT7: GfxMemType = GMM_GFX_WC; pPrivatePATTableMemoryType[GMM_GFX_PAT_WC] = PAT5; break; default: __GMM_ASSERT(0); Status = GMM_ERROR; } PAT.Gen10.MemoryType = GfxMemType; PAT.Gen10.TargetCache = GfxTargetCache; PAT.Gen10.Age = Age; PAT.Gen10.CoS = ServiceClass; SetPrivatePATEntry(i, PAT); } #else Status = GMM_ERROR; #endif return Status; } gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/CachePolicy/GmmGen10CachePolicy.h000077500000000000000000000673151466655022700260450ustar00rootroot00000000000000/*============================================================================== Copyright(c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ============================================================================*/ #include "GmmCachePolicyConditionals.h" #define EDRAM (SKU(FtrEDram)) #define FBLLC (SKU(FtrFrameBufferLLC)) //eDRAM-Only caching, for a usage that might be encrypted, must use ENCRYPTED_PARTIALS_EDRAM #define ENCRYPTED_PARTIALS_EDRAM (EDRAM && !(pGmmLibContext->GetWaTable().WaEncryptedEdramOnlyPartials)) // Cache Policy Definition // AOM = Do not allocate on miss (0 = allocate on miss [normal cache behavior], 1 = don't allocate on miss) // LeCC_SCC = LLC/eLLC skip caching control (disabled if LeCC_SCC = 0) // L3_SCC = L3 skip caching control (disabled if L3_SCC = 0) // SSO = Override MIDI self snoop settings (1 = never send to uncore, 3 = always send to uncore, 0 = [default] No override ) // CoS = Class of Service ( allowed values 1, 2, 3 for class IDs 1, 2, 3 respectively, default class 1 => driver overrides 0->1) // HDCL1 = HDC L1 cache control (1 = cached in HDC L1, 0 = not cached in HDC L1) // Faster PushWrite(Gen10+) used iff !WT, eLLC-only cacheable - Globally visible surface (eg display surface) should be marked WT //***************************************************************************************************************/ // USAGE TYPE , LLC , ELLC , L3 , WT , AGE , LeCC_SCC , L3_SCC, SSO, CoS, HDCL1 ) /****************************************************************************************************************/ // KMD Usages DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_BATCH_BUFFER , 0 , 0 , 0 , 0 , 0 , 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_COMP_FRAME_BUFFER , 0 , 0 , 0 , 0 , 0 , 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_CONTEXT_SWITCH_BUFFER , 0 , 0 , 0 , 0 , 0 , 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_CURSOR , 0 , 0 , 0 , 0 , 0 , 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_DISPLAY_STATIC_IMG_FOR_SMOOTH_ROTATION_BUFFER , 0 , 0 , 0 , 0 , 0 , 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_DUMMY_PAGE , 0 , 0 , 0 , 0 , 0 , 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_GDI_SURFACE , 1 , 1 , 1 , 0 , 3 , 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_GENERIC_KMD_RESOURCE , 0 , 0 , 0 , 0 , 0 , 0, 0, 0, 0, 0); // GMM_RESOURCE_USAGE_GFX_RING is only used if WaEnableRingHostMapping is enabled. DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_GFX_RING , 0 , 0 , 0 , 0 , 0 , 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_GTT_TRANSFER_REGION , 0 , 0 , 0 , 0 , 0 , 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_HW_CONTEXT , 0 , 0 , 0 , 0 , 0 , 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_STATE_MANAGER_KERNEL_STATE , 0 , 0 , 0 , 0 , 0 , 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_KMD_STAGING_SURFACE , 1 , 1 , 1 , 0 , 3 , 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_MBM_BUFFER , 0 , 0 , 0 , 0 , 0 , 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_NNDI_BUFFER , 0 , 0 , 0 , 0 , 0 , 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_OVERLAY_MBM , 0 , 0 , 0 , 0 , 0 , 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_PRIMARY_SURFACE , 0 , 0 , 0 , 0 , 0 , 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_SCREEN_PROTECTION_INTERMEDIATE_SURFACE , 0 , 0 , 0 , 0 , 0 , 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_SHADOW_SURFACE , 1 , 1 , 1 , 0 , 3 , 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_SM_SCRATCH_STATE , 0 , 0 , 0 , 0 , 0 , 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_STATUS_PAGE , 1 , 1 , 1 , 0 , 3 , 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_TIMER_PERF_QUEUE , 0 , 0 , 0 , 0 , 0 , 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_UNKNOWN , 0 , 0 , 0 , 0 , 0 , 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_UNMAP_PAGING_RESERVED_GTT_DMA_BUFFER , 0 , 0 , 0 , 0 , 0 , 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_VSC_BATCH_BUFFER , 0 , 0 , 0 , 0 , 0 , 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_WA_BATCH_BUFFER , 0 , 0 , 0 , 0 , 0 , 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_KMD_OCA_BUFFER , 0 , 0 , 0 , 0 , 0 , 0, 0, 0, 0, 0); // // 3D Usages // DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_UMD_BATCH_BUFFER , 0 , 0 , 0 , 0 , 0 , 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_BINDING_TABLE_POOL , 1 , 0 , 1 , 0 , 3 , 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_CCS , 1 , 0 , 0 , 0 , 3 , 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_CONSTANT_BUFFER_POOL , 1 , 0 , 1 , 0 , 3 , 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_DEPTH_BUFFER , 1 , 0 , 0 , 0 , 3 , 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_DISPLAYABLE_RENDER_TARGET , FBLLC, ENCRYPTED_PARTIALS_EDRAM, FBLLC, !FBLLC && ENCRYPTED_PARTIALS_EDRAM, 3 , 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_GATHER_POOL , 0 , 0 , 0 , 0 , 3 , 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_HEAP_SURFACE_STATE , 1 , 0 , 1 , 0 , 3 , 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_HEAP_DYNAMIC_STATE , 1 , 1 , 1 , 0 , 3 , 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_HEAP_GENERAL_STATE , 1 , 0 , 1 , 0 , 3 , 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_HEAP_GENERAL_STATE_UC , 0 , 0 , 0 , 0 , 3 , 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_HEAP_STATELESS_DATA_PORT , 1 , 0 , 1 , 0 , 3 , 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_HEAP_INDIRECT_OBJECT , 1 , 0 , 1 , 0 , 3 , 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_HEAP_INSTRUCTION , 1 , 0 , 1 , 0 , 3 , 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_HIZ , 1 , 0 , 1 , 0 , 3 , 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_INDEX_BUFFER , 1 , 0 , 1 , 0 , 3 , 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_MCS , 1 , 0 , 0 , 0 , 3 , 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_PUSH_CONSTANT_BUFFER , 0 , 0 , 0 , 0 , 3 , 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_PULL_CONSTANT_BUFFER , 1 , 0 , 1 , 0 , 3 , 0, 0, 0, 0, 1); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_QUERY , 1 , 1 , 1 , 0 , 3 , 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_RENDER_TARGET , 1 , 0 , 0 , 0 , 3 , 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_SHADER_RESOURCE , 1 , 0 , 1 , 0 , 3 , 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_STAGING , 1 , 1 , 1 , 0 , 3 , 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_STENCIL_BUFFER , 1 , 0 , 1 , 0 , 3 , 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_STREAM_OUTPUT_BUFFER , 0 , 0 , 0 , 0 , 3 , 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_TILE_POOL , 1 , 1 , 1 , 0 , 3 , 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_PROCEDURAL_TEXTURE , 0 , 0 , 0 , 0 , 0 , 0, 0, 0, 0, 0); // Tiled Resource DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_TILED_DEPTH_BUFFER , 1 , 0 , 0 , 0 , 3 , 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_TILED_HIZ , 1 , 0 , 1 , 0 , 3 , 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_TILED_MCS , 1 , 0 , 0 , 0 , 3 , 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_TILED_CCS , 1 , 0 , 0 , 0 , 3 , 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_TILED_RENDER_TARGET , 1 , 0 , 0 , 0 , 3 , 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_TILED_RENDER_TARGET_AND_SHADER_RESOURCE , 1 , 0 , 1 , 0 , 3 , 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_TILED_SHADER_RESOURCE , 1 , 0 , 1 , 0 , 3 , 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_TILED_UAV , 1 , 0 , 1 , 0 , 3 , 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_UAV , 1 , 0 , 1 , 0 , 3 , 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_VERTEX_BUFFER , 1 , 0 , 0 , 0 , 3 , 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_OGL_WSTN_VERTEX_BUFFER , 1 , 0 , 0 , 0 , 3 , 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_RENDER_TARGET_AND_SHADER_RESOURCE , 1 , 0 , 1 , 0 , 3 , 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_WDDM_HISTORY_BUFFER , 0 , 0 , 0 , 0 , 3 , 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_CONTEXT_SAVE_RESTORE , 1 , 1 , 1 , 0 , 3 , 0, 0, 0, 0, 0); // // CM USAGES // DEFINE_CACHE_ELEMENT(CM_RESOURCE_USAGE_SurfaceState, 1 , 1 , 1 , 0 ,3 , 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(CM_RESOURCE_USAGE_NO_L3_SurfaceState, 1 , 1 , 0 , 0 ,3, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(CM_RESOURCE_USAGE_NO_LLC_ELLC_SurfaceState, 0 , 0 , 1 , 0 ,3, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(CM_RESOURCE_USAGE_NO_LLC_SurfaceState, 0 , 1 , 1 , 0 ,3, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(CM_RESOURCE_USAGE_NO_ELLC_SurfaceState, 1 , 0 , 1 , 0 ,3, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(CM_RESOURCE_USAGE_NO_LLC_L3_SurfaceState, 0 , 1 , 0 , 0 ,3, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(CM_RESOURCE_USAGE_NO_ELLC_L3_SurfaceState, 1 , 0 , 0 , 0 ,3, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(CM_RESOURCE_USAGE_NO_CACHE_SurfaceState, 0 , 0 , 0 , 0 ,3, 0, 0, 0, 0, 0); // // MP USAGES // DEFINE_CACHE_ELEMENT(MP_RESOURCE_USAGE_BEGIN, 0 , 0 , 0 , 0 , 0, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(MP_RESOURCE_USAGE_DEFAULT, 0 , 0 , 0 , 0 , 0, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(MP_RESOURCE_USAGE_SurfaceState, 1 , EDRAM, 1 , 0 , 1, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(MP_RESOURCE_USAGE_AGE3_SurfaceState, 1 , EDRAM, 1 , 0 , 3, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(MP_RESOURCE_USAGE_END, 0 , 0 , 0 , 0 , 0, 0, 0, 0, 0, 0); // MHW - SFC DEFINE_CACHE_ELEMENT(MHW_RESOURCE_USAGE_Sfc_CurrentOutputSurface, 0 , 0 , 0 , 0 , 0, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(MHW_RESOURCE_USAGE_Sfc_AvsLineBufferSurface, 1 , EDRAM, 1 , 0 , 1, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(MHW_RESOURCE_USAGE_Sfc_IefLineBufferSurface, 1 , EDRAM, 1 , 0 , 1, 0, 0, 0, 0, 0); //Media GMM Resource USAGES DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_PRE_DEBLOCKING_CODEC , 0 , EDRAM , 0 , 0 , 3, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_POST_DEBLOCKING_CODEC , 0 , EDRAM , 0 , 0 , 3, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_ORIGINAL_UNCOMPRESSED_PICTURE_ENCODE , 0 , EDRAM , 0 , 0 , 3, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_ORIGINAL_UNCOMPRESSED_PICTURE_DECODE , 0 , EDRAM , 0 , 0 , 3, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_STREAMOUT_DATA_CODEC , 0 , 0 , 0 , 0 , 3, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_INTRA_ROWSTORE_SCRATCH_BUFFER_CODEC , 1 , EDRAM , 0 , 0 , 3, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_DEBLOCKINGFILTER_ROWSTORE_SCRATCH_BUFFER_CODEC , 1 , EDRAM , 0 , 0 , 3, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_REFERENCE_PICTURE_CODEC , 1 , EDRAM , 0 , 0 , 3, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_MACROBLOCK_STATUS_BUFFER_CODEC , 0 , EDRAM , 0 , 0 , 3, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_MFX_INDIRECT_BITSTREAM_OBJECT_DECODE , 0 , EDRAM , 0 , 0 , 3, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_MFX_INDIRECT_MV_OBJECT_CODEC , 0 , EDRAM , 0 , 0 , 3, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_MFD_INDIRECT_IT_COEF_OBJECT_DECODE , 0 , EDRAM , 0 , 0 , 3, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_MFC_INDIRECT_PAKBASE_OBJECT_CODEC , 0 , EDRAM , 0 , 0 , 3, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_BSDMPC_ROWSTORE_SCRATCH_BUFFER_CODEC , 1 , EDRAM , 0 , 0 , 3, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_MPR_ROWSTORE_SCRATCH_BUFFER_CODEC , 1 , EDRAM , 0 , 0 , 3, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_BITPLANE_READ_CODEC , 0 , EDRAM , 0 , 0 , 3, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_AACSBIT_VECTOR_CODEC , 0 , EDRAM , 0 , 0 , 3, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_DIRECTMV_BUFFER_CODEC , 0 , EDRAM , 0 , 0 , 3, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_SURFACE_CURR_ENCODE , 1 , EDRAM , 1 , 0 , 3, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_SURFACE_REF_ENCODE , 1 , EDRAM , 1 , 0 , 3, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_SURFACE_MV_DATA_ENCODE , 1 , EDRAM , 1 , 0 , 3, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_SURFACE_HME_DOWNSAMPLED_ENCODE , 1 , EDRAM , 1 , 0 , 3, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_SURFACE_HME_DOWNSAMPLED_ENCODE_DST , 1 , EDRAM , 1 , 0 , 3, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_SURFACE_ME_DISTORTION_ENCODE , 1 , EDRAM , 1 , 0 , 3, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_SURFACE_BRC_ME_DISTORTION_ENCODE , 1 , EDRAM , 1 , 0 , 3, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_PAK_OBJECT_ENCODE , 1 , EDRAM , 1 , 0 , 3, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_SURFACE_FLATNESS_CHECK_ENCODE , 1 , EDRAM , 1 , 0 , 3, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_SURFACE_MBENC_CURBE_ENCODE , 1 , EDRAM , 1 , 0 , 3, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_VDENC_ROW_STORE_BUFFER_CODEC , 1 , 0 , 0 , 0 , 3, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_VDENC_STREAMIN_CODEC , 1 , EDRAM , 0 , 0 , 3, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_SURFACE_MB_QP_CODEC , 1 , EDRAM , 1 , 0 , 3, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_HCP_MD_CODEC , 0 , EDRAM , 0 , 0 , 3, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_HCP_SAO_CODEC , 0 , EDRAM , 0 , 0 , 3, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_VP9_PROBABILITY_COUNTER_BUFFER_CODEC , 1 , EDRAM , 1 , 0 , 3, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_HUC_VIRTUAL_ADDR_REGION_BUFFER_CODEC , 1 , EDRAM , 1 , 0 , 3, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_SIZE_STREAMOUT_CODEC , 1 , EDRAM , 0 , 0 , 3, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_COMPRESSED_HEADER_BUFFER_CODEC , 1 , EDRAM , 0 , 0 , 3, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_PROBABILITY_DELTA_BUFFER_CODEC , 1 , EDRAM , 0 , 0 , 3, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_HCP_MV_CODEC , 0 , EDRAM , 0 , 0 , 3, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_HCP_STATUS_ERROR_CODEC , 0 , 0 , 0 , 0 , 3, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_HCP_LCU_ILDB_STREAMOUT_CODEC , 0 , 0 , 0 , 0 , 3, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_VP9_PROBABILITY_BUFFER_CODEC , 1 , EDRAM , 0 , 0 , 3, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_VP9_SEGMENT_ID_BUFFER_CODEC , 1 , EDRAM , 0 , 0 , 3, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_VP9_HVD_ROWSTORE_BUFFER_CODEC , 1 , EDRAM , 0 , 0 , 3, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_MACROBLOCK_ILDB_STREAM_OUT_BUFFER_CODEC , 0 , 0 , 0 , 0 , 3, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_SSE_SRC_PIXEL_ROW_STORE_BUFFER_CODEC , 1 , EDRAM , 0 , 0 , 3, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_SURFACE_UNCACHED , 0 , 0 , 0 , 0 , 3, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_SURFACE_ELLC_ONLY , 0 , EDRAM , 0 , 0 , 3, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_SURFACE_ELLC_LLC_ONLY , 1 , EDRAM , 0 , 0 , 3, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_SURFACE_ELLC_LLC_L3 , 1 , EDRAM , 1 , 0 , 3, 0, 0, 0, 0, 0); /**********************************************************************************/ // // OCL Usages // DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_OCL_BUFFER , 1 , 0 , 1 , 0 , 3 , 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_OCL_BUFFER_CONST , 1 , 0 , 1 , 0 , 3 , 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_OCL_BUFFER_CSR_UC , 0 , 0 , 0 , 0 , 3 , 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_OCL_BUFFER_CACHELINE_MISALIGNED , 1 , 0 , 0 , 0 , 3 , 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_OCL_IMAGE , 1 , 0 , 1 , 0 , 3 , 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_OCL_INLINE_CONST , 1 , 0 , 1 , 0 , 3 , 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_OCL_INLINE_CONST_HDC , 1 , 0 , 1 , 0 , 3 , 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_OCL_SCRATCH , 1 , 0 , 1 , 0 , 3 , 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_OCL_PRIVATE_MEM , 1 , 0 , 1 , 0 , 3 , 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_OCL_PRINTF_BUFFER , 1 , 0 , 1 , 0 , 3 , 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_OCL_STATE_HEAP_BUFFER , 1 , 0 , 1 , 0 , 3 , 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_OCL_SYSTEM_MEMORY_BUFFER , 1 , 0 , 1 , 0 , 3 , 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_OCL_SYSTEM_MEMORY_BUFFER_CACHELINE_MISALIGNED , 1 , 0 , 0 , 0 , 3 , 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_OCL_ISH_HEAP_BUFFER , 1 , 0 , 1 , 0 , 3 , 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_OCL_TAG_MEMORY_BUFFER , 1 , 0 , 1 , 0 , 3 , 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_OCL_TEXTURE_BUFFER , 1 , 0 , 1 , 0 , 3 , 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_OCL_IMAGE_FROM_BUFFER , 1 , 0 , 0 , 0 , 3 , 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_OCL_SELF_SNOOP_BUFFER , 1 , 0 , 1 , 0 , 3 , 0, 0, 3, 0, 0); /**********************************************************************************/ // Cross Adapter DEFINE_CACHE_ELEMENT( GMM_RESOURCE_USAGE_XADAPTER_SHARED_RESOURCE , 0 , 0 , 0 , 0 , 0 , 0, 0, 0, 0, 0); /**********************************************************************************/ DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_CAMERA_CAPTURE , CAM$, 0 , 0 , 0 , CAM$ , 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_COMMAND_STREAMER , 0 , 0 , 0 , 0 , 0 , 0, 0, 0, 0, 0); // Uncacheable copies DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_COPY_SOURCE , 0 , 0 , 0 , 0 , 0 , 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_COPY_DEST , 0 , 0 , 0 , 0 , 0 , 0, 0, 0, 0, 0); #include "GmmCachePolicyUndefineConditionals.h" gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/CachePolicy/GmmGen11CachePolicy.cpp000066400000000000000000000443441466655022700263730ustar00rootroot00000000000000/*============================================================================== Copyright(c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ============================================================================*/ #include "Internal/Common/GmmLibInc.h" #include "External/Common/GmmCachePolicy.h" #include "External/Common/CachePolicy/GmmCachePolicyGen10.h" #include "External/Common/CachePolicy/GmmCachePolicyGen11.h" //============================================================================= // // Function: IsSpecialMOCSUsage // // Desc: This function returns special(hw-reserved) MocsIdx based on usage // // Parameters: usage -> Resource usage type // UpdateMOCS -> True if MOCS Table must be updated, ow false // // Return: int32_t // //----------------------------------------------------------------------------- int32_t GmmLib::GmmGen11CachePolicy::IsSpecialMOCSUsage(GMM_RESOURCE_USAGE_TYPE Usage, bool &UpdateMOCS) { int32_t MocsIdx = -1; UpdateMOCS = true; switch(Usage) { case GMM_RESOURCE_USAGE_MOCS_62: __GMM_ASSERT(pCachePolicy[Usage].L3 == 0); //Architecturally, TR/Aux-TT node isn't L3-cacheable. pCachePolicy[Usage].L3 = 0; MocsIdx = 62; break; case GMM_RESOURCE_USAGE_L3_EVICTION: pCachePolicy[Usage].L3 = 0; MocsIdx = 63; break; default: UpdateMOCS = false; break; } return MocsIdx; } //============================================================================= // // Function: __GmmGen11InitCachePolicy // // Desc: This function initializes the cache policy // // Parameters: pCachePolicy -> Ptr to array to be populated with the // mapping of usages -> cache settings. // // Return: GMM_STATUS // //----------------------------------------------------------------------------- GMM_STATUS GmmLib::GmmGen11CachePolicy::InitCachePolicy() { __GMM_ASSERTPTR(pCachePolicy, GMM_ERROR); #define DEFINE_CACHE_ELEMENT(usage, llc, ellc, l3, wt, age, aom, lecc_scc, l3_scc, scf, sso, cos) DEFINE_CP_ELEMENT(usage, llc, ellc, l3, wt, age, aom, lecc_scc, l3_scc, scf, sso, cos, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) #include "GmmGen11CachePolicy.h" #define TC_LLC (1) #define TC_ELLC (0) //Is this supported anymore in TargetCache? #define TC_LLC_ELLC (2) #define LeCC_UNCACHEABLE (0x1) #define LeCC_WT_CACHEABLE (0x2) //Only used as MemPushWRite disqualifier if set along with eLLC-only #define LeCC_WB_CACHEABLE (0x3) #define L3_UNCACHEABLE (0x1) #define L3_WB_CACHEABLE (0x3) #define DISABLE_SKIP_CACHING_CONTROL (0x0) #define ENABLE_SKIP_CACHING_CONTROL (0x1) #define DISABLE_SELF_SNOOP_OVERRIDE (0x0) #define ENABLE_SELF_SNOOP_OVERRIDE (0x1) #define ENABLE_SELF_SNOOP_ALWAYS (0x3) #define CLASS_SERVICE_ZERO (0x0) // Setup Static MOCS Table { this->SetUpMOCSTable(); } { // Define index of cache element uint32_t Usage = 0; uint32_t CurrentMaxSpecialIndex = GMM_GEN9_MAX_NUMBER_MOCS_INDEXES - 1; #if(_WIN32 && (_DEBUG || _RELEASE_INTERNAL)) OverrideCachePolicy(); #endif // Process the cache policy and fill in the look up table for(; Usage < GMM_RESOURCE_USAGE_MAX; Usage++) { bool CachePolicyError = false; bool SpecialMOCS = false; int32_t CPTblIdx = -1; uint32_t j = 0; uint64_t PTEValue = 0; GMM_CACHE_POLICY_TBL_ELEMENT UsageEle = {0}; CPTblIdx = IsSpecialMOCSUsage((GMM_RESOURCE_USAGE_TYPE)Usage, SpecialMOCS); UsageEle.LeCC.Reserved = 0; // Reserved bits zeroe'd, this is so we // we can compare the unioned LeCC.DwordValue. UsageEle.LeCC.SelfSnoop = DISABLE_SELF_SNOOP_OVERRIDE; UsageEle.LeCC.CoS = CLASS_SERVICE_ZERO; UsageEle.LeCC.SCC = 0; UsageEle.LeCC.ESC = 0; if(pCachePolicy[Usage].SCF && pGmmLibContext->GetSkuTable().FtrLLCBypass) { UsageEle.LeCC.SCF = pCachePolicy[Usage].SCF; } if(pCachePolicy[Usage].SSO & ENABLE_SELF_SNOOP_OVERRIDE) { UsageEle.LeCC.SelfSnoop = pCachePolicy[Usage].SSO & ENABLE_SELF_SNOOP_ALWAYS; } if(pCachePolicy[Usage].CoS) { UsageEle.LeCC.CoS = pCachePolicy[Usage].CoS; } if(pCachePolicy[Usage].LeCC_SCC) { UsageEle.LeCC.SCC = pCachePolicy[Usage].LeCC_SCC; UsageEle.LeCC.ESC = ENABLE_SKIP_CACHING_CONTROL; } UsageEle.LeCC.LRUM = pCachePolicy[Usage].AGE; // default to LLC target cache. UsageEle.LeCC.TargetCache = TC_LLC; UsageEle.LeCC.Cacheability = LeCC_WB_CACHEABLE; if(pCachePolicy[Usage].LLC) { UsageEle.LeCC.TargetCache = TC_LLC; } else { UsageEle.LeCC.Cacheability = LeCC_UNCACHEABLE; } UsageEle.L3.Reserved = 0; // Reserved bits zeroe'd, this is so we // we can compare the unioned L3.UshortValue. UsageEle.L3.ESC = DISABLE_SKIP_CACHING_CONTROL; UsageEle.L3.SCC = 0; UsageEle.L3.Cacheability = pCachePolicy[Usage].L3 ? L3_WB_CACHEABLE : L3_UNCACHEABLE; if(pCachePolicy[Usage].L3_SCC) { UsageEle.L3.ESC = ENABLE_SKIP_CACHING_CONTROL; UsageEle.L3.SCC = (uint16_t)pCachePolicy[Usage].L3_SCC; } if(CPTblIdx >= GMM_GEN9_MAX_NUMBER_MOCS_INDEXES) { GMM_CACHE_POLICY_TBL_ELEMENT *TblEle = &pGmmLibContext->GetCachePolicyTlbElement()[CPTblIdx]; CurrentMaxSpecialIndex = ((uint32_t)CPTblIdx > CurrentMaxSpecialIndex) ? (uint32_t)CPTblIdx : CurrentMaxSpecialIndex; if(SpecialMOCS && //Update if one of special MOCS enums !(TblEle->LeCC.DwordValue == UsageEle.LeCC.DwordValue && TblEle->L3.UshortValue == UsageEle.L3.UshortValue)) { //Assert if being overwritten! __GMM_ASSERT(TblEle->LeCC.DwordValue == 0 && TblEle->L3.UshortValue == 0); } } else { for(j = 1; j <= CurrentMaxMocsIndex; j++) { GMM_CACHE_POLICY_TBL_ELEMENT *TblEle = &pGmmLibContext->GetCachePolicyTlbElement()[j]; if(TblEle->LeCC.DwordValue == UsageEle.LeCC.DwordValue && TblEle->L3.UshortValue == UsageEle.L3.UshortValue) { CPTblIdx = j; break; } } } // Didn't find the caching settings in one of the already programmed Explicit Mocs lookup table entries // Need to add a new explicit mocs lookup table entry. if(CPTblIdx == -1) { #if(_WIN32 && (_DEBUG || _RELEASE_INTERNAL)) // If the Cache Policy setting is overriden through regkey, // don't raise an assert/log error. Raising an assert for debug/perf testing isn't really helpful if(pCachePolicy[Usage].IsOverridenByRegkey) { if(CurrentMaxMocsIndex < GMM_GEN9_MAX_NUMBER_MOCS_INDEXES - 1) { GMM_CACHE_POLICY_TBL_ELEMENT *TblEle = &(pGmmLibContext->GetCachePolicyTlbElement()[++CurrentMaxMocsIndex]); CPTblIdx = CurrentMaxMocsIndex; TblEle->LeCC.DwordValue = UsageEle.LeCC.DwordValue; TblEle->L3.UshortValue = UsageEle.L3.UshortValue; } else { // Too many unique caching combinations to program the // MOCS lookup table. CachePolicyError = true; GMM_ASSERTDPF( "Cache Policy Init Error: Invalid Cache Programming, too many unique caching combinations" "(we only support GMM_GEN_MAX_NUMBER_MOCS_INDEXES = %d)", GMM_GEN9_MAX_NUMBER_MOCS_INDEXES - 1); // Set cache policy index to uncached. CPTblIdx = 0; } } else #endif { GMM_ASSERTDPF(false, "CRITICAL ERROR: Cache Policy Usage value specified by Client in not defined in Fixed MOCS Table!"); // Log Error using regkey to indicate the above error #if(_WIN32 && (_DEBUG || _RELEASE_INTERNAL) && __GMM_KMD__) REGISTRY_OVERRIDE_WRITE(Usage, NewMOCSEntryLeCCValue, UsageEle.LeCC.DwordValue); REGISTRY_OVERRIDE_WRITE(Usage, NewMOCSEntryL3Value, UsageEle.L3.UshortValue); #endif CachePolicyError = true; GMM_ASSERTDPF( "Cache Policy Init Error: Invalid Cache Programming, too many unique caching combinations" "(we only support GMM_GEN_MAX_NUMBER_MOCS_INDEXES = %d)", CurrentMaxMocsIndex); // Set cache policy index to uncached. CPTblIdx = 0; } } // PTE entries do not control caching on SKL+ (for legacy context) if(!GetUsagePTEValue(pCachePolicy[Usage], Usage, &PTEValue)) { CachePolicyError = true; } pCachePolicy[Usage].PTE.DwordValue = PTEValue & 0xFFFFFFFF; pCachePolicy[Usage].PTE.HighDwordValue = 0; pCachePolicy[Usage].MemoryObjectOverride.Gen11.Index = CPTblIdx; pCachePolicy[Usage].Override = ALWAYS_OVERRIDE; if(CachePolicyError) { GMM_ASSERTDPF("Cache Policy Init Error: Invalid Cache Programming - Element %d", Usage); } } CurrentMaxSpecialMocsIndex = CurrentMaxSpecialIndex; } return GMM_SUCCESS; } //============================================================================= // // Function: SetUpMOCSTable // // Desc: // // Parameters: // // Return: GMM_STATUS // //----------------------------------------------------------------------------- void GmmLib::GmmGen11CachePolicy::SetUpMOCSTable() { GMM_CACHE_POLICY_TBL_ELEMENT *pCachePolicyTlbElement = &(pGmmLibContext->GetCachePolicyTlbElement()[0]); #define GMM_DEFINE_MOCS(Index, L3_ESC, L3_SCC, L3_CC, LeCC_CC, LeCC_TC, LeCC_LRUM, LeCC_AOM, LeCC_ESC, LeCC_SCC, LeCC_PFM, LeCC_SCF, LeCC_CoS, LeCC_SelfSnoop) \ { \ pCachePolicyTlbElement[Index].L3.ESC = L3_ESC; \ pCachePolicyTlbElement[Index].L3.SCC = L3_SCC; \ pCachePolicyTlbElement[Index].L3.Cacheability = L3_CC; \ pCachePolicyTlbElement[Index].LeCC.Cacheability = LeCC_CC; \ pCachePolicyTlbElement[Index].LeCC.TargetCache = LeCC_TC; \ pCachePolicyTlbElement[Index].LeCC.LRUM = LeCC_LRUM; \ pCachePolicyTlbElement[Index].LeCC.AOM = LeCC_AOM; \ pCachePolicyTlbElement[Index].LeCC.ESC = LeCC_ESC; \ pCachePolicyTlbElement[Index].LeCC.SCC = LeCC_SCC; \ pCachePolicyTlbElement[Index].LeCC.PFM = LeCC_PFM; \ pCachePolicyTlbElement[Index].LeCC.SCF = LeCC_SCF; \ pCachePolicyTlbElement[Index].LeCC.CoS = LeCC_CoS; \ pCachePolicyTlbElement[Index].LeCC.SelfSnoop = LeCC_SelfSnoop; \ } // clang-format off //Default MOCS Table for(int index = 0; index < GMM_MAX_NUMBER_MOCS_INDEXES; index++) { // Index ESC SCC L3CC LeCC TC LRUM DAoM ERSC SCC PFM SCF CoS SSE GMM_DEFINE_MOCS(index , 0 , 0 , 3 , 3 , 1 , 3 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ) } // Explicit MOCS Table // Index ESC SCC L3CC LeCC TC LRUM DAoM ERSC SCC PFM SCF CoS SSE GMM_DEFINE_MOCS( 1 , 0 , 0 , 3 , 0 , 1 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ) GMM_DEFINE_MOCS( 2 , 0 , 0 , 3 , 3 , 1 , 3 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ) GMM_DEFINE_MOCS( 3 , 0 , 0 , 1 , 1 , 1 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ) GMM_DEFINE_MOCS( 4 , 0 , 0 , 3 , 1 , 1 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ) GMM_DEFINE_MOCS( 5 , 0 , 0 , 1 , 3 , 1 , 3 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ) GMM_DEFINE_MOCS( 6 , 0 , 0 , 1 , 3 , 1 , 1 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ) GMM_DEFINE_MOCS( 7 , 0 , 0 , 3 , 3 , 1 , 1 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ) GMM_DEFINE_MOCS( 8 , 0 , 0 , 1 , 3 , 1 , 2 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ) GMM_DEFINE_MOCS( 9 , 0 , 0 , 3 , 3 , 1 , 2 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ) GMM_DEFINE_MOCS( 10 , 0 , 0 , 1 , 3 , 1 , 3 , 1 , 0 , 0 , 0 , 0 , 0 , 0 ) GMM_DEFINE_MOCS( 11 , 0 , 0 , 3 , 3 , 1 , 3 , 1 , 0 , 0 , 0 , 0 , 0 , 0 ) GMM_DEFINE_MOCS( 12 , 0 , 0 , 1 , 3 , 1 , 1 , 1 , 0 , 0 , 0 , 0 , 0 , 0 ) GMM_DEFINE_MOCS( 13 , 0 , 0 , 3 , 3 , 1 , 1 , 1 , 0 , 0 , 0 , 0 , 0 , 0 ) GMM_DEFINE_MOCS( 14 , 0 , 0 , 1 , 3 , 1 , 2 , 1 , 0 , 0 , 0 , 0 , 0 , 0 ) GMM_DEFINE_MOCS( 15 , 0 , 0 , 3 , 3 , 1 , 2 , 1 , 0 , 0 , 0 , 0 , 0 , 0 ) GMM_DEFINE_MOCS( 16 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ) GMM_DEFINE_MOCS( 17 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ) GMM_DEFINE_MOCS( 18 , 0 , 0 , 3 , 3 , 1 , 3 , 0 , 0 , 0 , 0 , 0 , 0 , 3 ) GMM_DEFINE_MOCS( 19 , 0 , 0 , 3 , 3 , 1 , 3 , 0 , 0 , 7 , 0 , 0 , 0 , 0 ) GMM_DEFINE_MOCS( 20 , 0 , 0 , 3 , 3 , 1 , 3 , 0 , 0 , 3 , 0 , 0 , 0 , 0 ) GMM_DEFINE_MOCS( 21 , 0 , 0 , 3 , 3 , 1 , 3 , 0 , 0 , 1 , 0 , 0 , 0 , 0 ) GMM_DEFINE_MOCS( 22 , 0 , 0 , 3 , 3 , 1 , 3 , 0 , 1 , 3 , 0 , 0 , 0 , 0 ) GMM_DEFINE_MOCS( 23 , 0 , 0 , 3 , 3 , 1 , 3 , 0 , 1 , 7 , 0 , 0 , 0 , 0 ) GMM_DEFINE_MOCS( 62 , 0 , 0 , 1 , 3 , 1 , 3 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ) GMM_DEFINE_MOCS( 63 , 0 , 0 , 1 , 3 , 1 , 3 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ) if(pGmmLibContext->GetSkuTable().FtrLLCBypass) { GMM_DEFINE_MOCS( 16 , 0 , 0 , 1 , 1 , 1 , 0 , 0 , 0 , 0 , 0 , 1 , 0 , 0 ) GMM_DEFINE_MOCS( 17 , 0 , 0 , 3 , 1 , 1 , 0 , 0 , 0 , 0 , 0 , 1 , 0 , 0 ) } CurrentMaxMocsIndex = 23; // clang-format on #undef GMM_DEFINE_MOCS } gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/CachePolicy/GmmGen11CachePolicy.h000066400000000000000000001124571466655022700260410ustar00rootroot00000000000000/*============================================================================== Copyright(c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ============================================================================*/ #include "GmmCachePolicyConditionals.h" #define EDRAM (SKU(FtrEDram)) #define FBLLC (SKU(FtrFrameBufferLLC)) #define NS (SKU(FtrLLCBypass)) // Cache Policy Definition // AOM = Do not allocate on miss (0 = allocate on miss [normal cache behavior], 1 = don't allocate on miss) // LeCC_SCC = LLC/eLLC skip caching control (disabled if LeCC_SCC = 0) // L3_SCC = L3 skip caching control (disabled if L3_SCC = 0) // SCF = Snoop Control Field (SCF)- Only for SKL/BXT(as coherent/non-coherent) // SSO = Override MIDI self snoop settings (1 = never send to uncore, 3 = always send to uncore, 0 = [default] No override ) // CoS = Class of Service ( allowed values 1, 2, 3 for class IDs 1, 2, 3 respectively, default class 1 => driver overrides 0->1) // Faster PushWrite(Gen10+) used iff !WT, eLLC-only cacheable - Globally visible surface (eg display surface) should be marked WT //***************************************************************************************************************/ // USAGE TYPE , LLC , ELLC , L3 , WT , AGE , AOM , LeCC_SCC , L3_SCC, SCF, SSO, CoS) /****************************************************************************************************************/ // KMD Usages DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_BATCH_BUFFER , 0 , 0 , 0 , 0 , 0 , 0, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_COMP_FRAME_BUFFER , 0 , 0 , 0 , 0 , 0 , 0, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_CONTEXT_SWITCH_BUFFER , 0 , 0 , 0 , 0 , 0 , 0, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_CURSOR , 0 , 0 , 0 , 0 , 0 , 0, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_DISPLAY_STATIC_IMG_FOR_SMOOTH_ROTATION_BUFFER , 0 , 0 , 0 , 0 , 0 , 0, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_DUMMY_PAGE , 0 , 0 , 0 , 0 , 0 , 0, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_GDI_SURFACE , 1 , 1 , 1 , 0 , 3 , 0, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_GENERIC_KMD_RESOURCE , 0 , 0 , 0 , 0 , 0 , 0, 0, 0, 0, 0, 0); // GMM_RESOURCE_USAGE_GFX_RING is only used if WaEnableRingHostMapping is enabled. DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_GFX_RING , 0 , 0 , 0 , 0 , 0 , 0, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_GTT_TRANSFER_REGION , 0 , 0 , 0 , 0 , 0 , 0, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_HW_CONTEXT , 0 , 0 , 0 , 0 , 0 , 0, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_STATE_MANAGER_KERNEL_STATE , 0 , 0 , 0 , 0 , 0 , 0, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_KMD_STAGING_SURFACE , 1 , 1 , 1 , 0 , 3 , 0, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_MBM_BUFFER , 0 , 0 , 0 , 0 , 0 , 0, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_NNDI_BUFFER , 0 , 0 , 0 , 0 , 0 , 0, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_OVERLAY_MBM , 0 , 0 , 0 , 0 , 0 , 0, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_PRIMARY_SURFACE , 0 , 0 , 0 , 0 , 0 , 0, 0, 0, NS, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_SCREEN_PROTECTION_INTERMEDIATE_SURFACE , 0 , 0 , 0 , 0 , 0 , 0, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_SHADOW_SURFACE , 1 , 1 , 1 , 0 , 3 , 0, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_SM_SCRATCH_STATE , 0 , 0 , 0 , 0 , 0 , 0, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_STATUS_PAGE , 1 , 1 , 1 , 0 , 3 , 0, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_TIMER_PERF_QUEUE , 0 , 0 , 0 , 0 , 0 , 0, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_UNKNOWN , 0 , 0 , 0 , 0 , 0 , 0, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_UNMAP_PAGING_RESERVED_GTT_DMA_BUFFER , 0 , 0 , 0 , 0 , 0 , 0, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_VSC_BATCH_BUFFER , 0 , 0 , 0 , 0 , 0 , 0, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_WA_BATCH_BUFFER , 0 , 0 , 0 , 0 , 0 , 0, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_KMD_OCA_BUFFER , 0 , 0 , 0 , 0 , 0 , 0, 0, 0, 0, 0, 0); // // 3D Usages // DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_UMD_BATCH_BUFFER , 0 , 0 , 0 , 0 , 0 , 0, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_BINDING_TABLE_POOL , 1 , 1 , 1 , 0 , 3 , 0, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_CCS , 1 , 1 , 1 , 0 , 3 , 0, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_CONSTANT_BUFFER_POOL , 1 , 1 , 1 , 0 , 3 , 0, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_DEPTH_BUFFER , 1 , 1 , 1 , 0 , 3 , 0, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_DISPLAYABLE_RENDER_TARGET , 0 , EDRAM, 0 , EDRAM , 0 , 0, 0, 0, NS, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_GATHER_POOL , 1 , 1 , 1 , 0 , 3 , 0, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_HEAP_SURFACE_STATE , 1 , 1 , 1 , 0 , 3 , 0, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_HEAP_DYNAMIC_STATE , 1 , 1 , 1 , 0 , 3 , 0, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_HEAP_GENERAL_STATE , 1 , 1 , 1 , 0 , 3 , 0, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_HEAP_GENERAL_STATE_UC , 0 , 0 , 0 , 0 , 0 , 0, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_HEAP_STATELESS_DATA_PORT , 1 , 1 , 1 , 0 , 3 , 0, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_HEAP_STATELESS_DATA_PORT_L1_CACHED , 1 , 1 , 1 , 0 , 3 , 0, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_HEAP_INDIRECT_OBJECT , 1 , 1 , 1 , 0 , 3 , 0, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_HEAP_INSTRUCTION , 1 , 1 , 1 , 0 , 3 , 0, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_HIZ , 1 , 1 , 1 , 0 , 3 , 0, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_INDEX_BUFFER , 1 , 1 , 1 , 0 , 3 , 0, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_INDEX_BUFFER_L3_COHERENT_UC , 0 , 0 , 0 , 0 , 0 , 0, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_INDEX_BUFFER_L3_CACHED , 0 , 0 , 0 , 0 , 0 , 0, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_MCS , 1 , 1 , 1 , 0 , 3 , 0, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_PUSH_CONSTANT_BUFFER , 1 , 1 , 1 , 0 , 3 , 0, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_PULL_CONSTANT_BUFFER , 1 , 1 , 1 , 0 , 3 , 0, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_QUERY , 1 , 1 , 1 , 0 , 3 , 0, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_RENDER_TARGET , 1 , 1 , 1 , 0 , 3 , 0, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_SHADER_RESOURCE , 0 , 1 , 1 , 0 , 0 , 0, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_STAGING , 1 , 1 , 1 , 0 , 3 , 0, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_STENCIL_BUFFER , 1 , 1 , 1 , 0 , 3 , 0, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_STREAM_OUTPUT_BUFFER , 1 , 1 , 1 , 0 , 3 , 0, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_TILE_POOL , 1 , 1 , 1 , 0 , 3 , 0, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_SHADER_RESOURCE_LLC_BYPASS , 0 , 1 , 1 , 0 , 0 , 0, 0, 0, NS, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_MOCS_62 , 1 , 0 , 0 , 0 , 3 , 0, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_L3_EVICTION , 1 , 1 , 0 , 0 , 3 , 0, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_PROCEDURAL_TEXTURE , 0 , 0 , 0 , 0 , 0 , 0, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_UNCACHED , 0 , 0 , 0 , 0 , 0 , 0, 0, 0, 0, 0, 0); // Tiled Resource DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_TILED_DEPTH_BUFFER , 1 , 1 , 1 , 0 , 3 , 0, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_TILED_HIZ , 1 , 1 , 1 , 0 , 3 , 0, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_TILED_MCS , 1 , 1 , 1 , 0 , 3 , 0, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_TILED_CCS , 1 , 1 , 1 , 0 , 3 , 0, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_TILED_RENDER_TARGET , 1 , 1 , 1 , 0 , 3 , 0, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_TILED_RENDER_TARGET_AND_SHADER_RESOURCE , 1 , 1 , 1 , 0 , 3 , 0, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_TILED_SHADER_RESOURCE , 1 , 1 , 1 , 0 , 3 , 0, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_TILED_UAV , 1 , 1 , 1 , 0 , 3 , 0, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_UAV , 1 , 1 , 1 , 0 , 3 , 0, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_VERTEX_BUFFER , 1 , 1 , 1 , 0 , 3 , 0, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_VERTEX_BUFFER_L3_COHERENT_UC , 0 , 0 , 0 , 0 , 0 , 0, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_VERTEX_BUFFER_L3_CACHED , 0 , 0 , 0 , 0 , 0 , 0, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_OGL_WSTN_VERTEX_BUFFER , 1 , 1 , 1 , 0 , 3 , 0, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_POSH_VERTEX_BUFFER , 1 , 1 , 1 , 0 , 3 , 0, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_RENDER_TARGET_AND_SHADER_RESOURCE , 1 , 1 , 1 , 0 , 3 , 0, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_WDDM_HISTORY_BUFFER , 1 , 1 , 1 , 0 , 3 , 0, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_CONTEXT_SAVE_RESTORE , 1 , 1 , 1 , 0 , 3 , 0, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_PTBR_PAGE_POOL , 1 , 1 , 1 , 0 , 3 , 0, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_PTBR_BATCH_BUFFER , 0 , 0 , 1 , 0 , 0 , 0, 0, 0, 0, 0, 0); // // CM USAGES // DEFINE_CACHE_ELEMENT(CM_RESOURCE_USAGE_SurfaceState, 1 , 1 , 1 , 0 , 3 , 0, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(CM_RESOURCE_USAGE_NO_L3_SurfaceState, 1 , 1 , 0 , 0 , 3 , 0, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(CM_RESOURCE_USAGE_NO_LLC_ELLC_SurfaceState, 0 , 0 , 1 , 0 , 0 , 0, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(CM_RESOURCE_USAGE_NO_LLC_SurfaceState, 0 , 1 , 1 , 0 , 0, 0, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(CM_RESOURCE_USAGE_NO_ELLC_SurfaceState, 1 , 0 , 1 , 0 , 3, 0, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(CM_RESOURCE_USAGE_NO_LLC_L3_SurfaceState, 0 , 1 , 0 , 0 , 0, 0, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(CM_RESOURCE_USAGE_NO_ELLC_L3_SurfaceState, 1 , 0 , 0 , 0 , 3, 0, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(CM_RESOURCE_USAGE_NO_CACHE_SurfaceState, 0 , 0 , 0 , 0 , 0, 0, 0, 0, 0, 0, 0); // // MP USAGES // DEFINE_CACHE_ELEMENT(MP_RESOURCE_USAGE_BEGIN, 0 , 0 , 0 , 0 , 0, 0, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(MP_RESOURCE_USAGE_DEFAULT, 0 , 0 , 0 , 0 , 0, 0, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(MP_RESOURCE_USAGE_SurfaceState, 1 , EDRAM, 1 , 0 , 1, 0, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(MP_RESOURCE_USAGE_AGE3_SurfaceState, 1 , EDRAM, 1 , 0 , 3, 0, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(MP_RESOURCE_USAGE_END, 0 , 0 , 0 , 0 , 0, 0, 0, 0, 0, 0, 0); // MHW - SFC DEFINE_CACHE_ELEMENT(MHW_RESOURCE_USAGE_Sfc_CurrentOutputSurface, 0 , 0 , 0 , 0 , 0, 0, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(MHW_RESOURCE_USAGE_Sfc_AvsLineBufferSurface, 1 , EDRAM, 1 , 0 , 1, 0, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(MHW_RESOURCE_USAGE_Sfc_IefLineBufferSurface, 1 , EDRAM, 1 , 0 , 1, 0, 0, 0, 0, 0, 0); //Media GMM Resource USAGES DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_PRE_DEBLOCKING_CODEC , 0 , EDRAM , 0 , 0 , 0, 0, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_POST_DEBLOCKING_CODEC , 0 , EDRAM , 0 , 0 , 0, 0, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_ORIGINAL_UNCOMPRESSED_PICTURE_ENCODE , 0 , EDRAM , 0 , 0 , 0, 0, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_ORIGINAL_UNCOMPRESSED_PICTURE_DECODE , 0 , EDRAM , 0 , 0 , 0, 0, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_STREAMOUT_DATA_CODEC , 0 , 0 , 0 , 0 , 0, 0, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_INTRA_ROWSTORE_SCRATCH_BUFFER_CODEC , 1 , EDRAM , 0 , 0 , 3, 0, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_DEBLOCKINGFILTER_ROWSTORE_SCRATCH_BUFFER_CODEC , 1 , EDRAM , 0 , 0 , 3, 0, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_REFERENCE_PICTURE_CODEC , 1 , EDRAM , 0 , 0 , 3, 0, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_MACROBLOCK_STATUS_BUFFER_CODEC , 0 , EDRAM , 0 , 0 , 0, 0, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_MFX_INDIRECT_BITSTREAM_OBJECT_DECODE , 0 , EDRAM , 0 , 0 , 0, 0, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_MFX_INDIRECT_MV_OBJECT_CODEC , 0 , EDRAM , 0 , 0 , 0, 0, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_MFD_INDIRECT_IT_COEF_OBJECT_DECODE , 0 , EDRAM , 0 , 0 , 0, 0, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_MFC_INDIRECT_PAKBASE_OBJECT_CODEC , 1 , EDRAM , 0 , 0 , 3, 0, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_BSDMPC_ROWSTORE_SCRATCH_BUFFER_CODEC , 1 , EDRAM , 0 , 0 , 3, 0, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_MPR_ROWSTORE_SCRATCH_BUFFER_CODEC , 1 , EDRAM , 0 , 0 , 3, 0, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_BITPLANE_READ_CODEC , 0 , EDRAM , 0 , 0 , 0, 0, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_AACSBIT_VECTOR_CODEC , 0 , EDRAM , 0 , 0 , 0, 0, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_DIRECTMV_BUFFER_CODEC , 0 , EDRAM , 0 , 0 , 0, 0, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_SURFACE_CURR_ENCODE , 1 , EDRAM , 1 , 0 , 3, 0, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_SURFACE_REF_ENCODE , 1 , EDRAM , 1 , 0 , 3, 0, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_SURFACE_MV_DATA_ENCODE , 1 , EDRAM , 1 , 0 , 3, 0, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_SURFACE_HME_DOWNSAMPLED_ENCODE , 1 , EDRAM , 1 , 0 , 3, 0, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_SURFACE_HME_DOWNSAMPLED_ENCODE_DST , 1 , EDRAM , 1 , 0 , 3, 0, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_SURFACE_ME_DISTORTION_ENCODE , 1 , EDRAM , 1 , 0 , 3, 0, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_SURFACE_BRC_ME_DISTORTION_ENCODE , 1 , EDRAM , 1 , 0 , 3, 0, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_PAK_OBJECT_ENCODE , 1 , EDRAM , 1 , 0 , 3, 0, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_SURFACE_FLATNESS_CHECK_ENCODE , 1 , EDRAM , 1 , 0 , 3, 0, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_SURFACE_MBENC_CURBE_ENCODE , 1 , EDRAM , 1 , 0 , 3, 0, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_VDENC_ROW_STORE_BUFFER_CODEC , 1 , 0 , 0 , 0 , 3, 0 , 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_VDENC_STREAMIN_CODEC , 0 , EDRAM , 0 , 0 , 0, 0 , 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_HCP_MD_CODEC , 0 , EDRAM , 0 , 0 , 0, 0 , 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_HCP_SAO_CODEC , 0 , EDRAM , 0 , 0 , 0, 0 , 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_HCP_MV_CODEC , 0 , EDRAM , 0 , 0 , 0, 0 , 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_HCP_STATUS_ERROR_CODEC , 0 , 0 , 0 , 0 , 0, 0 , 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_HCP_LCU_ILDB_STREAMOUT_CODEC , 0 , 0 , 0 , 0 , 0, 0 , 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_VP9_PROBABILITY_BUFFER_CODEC , 1 , EDRAM , 0 , 0 , 3, 0 , 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_VP9_SEGMENT_ID_BUFFER_CODEC , 1 , EDRAM , 0 , 0 , 3, 0 , 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_VP9_HVD_ROWSTORE_BUFFER_CODEC , 1 , EDRAM , 0 , 0 , 3, 0 , 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_MACROBLOCK_ILDB_STREAM_OUT_BUFFER_CODEC , 0 , 0 , 0 , 0 , 0, 0 , 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_SSE_SRC_PIXEL_ROW_STORE_BUFFER_CODEC , 1 , EDRAM , 0 , 0 , 3, 0 , 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_SLICE_STATE_STREAM_OUT_BUFFER_CODEC , 0 , 0 , 0 , 0 , 0, 0 , 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_CABAC_SYNTAX_STREAM_OUT_BUFFER_CODEC , 0 , EDRAM , 0 , 0 , 0, 0 , 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_PRED_COL_STORE_BUFFER_CODEC , 1 , EDRAM , 0 , 0 , 3, 0 , 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_SURFACE_UNCACHED , 0 , 0 , 0 , 0 , 0, 0 , 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_SURFACE_ELLC_ONLY , 0 , EDRAM , 0 , 0 , 0, 0 , 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_SURFACE_ELLC_LLC_ONLY , 1 , EDRAM , 0 , 0 , 3, 0 , 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_SURFACE_ELLC_LLC_L3 , 1 , EDRAM , 1 , 0 , 3, 0 , 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_SURFACE_BRC_HISTORY_ENCODE , 1 , EDRAM , 1 , 0 , 3, 0, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_SURFACE_SOFTWARE_SCOREBOARD_ENCODE , 1 , EDRAM , 1 , 0 , 3, 0, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_SURFACE_ME_MV_DATA_ENCODE , 1 , EDRAM , 1 , 0 , 3, 0, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_SURFACE_MV_DISTORTION_ENCODE , 1 , EDRAM , 1 , 0 , 3, 0, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_SURFACE_4XME_DISTORTION_ENCODE , 1 , EDRAM , 1 , 0 , 3, 0, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_SURFACE_INTRA_DISTORTION_ENCODE , 1 , EDRAM , 1 , 0 , 3, 0, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_MB_STATS_ENCODE , 1 , EDRAM , 1 , 0 , 3, 0, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_SURFACE_PAK_STATS_ENCODE , 1 , EDRAM , 1 , 0 , 3, 0, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_SURFACE_PIC_STATE_READ_ENCODE , 1 , EDRAM , 1 , 0 , 3, 0, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_SURFACE_PIC_STATE_WRITE_ENCODE , 1 , EDRAM , 1 , 0 , 3, 0, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_SURFACE_COMBINED_ENC_ENCODE , 1 , EDRAM , 1 , 0 , 3, 0, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_SURFACE_BRC_CONSTANT_DATA_ENCODE , 1 , EDRAM , 1 , 0 , 3, 0, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_SURFACE_INTERMEDIATE_CU_RECORD_SURFACE_ENCODE , 1 , EDRAM , 0 , 0 , 3, 0, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_SURFACE_SCRATCH_ENCODE , 1 , EDRAM , 0 , 0 , 3, 0, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_SURFACE_LCU_LEVEL_DATA_ENCODE , 1 , EDRAM , 1 , 0 , 3, 0, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_SURFACE_ENC_HISTORY_INPUT_ENCODE , 1 , EDRAM , 1 , 0 , 3, 0, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_SURFACE_ENC_HISTORY_OUTPUT_ENCODE , 1 , EDRAM , 1 , 0 , 3, 0, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_SURFACE_DEBUG_ENCODE , 0 , 0 , 0 , 0 , 0, 0, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_SURFACE_ENC_CONSTANT_TABLE_ENCODE , 1 , EDRAM , 1 , 0 , 3, 0, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_SURFACE_ENC_CU_RECORD_ENCODE , 1 , EDRAM , 1 , 0 , 3, 0, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_SURFACE_ENC_MV_TEMPORAL_BUFFER_ENCODE , 1 , EDRAM , 1 , 0 , 3, 0, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_SURFACE_ENC_CU_PACKET_FOR_PAK_ENCODE , 1 , EDRAM , 1 , 0 , 3, 0, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_SURFACE_ENC_BCOMBINED1_ENCODE , 1 , EDRAM , 1 , 0 , 3, 0, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_SURFACE_ENC_BCOMBINED2_ENCODE , 1 , EDRAM , 1 , 0 , 3, 0, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_FRAME_STATS_STREAMOUT_DATA_CODEC , 1 , EDRAM , 0 , 0 , 3, 0, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_DEBLOCKINGFILTER_ROWSTORE_TILE_LINE_BUFFER_CODEC , 1 , EDRAM , 0 , 0 , 3, 0, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_DEBLOCKINGFILTER_ROWSTORE_TILE_COLUMN_BUFFER_CODEC , 1 , EDRAM , 0 , 0 , 3, 0, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_HCP_MD_TILE_LINE_CODEC , 1 , EDRAM , 0 , 0 , 3, 0, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_HCP_MD_TILE_COLUMN_CODEC , 1 , EDRAM , 0 , 0 , 3, 0, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_HCP_SAO_TILE_LINE_CODEC , 1 , EDRAM , 0 , 0 , 3, 0, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_HCP_SAO_TILE_COLUMN_CODEC , 1 , EDRAM , 0 , 0 , 3, 0, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_VP9_PROBABILITY_COUNTER_BUFFER_CODEC , 1 , EDRAM , 1 , 0 , 3, 0, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_HUC_VIRTUAL_ADDR_REGION_BUFFER_CODEC , 1 , EDRAM , 1 , 0 , 3, 0, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_SIZE_STREAMOUT_CODEC , 1 , EDRAM , 0 , 0 , 3, 0, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_COMPRESSED_HEADER_BUFFER_CODEC , 1 , EDRAM , 0 , 0 , 3, 0, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_PROBABILITY_DELTA_BUFFER_CODEC , 1 , EDRAM , 0 , 0 , 3, 0, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_SURFACE_MAD_ENCODE , 1 , EDRAM , 1 , 0 , 3, 0, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_SURFACE_PAK_IMAGESTATE_ENCODE , 1 , EDRAM , 1 , 0 , 3, 0, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_SURFACE_MBENC_BRC_ENCODE , 1 , EDRAM , 1 , 0 , 3, 0, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_SURFACE_MB_BRC_CONST_ENCODE , 1 , EDRAM , 1 , 0 , 3, 0, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_SURFACE_BRC_MB_QP_ENCODE , 1 , EDRAM , 1 , 0 , 3, 0, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_SURFACE_BRC_ROI_ENCODE , 1 , EDRAM , 1 , 0 , 3, 0, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_MBDISABLE_SKIPMAP_CODEC , 1 , EDRAM , 1 , 0 , 3, 0, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_SURFACE_SLICE_MAP_ENCODE , 1 , EDRAM , 1 , 0 , 3, 0, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_SURFACE_WP_DOWNSAMPLED_ENCODE , 1 , EDRAM , 1 , 0 , 3, 0, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_SURFACE_VDENC_IMAGESTATE_ENCODE , 1 , EDRAM , 1 , 0 , 3, 0, 0, 0, 0, 0, 0); /**********************************************************************************/ // // OCL Usages // DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_OCL_BUFFER , 1 , 1 , 1 , 0 , 3 , 0, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_OCL_BUFFER_CONST , 1 , 1 , 1 , 0 , 3 , 0, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_OCL_BUFFER_CSR_UC , 0 , 0 , 0 , 0 , 0 , 0, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_OCL_BUFFER_CACHELINE_MISALIGNED , 1 , 1 , 0 , 0 , 3 , 0, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_OCL_IMAGE , 1 , 1 , 1 , 0 , 3 , 0, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_OCL_INLINE_CONST , 1 , 1 , 1 , 0 , 3 , 0, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_OCL_INLINE_CONST_HDC , 1 , 1 , 1, 0 , 3 , 0, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_OCL_SCRATCH , 1 , 1 , 1 , 0 , 3 , 0, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_OCL_PRIVATE_MEM , 1 , 1 , 1 , 0 , 3 , 0, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_OCL_PRINTF_BUFFER , 1 , 1 , 1 , 0 , 3 , 0, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_OCL_STATE_HEAP_BUFFER , 1 , 1 , 1 , 0 , 3 , 0, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_OCL_SYSTEM_MEMORY_BUFFER , 1 , 1 , 1 , 0 , 3 , 0, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_OCL_SYSTEM_MEMORY_BUFFER_CACHELINE_MISALIGNED , 1 , 1 , 0 , 0 , 3 , 0, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_OCL_ISH_HEAP_BUFFER , 1 , 1 , 1 , 0 , 3 , 0, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_OCL_TAG_MEMORY_BUFFER , 1 , 1 , 1 , 0 , 3 , 0, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_OCL_TEXTURE_BUFFER , 1 , 1 , 1 , 0 , 3 , 0, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_OCL_SELF_SNOOP_BUFFER , 1 , 1 , 1 , 0 , 3 , 0, 0, 0, 0, 3, 0); /**********************************************************************************/ // Cross Adapter DEFINE_CACHE_ELEMENT( GMM_RESOURCE_USAGE_XADAPTER_SHARED_RESOURCE , 0 , 0 , 0 , 0 , 0 , 0, 0, 0, 0, 0, 0); /**********************************************************************************/ DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_CAMERA_CAPTURE , CAM$, 0 , 0 , 0 , CAM$ , 0, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_COMMAND_STREAMER , 0 , 0 , 0 , 0 , 0 , 0, 0, 0, 0, 0, 0); // Uncacheable copies DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_COPY_SOURCE , 0 , 0 , 0 , 0 , 0 , 0, 0, 0, 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_COPY_DEST , 0 , 0 , 0 , 0 , 0 , 0, 0, 0, 0, 0, 0); #include "GmmCachePolicyUndefineConditionals.h" gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/CachePolicy/GmmGen12CachePolicy.cpp000066400000000000000000000773261466655022700264020ustar00rootroot00000000000000/*============================================================================== Copyright(c) 2019 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ============================================================================*/ #include "Internal/Common/GmmLibInc.h" #include "External/Common/GmmCachePolicy.h" #include "External/Common/CachePolicy/GmmCachePolicyGen10.h" #include "External/Common/CachePolicy/GmmCachePolicyGen11.h" #include "External/Common/CachePolicy/GmmCachePolicyGen12.h" //============================================================================= // // Function: IsSpecialMOCSUsage // // Desc: This function returns special(hw-reserved) MocsIdx based on usage // // Parameters: usage -> Resource usage type // UpdateMOCS -> True if MOCS Table must be updated, ow false // // Return: int32_t // //----------------------------------------------------------------------------- int32_t GmmLib::GmmGen12CachePolicy::IsSpecialMOCSUsage(GMM_RESOURCE_USAGE_TYPE Usage, bool &UpdateMOCS) { int32_t MocsIdx = -1; UpdateMOCS = true; //Macros for L3-Eviction Type #define NA 0x0 #define RO 0x1 #define RW 0x2 #define SP 0x3 switch(Usage) { case GMM_RESOURCE_USAGE_CCS: __GMM_ASSERT(pCachePolicy[Usage].L3 == 0); //Architecturally, CCS isn't L3-cacheable. pCachePolicy[Usage].L3 = 0; MocsIdx = 60; break; case GMM_RESOURCE_USAGE_MOCS_62: __GMM_ASSERT(pCachePolicy[Usage].L3 == 0); //Architecturally, TR/Aux-TT node isn't L3-cacheable. pCachePolicy[Usage].L3 = 0; MocsIdx = 62; break; case GMM_RESOURCE_USAGE_L3_EVICTION: __GMM_ASSERT(pCachePolicy[Usage].L3 == 0 && pCachePolicy[Usage].L3Eviction == RW); //Reserved MOCS for L3-evictions pCachePolicy[Usage].L3 = 0; pCachePolicy[Usage].L3Eviction = RW; MocsIdx = 63; break; case GMM_RESOURCE_USAGE_L3_EVICTION_SPECIAL: case GMM_RESOURCE_USAGE_CCS_MEDIA_WRITABLE: __GMM_ASSERT(pCachePolicy[Usage].L3 && pCachePolicy[Usage].L3Eviction == SP); //Reserved MOCS for L3-evictions //Special-case for Displayable, and similar non-LLC accesses GMM_ASSERTDPF(pCachePolicy[Usage].LLC == 0, "MOCS#61's Special Eviction isn't for LLC caching"); pCachePolicy[Usage].L3 = 1; pCachePolicy[Usage].L3Eviction = SP; MocsIdx = 61; break; default: UpdateMOCS = false; break; } if(pCachePolicy[Usage].L3Eviction == RW) { GMM_CACHE_POLICY_ELEMENT L3Eviction; L3Eviction.Value = pCachePolicy[GMM_RESOURCE_USAGE_L3_EVICTION].Value; //For internal purpose, hw overrides MOCS#63 as L3-uncacheable, still using it for L3-evictions if(Usage != GMM_RESOURCE_USAGE_L3_EVICTION) { L3Eviction.L3 = 1; //Override L3, to verify MOCS#63 applicable or not } __GMM_ASSERT(pCachePolicy[Usage].Value == L3Eviction.Value); //Allow mis-match due to override registries //MocsIdx = 63; //Use non-#63 MOCS, #63 itself is L3-uncached } else if(pCachePolicy[Usage].L3Eviction == SP) { __GMM_ASSERT(pCachePolicy[Usage].Value == pCachePolicy[GMM_RESOURCE_USAGE_L3_EVICTION_SPECIAL].Value); //Allow mis-match due to override registries MocsIdx = 61; } return MocsIdx; } //============================================================================= // // Function: __GmmGen12InitCachePolicy // // Desc: This function initializes the cache policy // // Parameters: pCachePolicy -> Ptr to array to be populated with the // mapping of usages -> cache settings. // // Return: GMM_STATUS // //----------------------------------------------------------------------------- GMM_STATUS GmmLib::GmmGen12CachePolicy::InitCachePolicy() { __GMM_ASSERTPTR(pCachePolicy, GMM_ERROR); #define DEFINE_CACHE_ELEMENT(usage, llc, ellc, l3, wt, age, aom, lecc_scc, l3_scc, scf, sso, cos, hdcl1, l3evict) DEFINE_CP_ELEMENT(usage, llc, ellc, l3, wt, age, aom, lecc_scc, l3_scc, scf, sso, cos, hdcl1, l3evict, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) #include "GmmGen12CachePolicy.h" #define TC_LLC (1) #define TC_ELLC (0) #define TC_LLC_ELLC (2) #define LeCC_UNCACHEABLE (0x0) #define LeCC_WC_UNCACHEABLE (0x1) #define LeCC_WT_CACHEABLE (0x2) //Only used as MemPushWRite disqualifier if set along with eLLC-only -still holds on gen12+? #define LeCC_WB_CACHEABLE (0x3) #define L3_UNCACHEABLE (0x1) #define L3_WB_CACHEABLE (0x3) #define DISABLE_SKIP_CACHING_CONTROL (0x0) #define ENABLE_SKIP_CACHING_CONTROL (0x1) #define DISABLE_SELF_SNOOP_OVERRIDE (0x0) #define ENABLE_SELF_SNOOP_OVERRIDE (0x1) #define ENABLE_SELF_SNOOP_ALWAYS (0x3) #define CLASS_SERVICE_ZERO (0x0) { SetUpMOCSTable(); } { // Define index of cache element uint32_t Usage = 0; #if(_WIN32 && (_DEBUG || _RELEASE_INTERNAL)) void *pKmdGmmContext = NULL; OverrideCachePolicy(pKmdGmmContext); #endif // Process the cache policy and fill in the look up table for(; Usage < GMM_RESOURCE_USAGE_MAX; Usage++) { bool CachePolicyError = false; bool SpecialMOCS = false; int32_t CPTblIdx = -1; uint32_t j = 0; uint64_t PTEValue = 0; GMM_CACHE_POLICY_TBL_ELEMENT UsageEle = {0}; CPTblIdx = IsSpecialMOCSUsage((GMM_RESOURCE_USAGE_TYPE)Usage, SpecialMOCS); UsageEle.LeCC.Reserved = 0; // Reserved bits zeroe'd, this is so we // we can compare the unioned LeCC.DwordValue. UsageEle.LeCC.SelfSnoop = DISABLE_SELF_SNOOP_OVERRIDE; UsageEle.LeCC.CoS = CLASS_SERVICE_ZERO; UsageEle.LeCC.SCC = 0; UsageEle.LeCC.ESC = 0; if(pCachePolicy[Usage].SCF && pGmmLibContext->GetSkuTable().FtrLLCBypass) { UsageEle.LeCC.SCF = pCachePolicy[Usage].SCF; __GMM_ASSERT(pCachePolicy[Usage].LLC == 0); //LLC and ByPassLLC are mutually-exclusive } if(pCachePolicy[Usage].SSO & ENABLE_SELF_SNOOP_OVERRIDE) { UsageEle.LeCC.SelfSnoop = pCachePolicy[Usage].SSO & ENABLE_SELF_SNOOP_ALWAYS; } if(pCachePolicy[Usage].CoS) { UsageEle.LeCC.CoS = pCachePolicy[Usage].CoS; } if(pCachePolicy[Usage].HDCL1) { UsageEle.HDCL1 = 1; } if(pCachePolicy[Usage].LeCC_SCC) { UsageEle.LeCC.SCC = pCachePolicy[Usage].LeCC_SCC; UsageEle.LeCC.ESC = ENABLE_SKIP_CACHING_CONTROL; } UsageEle.LeCC.LRUM = pCachePolicy[Usage].AGE; // default to LLC target cache. UsageEle.LeCC.TargetCache = TC_LLC; UsageEle.LeCC.Cacheability = LeCC_WB_CACHEABLE; if(pCachePolicy[Usage].LLC) { UsageEle.LeCC.TargetCache = TC_LLC; __GMM_ASSERT(pCachePolicy[Usage].SCF == 0); //LLC and ByPassLLC are mutually-exclusive } else { UsageEle.LeCC.Cacheability = LeCC_WC_UNCACHEABLE; } UsageEle.L3.Reserved = 0; // Reserved bits zeroe'd, this is so we // we can compare the unioned L3.UshortValue. UsageEle.L3.ESC = DISABLE_SKIP_CACHING_CONTROL; UsageEle.L3.SCC = 0; UsageEle.L3.Cacheability = pCachePolicy[Usage].L3 ? L3_WB_CACHEABLE : L3_UNCACHEABLE; __GMM_ASSERT((pCachePolicy[Usage].L3 && pCachePolicy[Usage].L3Eviction != 0) || (pCachePolicy[Usage].L3 == 0 && (pCachePolicy[Usage].L3Eviction == 0 || Usage == GMM_RESOURCE_USAGE_L3_EVICTION))); if(pCachePolicy[Usage].L3_SCC) { UsageEle.L3.ESC = ENABLE_SKIP_CACHING_CONTROL; UsageEle.L3.SCC = (uint16_t)pCachePolicy[Usage].L3_SCC; } //Special-case MOCS handling for MOCS Table Index 60-63 if(CPTblIdx >= GMM_GEN12_MAX_NUMBER_MOCS_INDEXES) { GMM_CACHE_POLICY_TBL_ELEMENT *TblEle = &pGmmLibContext->GetCachePolicyTlbElement()[CPTblIdx]; if(SpecialMOCS && !(TblEle->LeCC.DwordValue == UsageEle.LeCC.DwordValue && TblEle->L3.UshortValue == UsageEle.L3.UshortValue && TblEle->HDCL1 == UsageEle.HDCL1)) { //Assert if being overwritten! __GMM_ASSERT(TblEle->LeCC.DwordValue == 0 && TblEle->L3.UshortValue == 0 && TblEle->HDCL1 == 0); #if(_WIN32 && (_DEBUG || _RELEASE_INTERNAL)) if(pCachePolicy[Usage].IsOverridenByRegkey) { TblEle->LeCC.DwordValue = UsageEle.LeCC.DwordValue; TblEle->L3.UshortValue = UsageEle.L3.UshortValue; TblEle->HDCL1 = UsageEle.HDCL1; } #endif } } //For HDC L1 caching, MOCS Table index 48-59 should be used else if(UsageEle.HDCL1) { for(j = GMM_GEN10_HDCL1_MOCS_INDEX_START; j <= CurrentMaxL1HdcMocsIndex; j++) { GMM_CACHE_POLICY_TBL_ELEMENT *TblEle = &pGmmLibContext->GetCachePolicyTlbElement()[j]; if(TblEle->LeCC.DwordValue == UsageEle.LeCC.DwordValue && TblEle->L3.UshortValue == UsageEle.L3.UshortValue && TblEle->HDCL1 == UsageEle.HDCL1) { CPTblIdx = j; break; } } } else { // Due to unstable system behavior on TGLLP, MOCS #0 index had to be programmed as UC in MOCS lookup table - pCachePolicyTlbElement // But still Index 0 is Reserved for Error by HW and should not be used. // Hence Gmmlib will opt out from the MOCS#0 usage and Lookup into MOCS table and MOCS index assigment must start from Index 1. for(j = 1; j <= CurrentMaxMocsIndex; j++) { GMM_CACHE_POLICY_TBL_ELEMENT *TblEle = &pGmmLibContext->GetCachePolicyTlbElement()[j]; if(TblEle->LeCC.DwordValue == UsageEle.LeCC.DwordValue && TblEle->L3.UshortValue == UsageEle.L3.UshortValue && TblEle->HDCL1 == UsageEle.HDCL1) { CPTblIdx = j; break; } } } // Didn't find the caching settings in one of the already programmed lookup table entries. // Need to add a new lookup table entry. if(CPTblIdx == -1) { #if(_WIN32 && (_DEBUG || _RELEASE_INTERNAL)) // If the Cache Policy setting is overriden through regkey, // don't raise an assert/log error. Raising an assert for debug/perf testing isn't really helpful if(pCachePolicy[Usage].IsOverridenByRegkey) { if(UsageEle.HDCL1 && CurrentMaxL1HdcMocsIndex < GMM_GEN12_MAX_NUMBER_MOCS_INDEXES - 1) { GMM_CACHE_POLICY_TBL_ELEMENT *TblEle = &(pGmmLibContext->GetCachePolicyTlbElement()[++CurrentMaxL1HdcMocsIndex]); CPTblIdx = CurrentMaxL1HdcMocsIndex; TblEle->LeCC.DwordValue = UsageEle.LeCC.DwordValue; TblEle->L3.UshortValue = UsageEle.L3.UshortValue; TblEle->HDCL1 = UsageEle.HDCL1; } else if(CurrentMaxMocsIndex < GMM_GEN10_HDCL1_MOCS_INDEX_START) { GMM_CACHE_POLICY_TBL_ELEMENT *TblEle = &(pGmmLibContext->GetCachePolicyTlbElement()[++CurrentMaxMocsIndex]); CPTblIdx = CurrentMaxMocsIndex; TblEle->LeCC.DwordValue = UsageEle.LeCC.DwordValue; TblEle->L3.UshortValue = UsageEle.L3.UshortValue; TblEle->HDCL1 = UsageEle.HDCL1; } else { // Too many unique caching combinations to program the // MOCS lookup table. CachePolicyError = true; GMM_ASSERTDPF( "Cache Policy Init Error: Invalid Cache Programming, too many unique caching combinations" "(we only support GMM_GEN_MAX_NUMBER_MOCS_INDEXES = %d)", GMM_MAX_NUMBER_MOCS_INDEXES - 1); // Set cache policy index to uncached. CPTblIdx = 3; } } else #endif { GMM_ASSERTDPF(false, "CRITICAL ERROR: Cache Policy Usage value specified by Client is not defined in Fixed MOCS Table!"); CachePolicyError = true; GMM_ASSERTDPF( "Cache Policy Init Error: Invalid Cache Programming, too many unique caching combinations" "(we only support GMM_GEN_MAX_NUMBER_MOCS_INDEXES = %d)", CurrentMaxMocsIndex); // Set cache policy index to uncached. CPTblIdx = 3; } } // PTE entries do not control caching on SKL+ (for legacy context) if(!GetUsagePTEValue(pCachePolicy[Usage], Usage, &PTEValue)) { CachePolicyError = true; } pCachePolicy[Usage].PTE.DwordValue = PTEValue & 0xFFFFFFFF; pCachePolicy[Usage].PTE.HighDwordValue = 0; pCachePolicy[Usage].MemoryObjectOverride.Gen12.Index = CPTblIdx; pCachePolicy[Usage].Override = ALWAYS_OVERRIDE; if(CachePolicyError) { GMM_ASSERTDPF("Cache Policy Init Error: Invalid Cache Programming - Element %d", Usage); } } } return GMM_SUCCESS; } ///////////////////////////////////////////////////////////////////////////////////// /// Return true if (MT2) is a better match for (WantedMT) /// than (MT1) /// /// @param[in] WantedMT: Wanted Memory Type /// @param[in] MT1: Memory Type for PATIdx1 /// @param[in] MT2: Memory Type for PATIdx2 /// /// @return Select the new PAT Index True/False ///////////////////////////////////////////////////////////////////////////////////// uint8_t GmmLib::GmmGen12CachePolicy::SelectNewPATIdx(GMM_GFX_MEMORY_TYPE WantedMT, GMM_GFX_MEMORY_TYPE MT1, GMM_GFX_MEMORY_TYPE MT2) { uint8_t SelectPAT2 = 0; // select on Memory Type if(MT1 != WantedMT) { if(MT2 == WantedMT || MT2 == GMM_GFX_UC_WITH_FENCE) { SelectPAT2 = 1; } goto EXIT; } EXIT: return SelectPAT2; } ///////////////////////////////////////////////////////////////////////////////////// /// Returns the PAT idx that best matches the cache policy for this usage. /// /// @param: CachePolicy: cache policy for a usage /// /// @return PAT Idx to use in the PTE ///////////////////////////////////////////////////////////////////////////////////// uint32_t GmmLib::GmmGen12CachePolicy::BestMatchingPATIdx(GMM_CACHE_POLICY_ELEMENT CachePolicy) { uint32_t i; uint32_t PATIdx = 0; GMM_GFX_MEMORY_TYPE WantedMemoryType = GMM_GFX_UC_WITH_FENCE, MemoryType; WA_TABLE * pWaTable = &const_cast(pGmmLibContext->GetWaTable()); WantedMemoryType = GetWantedMemoryType(CachePolicy); // Override wantedMemoryType so that PAT.MT is UC // Gen12 uses max function to resolve PAT-vs-MOCS MemType, So unless PTE.PAT says UC, MOCS won't be able to set UC! if(pWaTable->WaMemTypeIsMaxOfPatAndMocs) { WantedMemoryType = GMM_GFX_UC_WITH_FENCE; } for(i = 1; i < NumPATRegisters; i++) { GMM_PRIVATE_PAT PAT1 = GetPrivatePATEntry(PATIdx); GMM_PRIVATE_PAT PAT2 = GetPrivatePATEntry(i); if(SelectNewPATIdx(WantedMemoryType, (GMM_GFX_MEMORY_TYPE)PAT1.Gen12.MemoryType, (GMM_GFX_MEMORY_TYPE)PAT2.Gen12.MemoryType)) { PATIdx = i; } } MemoryType = (GMM_GFX_MEMORY_TYPE)GetPrivatePATEntry(PATIdx).Gen12.MemoryType; if(MemoryType != WantedMemoryType) { // Failed to find a matching PAT entry return GMM_PAT_ERROR; } return PATIdx; } ///////////////////////////////////////////////////////////////////////////////////// /// Initializes WA's needed for setting up the Private PATs /// WaNoMocsEllcOnly (reset) /// WaGttPat0, WaGttPat0GttWbOverOsIommuEllcOnly, WaGttPat0WB (use from base class) /// /// @return GMM_STATUS /// ///////////////////////////////////////////////////////////////////////////////////// GMM_STATUS GmmLib::GmmGen12CachePolicy::SetPATInitWA() { GMM_STATUS Status = GMM_SUCCESS; WA_TABLE * pWaTable = &const_cast(pGmmLibContext->GetWaTable()); #if(defined(__GMM_KMD__)) __GMM_ASSERT(pGmmLibContext->GetSkuTable().FtrMemTypeMocsDeferPAT == 0x0); //MOCS.TargetCache supports eLLC only, PAT.TC -> reserved bits. pWaTable->WaGttPat0WB = 0; //Override PAT #0 #else Status = GMM_ERROR; #endif return Status; } ///////////////////////////////////////////////////////////////////////////////////// /// Initializes the Gfx PAT tables for AdvCtx and Gfx MMIO/Private PAT /// PAT0 = WB_COHERENT or UC depending on WaGttPat0WB /// PAT1 = UC or WB_COHERENT depending on WaGttPat0WB /// PAT2 = WB_MOCSLESS /// PAT3 = WB /// PAT4 = WT /// PAT5 = WC /// PAT6 = WC /// PAT7 = WC /// HLD says to set to PAT0/1 to WC, but since we don't have a WC in GPU, /// WC option is same as UC. Hence setting PAT0 or PAT1 to UC. /// Unused PAT's (5,6,7) are set to WC. /// /// @return GMM_STATUS ///////////////////////////////////////////////////////////////////////////////////// GMM_STATUS GmmLib::GmmGen12CachePolicy::SetupPAT() { GMM_STATUS Status = GMM_SUCCESS; #if(defined(__GMM_KMD__)) uint32_t i = 0; GMM_GFX_MEMORY_TYPE GfxMemType = GMM_GFX_UC_WITH_FENCE; int32_t * pPrivatePATTableMemoryType = NULL; pPrivatePATTableMemoryType = pGmmLibContext->GetPrivatePATTableMemoryType(); __GMM_ASSERT(pGmmLibContext->GetSkuTable().FtrIA32eGfxPTEs); for(i = 0; i < GMM_NUM_GFX_PAT_TYPES; i++) { pPrivatePATTableMemoryType[i] = -1; } // Set values for GmmGlobalInfo PrivatePATTable for(i = 0; i < NumPATRegisters; i++) { GMM_PRIVATE_PAT PAT = {0}; switch(i) { case PAT0: if(pGmmLibContext->GetWaTable().WaGttPat0) { if(pGmmLibContext->GetWaTable().WaGttPat0WB) { GfxMemType = GMM_GFX_WB; pPrivatePATTableMemoryType[GMM_GFX_PAT_WB_COHERENT] = PAT0; } else { GfxMemType = GMM_GFX_UC_WITH_FENCE; pPrivatePATTableMemoryType[GMM_GFX_PAT_UC] = PAT0; } } else // if GTT is not tied to PAT0 then WaGttPat0WB is NA { GfxMemType = GMM_GFX_WB; pPrivatePATTableMemoryType[GMM_GFX_PAT_WB_COHERENT] = PAT0; } break; case PAT1: if(pGmmLibContext->GetWaTable().WaGttPat0 && !pGmmLibContext->GetWaTable().WaGttPat0WB) { GfxMemType = GMM_GFX_WB; pPrivatePATTableMemoryType[GMM_GFX_PAT_WB_COHERENT] = PAT1; } else { GfxMemType = GMM_GFX_UC_WITH_FENCE; pPrivatePATTableMemoryType[GMM_GFX_PAT_UC] = PAT1; } break; case PAT2: // This PAT idx shall be used for MOCS'Less resources like Page Tables // Page Tables have TC hardcoded to eLLC+LLC in Adv Ctxt. Hence making this to have same in Leg Ctxt. // For BDW-H, due to Perf issue, TC has to be eLLC only for Page Tables when eDRAM is present. GfxMemType = GMM_GFX_WB; pPrivatePATTableMemoryType[GMM_GFX_PAT_WB_MOCSLESS] = PAT2; break; case PAT3: GfxMemType = GMM_GFX_WB; pPrivatePATTableMemoryType[GMM_GFX_PAT_WB] = PAT3; break; case PAT4: GfxMemType = GMM_GFX_WT; pPrivatePATTableMemoryType[GMM_GFX_PAT_WT] = PAT4; break; case PAT5: case PAT6: case PAT7: GfxMemType = GMM_GFX_WC; pPrivatePATTableMemoryType[GMM_GFX_PAT_WC] = PAT5; break; default: __GMM_ASSERT(0); Status = GMM_ERROR; } PAT.Gen12.MemoryType = GfxMemType; SetPrivatePATEntry(i, PAT); } #else Status = GMM_ERROR; #endif return Status; } //============================================================================= // // Function: SetUpMOCSTable // // Desc: // // Parameters: // // Return: GMM_STATUS // //----------------------------------------------------------------------------- void GmmLib::GmmGen12CachePolicy::SetUpMOCSTable() { GMM_CACHE_POLICY_TBL_ELEMENT *pCachePolicyTlbElement = &(pGmmLibContext->GetCachePolicyTlbElement()[0]); #define GMM_DEFINE_MOCS(Index, L3_ESC, L3_SCC, L3_CC, LeCC_CC, LeCC_TC, LeCC_LRUM, LeCC_AOM, LeCC_ESC, LeCC_SCC, LeCC_PFM, LeCC_SCF, LeCC_CoS, LeCC_SelfSnoop, _HDCL1) \ { \ pCachePolicyTlbElement[Index].L3.ESC = L3_ESC; \ pCachePolicyTlbElement[Index].L3.SCC = L3_SCC; \ pCachePolicyTlbElement[Index].L3.Cacheability = L3_CC; \ pCachePolicyTlbElement[Index].LeCC.Cacheability = LeCC_CC; \ pCachePolicyTlbElement[Index].LeCC.TargetCache = LeCC_TC; \ pCachePolicyTlbElement[Index].LeCC.LRUM = LeCC_LRUM; \ pCachePolicyTlbElement[Index].LeCC.AOM = LeCC_AOM; \ pCachePolicyTlbElement[Index].LeCC.ESC = LeCC_ESC; \ pCachePolicyTlbElement[Index].LeCC.SCC = LeCC_SCC; \ pCachePolicyTlbElement[Index].LeCC.PFM = LeCC_PFM; \ pCachePolicyTlbElement[Index].LeCC.SCF = LeCC_SCF; \ pCachePolicyTlbElement[Index].LeCC.CoS = LeCC_CoS; \ pCachePolicyTlbElement[Index].LeCC.SelfSnoop = LeCC_SelfSnoop; \ pCachePolicyTlbElement[Index].HDCL1 = _HDCL1; \ } // clang-format off //Default MOCS Table for(int index = 0; index < GMM_MAX_NUMBER_MOCS_INDEXES; index++) { // Index ES SCC L3CC LeCC TC LRUM DAoM ERSC SCC PFM SCF CoS SSE HDCL1 GMM_DEFINE_MOCS( index , 0 , 0 , 3 , 3 , 1 , 3 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ) } // Fixed MOCS Table // Index ESC SCC L3CC LeCC TC LRUM DAoM ERSC SCC PFM SCF CoS SSE HDCL1 GMM_DEFINE_MOCS( 1 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ) GMM_DEFINE_MOCS( 2 , 0 , 0 , 3 , 3 , 1 , 3 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ) GMM_DEFINE_MOCS( 3 , 0 , 0 , 1 , 1 , 1 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ) GMM_DEFINE_MOCS( 4 , 0 , 0 , 3 , 1 , 1 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ) GMM_DEFINE_MOCS( 5 , 0 , 0 , 1 , 3 , 1 , 3 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ) GMM_DEFINE_MOCS( 6 , 0 , 0 , 1 , 3 , 1 , 1 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ) GMM_DEFINE_MOCS( 7 , 0 , 0 , 3 , 3 , 1 , 1 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ) GMM_DEFINE_MOCS( 8 , 0 , 0 , 1 , 3 , 1 , 2 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ) GMM_DEFINE_MOCS( 9 , 0 , 0 , 3 , 3 , 1 , 2 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ) GMM_DEFINE_MOCS( 10 , 0 , 0 , 1 , 3 , 1 , 3 , 1 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ) GMM_DEFINE_MOCS( 11 , 0 , 0 , 3 , 3 , 1 , 3 , 1 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ) GMM_DEFINE_MOCS( 12 , 0 , 0 , 1 , 3 , 1 , 1 , 1 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ) GMM_DEFINE_MOCS( 13 , 0 , 0 , 3 , 3 , 1 , 1 , 1 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ) GMM_DEFINE_MOCS( 14 , 0 , 0 , 1 , 3 , 1 , 2 , 1 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ) GMM_DEFINE_MOCS( 15 , 0 , 0 , 3 , 3 , 1 , 2 , 1 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ) GMM_DEFINE_MOCS( 16 , 0 , 0 , 1 , 1 , 1 , 0 , 0 , 0 , 0 , 0 , 1 , 0 , 0 , 0 ) GMM_DEFINE_MOCS( 17 , 0 , 0 , 3 , 1 , 1 , 0 , 0 , 0 , 0 , 0 , 1 , 0 , 0 , 0 ) GMM_DEFINE_MOCS( 18 , 0 , 0 , 3 , 3 , 1 , 3 , 0 , 0 , 0 , 0 , 0 , 0 , 3 , 0 ) GMM_DEFINE_MOCS( 19 , 0 , 0 , 3 , 3 , 1 , 3 , 0 , 0 , 7 , 0 , 0 , 0 , 0 , 0 ) GMM_DEFINE_MOCS( 20 , 0 , 0 , 3 , 3 , 1 , 3 , 0 , 0 , 3 , 0 , 0 , 0 , 0 , 0 ) GMM_DEFINE_MOCS( 21 , 0 , 0 , 3 , 3 , 1 , 3 , 0 , 0 , 1 , 0 , 0 , 0 , 0 , 0 ) GMM_DEFINE_MOCS( 22 , 0 , 0 , 3 , 3 , 1 , 3 , 0 , 1 , 3 , 0 , 0 , 0 , 0 , 0 ) GMM_DEFINE_MOCS( 23 , 0 , 0 , 3 , 3 , 1 , 3 , 0 , 1 , 7 , 0 , 0 , 0 , 0 , 0 ) GMM_DEFINE_MOCS( 48 , 0 , 0 , 3 , 3 , 1 , 3 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 1 ) GMM_DEFINE_MOCS( 49 , 0 , 0 , 3 , 1 , 1 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 1 ) GMM_DEFINE_MOCS( 50 , 0 , 0 , 1 , 3 , 1 , 3 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 1 ) GMM_DEFINE_MOCS( 51 , 0 , 0 , 1 , 1 , 1 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 1 ) GMM_DEFINE_MOCS( 60 , 0 , 0 , 1 , 3 , 1 , 3 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ) GMM_DEFINE_MOCS( 61 , 0 , 0 , 3 , 1 , 1 , 0 , 0 , 0 , 0 , 0 , 1 , 0 , 0 , 0 ) GMM_DEFINE_MOCS( 62 , 0 , 0 , 1 , 3 , 1 , 3 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ) GMM_DEFINE_MOCS( 63 , 0 , 0 , 1 , 3 , 1 , 3 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ) if(!pGmmLibContext->GetSkuTable().FtrLLCBypass || GFX_GET_CURRENT_PRODUCT(pGmmLibContext->GetPlatformInfo().Platform) == IGFX_ROCKETLAKE) { GMM_DEFINE_MOCS( 16 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ) GMM_DEFINE_MOCS( 17 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ) GMM_DEFINE_MOCS( 61 , 0 , 0 , 3 , 1 , 1 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ) } // clang-format on CurrentMaxMocsIndex = 23; CurrentMaxL1HdcMocsIndex = 51; CurrentMaxSpecialMocsIndex = 63; #undef GMM_DEFINE_MOCS } gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/CachePolicy/GmmGen12CachePolicy.h000066400000000000000000001244211466655022700260340ustar00rootroot00000000000000/*============================================================================== Copyright(c) 2019 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ============================================================================*/ #include "GmmCachePolicyConditionals.h" #define EDRAM (SKU(FtrEDram)) #define FBLLC (SKU(FtrFrameBufferLLC)) #define NS (SKU(FtrLLCBypass)) //Macros for L3-Eviction Type #define NA 0x0 #define RO 0x1 #define RW 0x2 #define SP 0x3 // Cache Policy Definition // AOM = Do not allocate on miss (0 = allocate on miss [normal cache behavior], 1 = don't allocate on miss) // LeCC_SCC = LLC/eLLC skip caching control (disabled if LeCC_SCC = 0) // L3_SCC = L3 skip caching control (disabled if L3_SCC = 0) // SCF = Snoop Control Field (SCF)- Only for SKL/BXT and Gen12+ (as coherent/non-coherent) // SSO = Override MIDI self snoop settings (1 = never send to uncore, 3 = always send to uncore, 0 = [default] No override ) // CoS = Class of Service ( allowed values 1, 2, 3 for class IDs 1, 2, 3 respectively, default class 0) // HDCL1 = HDC L1 cache control (1 = cached in HDC L1, 0 = not cached in HDC L1) // Faster PushWrite(Gen10+) used iff !WT, eLLC-only cacheable - Globally visible surface (eg display surface) should be marked WT // L3Evict = Type of L3-eviction (0= NA ie not L3 cacheable, 1= RO ie ReadOnly, 2 = RW ie Standard using MOCS#63), 3 = SP ie Special using MOCS#61 for non-LLC access) //***************************************************************************************************************/ // USAGE TYPE , LLC , ELLC , L3 , WT , AGE , AOM , LeCC_SCC , L3_SCC, SCF, SSO, CoS, HDCL1, L3Evict) /****************************************************************************************************************/ // KMD Usages DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_BATCH_BUFFER , 0 , 0 , 0 , 0 , 0 , 0, 0, 0, 0, 0, 0, 0, NA ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_COMP_FRAME_BUFFER , 0 , 0 , 0 , 0 , 0 , 0, 0, 0, 0, 0, 0, 0, NA ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_CONTEXT_SWITCH_BUFFER , 0 , 0 , 0 , 0 , 0 , 0, 0, 0, 0, 0, 0, 0, NA ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_CURSOR , 0 , 0 , 0 , 0 , 0 , 0, 0, 0, 0, 0, 0, 0, NA ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_DISPLAY_STATIC_IMG_FOR_SMOOTH_ROTATION_BUFFER , 0 , 0 , 0 , 0 , 0 , 0, 0, 0, 0, 0, 0, 0, NA ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_DUMMY_PAGE , 0 , 0 , 0 , 0 , 0 , 0, 0, 0, 0, 0, 0, 0, NA ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_GDI_SURFACE , 1 , 1 , 1 , 0 , 3 , 0, 0, 0, 0, 0, 0, 0, RO ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_GENERIC_KMD_RESOURCE , 0 , 0 , 0 , 0 , 0 , 0, 0, 0, 0, 0, 0, 0, NA ); // GMM_RESOURCE_USAGE_GFX_RING is only used if WaEnableRingHostMapping is enabled. DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_GFX_RING , 0 , 0 , 0 , 0 , 0 , 0, 0, 0, 0, 0, 0, 0, NA ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_GTT_TRANSFER_REGION , 0 , 0 , 0 , 0 , 0 , 0, 0, 0, 0, 0, 0, 0, NA ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_HW_CONTEXT , 0 , 0 , 0 , 0 , 0 , 0, 0, 0, 0, 0, 0, 0, NA ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_STATE_MANAGER_KERNEL_STATE , 0 , 0 , 0 , 0 , 0 , 0, 0, 0, 0, 0, 0, 0, NA ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_KMD_STAGING_SURFACE , 1 , 1 , 1 , 0 , 3 , 0, 0, 0, 0, 0, 0, 0, RO ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_MBM_BUFFER , 0 , 0 , 0 , 0 , 0 , 0, 0, 0, 0, 0, 0, 0, NA ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_NNDI_BUFFER , 0 , 0 , 0 , 0 , 0 , 0, 0, 0, 0, 0, 0, 0, NA ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_OVERLAY_MBM , 0 , 0 , 0 , 0 , 0 , 0, 0, 0, 0, 0, 0, 0, NA ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_PRIMARY_SURFACE , 0 , 0 , 0 , 0 , 0 , 0, 0, 0, NS, 0, 0, 0, NA ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_SCREEN_PROTECTION_INTERMEDIATE_SURFACE , 0 , 0 , 0 , 0 , 0 , 0, 0, 0, 0, 0, 0, 0, NA ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_SHADOW_SURFACE , 1 , 1 , 1 , 0 , 3 , 0, 0, 0, 0, 0, 0, 0, RO ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_SM_SCRATCH_STATE , 0 , 0 , 0 , 0 , 0 , 0, 0, 0, 0, 0, 0, 0, NA ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_STATUS_PAGE , 1 , 1 , 1 , 0 , 3 , 0, 0, 0, 0, 0, 0, 0, RO ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_TIMER_PERF_QUEUE , 0 , 0 , 0 , 0 , 0 , 0, 0, 0, 0, 0, 0, 0, NA ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_UNKNOWN , 0 , 0 , 0 , 0 , 0 , 0, 0, 0, 0, 0, 0, 0, NA ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_UNMAP_PAGING_RESERVED_GTT_DMA_BUFFER , 0 , 0 , 0 , 0 , 0 , 0, 0, 0, 0, 0, 0, 0, NA ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_VSC_BATCH_BUFFER , 0 , 0 , 0 , 0 , 0 , 0, 0, 0, 0, 0, 0, 0, NA ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_WA_BATCH_BUFFER , 0 , 0 , 0 , 0 , 0 , 0, 0, 0, 0, 0, 0, 0, NA ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_KMD_OCA_BUFFER , 0 , 0 , 0 , 0 , 0 , 0, 0, 0, 0, 0, 0, 0, NA ); // // 3D Usages // DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_UMD_BATCH_BUFFER , 0 , 0 , 0 , 0 , 0 , 0, 0, 0, 0, 0, 0, 0, NA ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_BINDING_TABLE_POOL , 1 , 1 , 1 , 0 , 3 , 0, 0, 0, 0, 0, 0, 0, RO ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_CCS , 1 , 0 , 0 , 0 , 3 , 0, 0, 0, 0, 0, 0, 0, NA ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_CONSTANT_BUFFER_POOL , 1 , 1 , 1 , 0 , 3 , 0, 0, 0, 0, 0, 0, 0, RO ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_DEPTH_BUFFER , 1 , 1 , 1 , 0 , 3 , 0, 0, 0, 0, 0, 0, 0, RO ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_DISPLAYABLE_RENDER_TARGET , 0 , EDRAM, 1 , EDRAM , 0 , 0, 0, 0, NS, 0, 0, 0, SP ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_GATHER_POOL , 1 , 1 , 1 , 0 , 3 , 0, 0, 0, 0, 0, 0, 0, RO ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_HEAP_SURFACE_STATE , 1 , 1 , 1 , 0 , 3 , 0, 0, 0, 0, 0, 0, 0, RO ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_HEAP_DYNAMIC_STATE , 1 , 1 , 1 , 0 , 3 , 0, 0, 0, 0, 0, 0, 0, RO ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_HEAP_GENERAL_STATE , 1 , 1 , 1 , 0 , 3 , 0, 0, 0, 0, 0, 0, 0, RO ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_HEAP_GENERAL_STATE_UC , 0 , 0 , 0 , 0 , 0 , 0, 0, 0, 0, 0, 0, 0, NA ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_HEAP_STATELESS_DATA_PORT , 1 , 1 , 1 , 0 , 3 , 0, 0, 0, 0, 0, 0, 0, RO ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_HEAP_STATELESS_DATA_PORT_L1_CACHED , 1 , 1 , 1 , 0 , 3 , 0, 0, 0, 0, 0, 0, 0, RO ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_HEAP_INDIRECT_OBJECT , 1 , 1 , 1 , 0 , 3 , 0, 0, 0, 0, 0, 0, 0, RO ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_HEAP_INSTRUCTION , 1 , 1 , 1 , 0 , 3 , 0, 0, 0, 0, 0, 0, 0, RO ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_HIZ , 1 , 1 , 1 , 0 , 3 , 0, 0, 0, 0, 0, 0, 0, RO ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_INDEX_BUFFER , 1 , 1 , 1 , 0 , 3 , 0, 0, 0, 0, 0, 0, 0, RO ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_INDEX_BUFFER_L3_COHERENT_UC , 1 , 1 , 0 , 0 , 3 , 0, 0, 0, 0, 0, 0, 0, NA ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_INDEX_BUFFER_L3_CACHED , 0 , 0 , 0 , 0 , 0 , 0, 0, 0, 0, 0, 0, 0, NA ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_MCS , 1 , 1 , 1 , 0 , 3 , 0, 0, 0, 0, 0, 0, 0, RO ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_PUSH_CONSTANT_BUFFER , 1 , 1 , 1 , 0 , 3 , 0, 0, 0, 0, 0, 0, 0, RO ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_PULL_CONSTANT_BUFFER , 1 , 1 , 1 , 0 , 3 , 0, 0, 0, 0, 0, 0, 1, RO ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_QUERY , 1 , 1 , 1 , 0 , 3 , 0, 0, 0, 0, 0, 0, 0, RO ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_RENDER_TARGET , 1 , 1 , 1 , 0 , 3 , 0, 0, 0, 0, 0, 0, 0, RO ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_SHADER_RESOURCE , 0 , 1 , 1 , 0 , 0 , 0, 0, 0, 0, 0, 0, 0, RO ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_STAGING , 1 , 1 , 1 , 0 , 3 , 0, 0, 0, 0, 0, 0, 0, RO ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_STENCIL_BUFFER , 1 , 1 , 1 , 0 , 3 , 0, 0, 0, 0, 0, 0, 0, RO ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_STREAM_OUTPUT_BUFFER , 1 , 1 , 1 , 0 , 3 , 0, 0, 0, 0, 0, 0, 0, RO ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_TILE_POOL , 1 , 1 , 1 , 0 , 3 , 0, 0, 0, 0, 0, 0, 0, RO ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_SHADER_RESOURCE_LLC_BYPASS , 0 , 1 , 1 , 0 , 0 , 0, 0, 0, NS, 0, 0, 0, RO ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_MOCS_62 , 1 , 0 , 0 , 0 , 3 , 0, 0, 0, 0, 0, 0, 0, NA ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_L3_EVICTION , 1 , 1 , 0 , 0 , 3 , 0, 0, 0, 0, 0, 0, 0, RW ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_L3_EVICTION_SPECIAL , 0 , EDRAM, 1 , EDRAM , 0 , 0, 0, 0, NS, 0, 0, 0, SP ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_PROCEDURAL_TEXTURE , 1 , 1 , 1 , 0 , 3 , 0, 0, 0, 0, 0, 0, 0, RO ); // Tiled Resource DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_TILED_DEPTH_BUFFER , 1 , 1 , 1 , 0 , 3 , 0, 0, 0, 0, 0, 0, 0, RO ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_TILED_HIZ , 1 , 1 , 1 , 0 , 3 , 0, 0, 0, 0, 0, 0, 0, RO ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_TILED_MCS , 1 , 1 , 1 , 0 , 3 , 0, 0, 0, 0, 0, 0, 0, RO ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_TILED_CCS , 1 , 1 , 1 , 0 , 3 , 0, 0, 0, 0, 0, 0, 0, RO ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_TILED_RENDER_TARGET , 1 , 1 , 1 , 0 , 3 , 0, 0, 0, 0, 0, 0, 0, RO ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_TILED_RENDER_TARGET_AND_SHADER_RESOURCE , 1 , 1 , 1 , 0 , 3 , 0, 0, 0, 0, 0, 0, 1, RO ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_TILED_SHADER_RESOURCE , 1 , 1 , 1 , 0 , 3 , 0, 0, 0, 0, 0, 0, 1, RO ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_TILED_UAV , 1 , 1 , 1 , 0 , 3 , 0, 0, 0, 0, 0, 0, 0, RO ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_UAV , 1 , 1 , 1 , 0 , 3 , 0, 0, 0, 0, 0, 0, 0, RO ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_VERTEX_BUFFER , 1 , 1 , 1 , 0 , 3 , 0, 0, 0, 0, 0, 0, 0, RO ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_VERTEX_BUFFER_L3_COHERENT_UC , 1 , 1 , 0 , 0 , 3 , 0, 0, 0, 0, 0, 0, 0, NA ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_VERTEX_BUFFER_L3_CACHED , 0 , 0 , 0 , 0 , 0 , 0, 0, 0, 0, 0, 0, 0, NA ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_OGL_WSTN_VERTEX_BUFFER , 1 , 1 , 1 , 0 , 3 , 0, 0, 0, 0, 0, 0, 0, RO ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_POSH_VERTEX_BUFFER , 1 , 1 , 1 , 0 , 3 , 0, 0, 0, 0, 0, 0, 0, RO ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_RENDER_TARGET_AND_SHADER_RESOURCE , 1 , 1 , 1 , 0 , 3 , 0, 0, 0, 0, 0, 0, 0, RO ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_WDDM_HISTORY_BUFFER , 1 , 1 , 1 , 0 , 3 , 0, 0, 0, 0, 0, 0, 0, RO ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_CONTEXT_SAVE_RESTORE , 1 , 1 , 1 , 0 , 3 , 0, 0, 0, 0, 0, 0, 0, RO ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_PTBR_PAGE_POOL , 1 , 1 , 1 , 0 , 3 , 0, 0, 0, 0, 0, 0, 0, RO ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_PTBR_BATCH_BUFFER , 0 , 0 , 1 , 0 , 0 , 0, 0, 0, 0, 0, 0, 0, RO ); // // CM USAGES // // USAGE TYPE , LLC , ELLC , L3 , WT , AGE , AOM , LeCC_SCC , L3_SCC, SCF, SSO, CoS, HDCL1, L3Evict ) DEFINE_CACHE_ELEMENT(CM_RESOURCE_USAGE_SurfaceState, 1 , 1 , 1 , 0 , 3 , 0, 0, 0, 0, 0, 0, 0, RO ); DEFINE_CACHE_ELEMENT(CM_RESOURCE_USAGE_StateHeap, 1 , 0 , 1 , 0 , 3 , 0, 0, 0, 0, 0, 0, 0, RO ); DEFINE_CACHE_ELEMENT(CM_RESOURCE_USAGE_L1_Enabled_SurfaceState, 1 , 1 , 1 , 0 , 3 , 0, 0, 0, 0, 0, 0, 1, RO ); DEFINE_CACHE_ELEMENT(CM_RESOURCE_USAGE_NO_L3_SurfaceState, 1 , 1 , 0 , 0 , 3 , 0, 0, 0, 0, 0, 0, 0, NA ); DEFINE_CACHE_ELEMENT(CM_RESOURCE_USAGE_NO_LLC_ELLC_SurfaceState, 0 , 0 , 1 , 0 , 0 , 0, 0, 0, 0, 0, 0, 0, RO ); DEFINE_CACHE_ELEMENT(CM_RESOURCE_USAGE_NO_LLC_SurfaceState, 0 , 1 , 1 , 0 , 0 , 0, 0, 0, 0, 0, 0, 0, RO ); DEFINE_CACHE_ELEMENT(CM_RESOURCE_USAGE_NO_ELLC_SurfaceState, 1 , 0 , 1 , 0 , 3 , 0, 0, 0, 0, 0, 0, 0, RO ); DEFINE_CACHE_ELEMENT(CM_RESOURCE_USAGE_NO_LLC_L3_SurfaceState, 0 , 1 , 0 , 0 , 0 , 0, 0, 0, 0, 0, 0, 0, NA ); DEFINE_CACHE_ELEMENT(CM_RESOURCE_USAGE_NO_ELLC_L3_SurfaceState, 1 , 0 , 0 , 0 , 3 , 0, 0, 0, 0, 0, 0, 0, NA ); DEFINE_CACHE_ELEMENT(CM_RESOURCE_USAGE_NO_CACHE_SurfaceState, 0 , 0 , 0 , 0 , 0 , 0, 0, 0, 0, 0, 0, 0, NA ); // // MP USAGES // DEFINE_CACHE_ELEMENT(MP_RESOURCE_USAGE_BEGIN, 0 , 0 , 0 , 0 , 0, 0, 0, 0, 0, 0, 0, 0, NA ); DEFINE_CACHE_ELEMENT(MP_RESOURCE_USAGE_DEFAULT, 0 , 0 , 0 , 0 , 0, 0, 0, 0, 0, 0, 0, 0, NA ); DEFINE_CACHE_ELEMENT(MP_RESOURCE_USAGE_SurfaceState, 1 , 1 , 1 , 0 , 3, 0, 0, 0, 0, 0, 0, 0, RO ); DEFINE_CACHE_ELEMENT(MP_RESOURCE_USAGE_END, 0 , 0 , 0 , 0 , 0, 0, 0, 0, 0, 0, 0, 0, NA ); // MHW - SFC DEFINE_CACHE_ELEMENT(MHW_RESOURCE_USAGE_Sfc_CurrentOutputSurface, 0 , 0 , 0 , 0 , 0, 0, 0, 0, 0, 0, 0, 0, NA ); DEFINE_CACHE_ELEMENT(MHW_RESOURCE_USAGE_Sfc_AvsLineBufferSurface, 1 , 1 , 1 , 0 , 1, 0, 0, 0, 0, 0, 0, 0, RO ); DEFINE_CACHE_ELEMENT(MHW_RESOURCE_USAGE_Sfc_IefLineBufferSurface, 1 , 1 , 1 , 0 , 1, 0, 0, 0, 0, 0, 0, 0, RO ); //Media GMM Resource USAGES DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_PRE_DEBLOCKING_CODEC , 0 , EDRAM , 0 , 0 , 0, 0, 0, 0, 0, 0, 0, 0, NA ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_POST_DEBLOCKING_CODEC , 0 , EDRAM , 0 , 0 , 0, 0, 0, 0, 0, 0, 0, 0, NA ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_ORIGINAL_UNCOMPRESSED_PICTURE_ENCODE , 0 , EDRAM , 0 , 0 , 0, 0, 0, 0, 0, 0, 0, 0, NA ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_ORIGINAL_UNCOMPRESSED_PICTURE_DECODE , 0 , EDRAM , 0 , 0 , 0, 0, 0, 0, 0, 0, 0, 0, NA ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_STREAMOUT_DATA_CODEC , 0 , 0 , 0 , 0 , 0, 0, 0, 0, 0, 0, 0, 0, NA ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_INTRA_ROWSTORE_SCRATCH_BUFFER_CODEC , 1 , EDRAM , 0 , 0 , 3, 0, 0, 0, 0, 0, 0, 0, NA ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_DEBLOCKINGFILTER_ROWSTORE_SCRATCH_BUFFER_CODEC , 1 , EDRAM , 0 , 0 , 3, 0, 0, 0, 0, 0, 0, 0, NA ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_REFERENCE_PICTURE_CODEC , 1 , EDRAM , 0 , 0 , 3, 0, 0, 0, 0, 0, 0, 0, NA ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_MACROBLOCK_STATUS_BUFFER_CODEC , 0 , EDRAM , 0 , 0 , 0, 0, 0, 0, 0, 0, 0, 0, NA ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_MFX_INDIRECT_BITSTREAM_OBJECT_DECODE , 0 , EDRAM , 0 , 0 , 0, 0, 0, 0, 0, 0, 0, 0, NA ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_MFX_INDIRECT_MV_OBJECT_CODEC , 0 , EDRAM , 0 , 0 , 0, 0, 0, 0, 0, 0, 0, 0, NA ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_MFD_INDIRECT_IT_COEF_OBJECT_DECODE , 0 , EDRAM , 0 , 0 , 0, 0, 0, 0, 0, 0, 0, 0, NA ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_MFC_INDIRECT_PAKBASE_OBJECT_CODEC , 1 , EDRAM , 0 , 0 , 3, 0, 0, 0, 0, 0, 0, 0, NA ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_BSDMPC_ROWSTORE_SCRATCH_BUFFER_CODEC , 1 , EDRAM , 0 , 0 , 3, 0, 0, 0, 0, 0, 0, 0, NA ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_MPR_ROWSTORE_SCRATCH_BUFFER_CODEC , 1 , EDRAM , 0 , 0 , 3, 0, 0, 0, 0, 0, 0, 0, NA ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_BITPLANE_READ_CODEC , 0 , EDRAM , 0 , 0 , 0, 0, 0, 0, 0, 0, 0, 0, NA ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_AACSBIT_VECTOR_CODEC , 0 , EDRAM , 0 , 0 , 0, 0, 0, 0, 0, 0, 0, 0, NA ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_DIRECTMV_BUFFER_CODEC , 0 , EDRAM , 0 , 0 , 0, 0, 0, 0, 0, 0, 0, 0, NA ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_SURFACE_CURR_ENCODE , 1 , EDRAM , 1 , 0 , 3, 0, 0, 0, 0, 0, 0, 0, RO ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_SURFACE_REF_ENCODE , 1 , EDRAM , 1 , 0 , 3, 0, 0, 0, 0, 0, 0, 0, RO ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_SURFACE_MV_DATA_ENCODE , 1 , EDRAM , 1 , 0 , 3, 0, 0, 0, 0, 0, 0, 0, RO ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_SURFACE_HME_DOWNSAMPLED_ENCODE , 1 , EDRAM , 1 , 0 , 3, 0, 0, 0, 0, 0, 0, 0, RO ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_SURFACE_HME_DOWNSAMPLED_ENCODE_DST , 1 , EDRAM , 1 , 0 , 3, 0, 0, 0, 0, 0, 0, 0, RO ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_SURFACE_ME_DISTORTION_ENCODE , 1 , EDRAM , 1 , 0 , 3, 0, 0, 0, 0, 0, 0, 0, RO ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_SURFACE_BRC_ME_DISTORTION_ENCODE , 1 , EDRAM , 1 , 0 , 3, 0, 0, 0, 0, 0, 0, 0, RO ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_PAK_OBJECT_ENCODE , 1 , EDRAM , 1 , 0 , 3, 0, 0, 0, 0, 0, 0, 0, RO ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_SURFACE_FLATNESS_CHECK_ENCODE , 1 , EDRAM , 1 , 0 , 3, 0, 0, 0, 0, 0, 0, 0, RO ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_SURFACE_MBENC_CURBE_ENCODE , 1 , EDRAM , 1 , 0 , 3, 0, 0, 0, 0, 0, 0, 0, RO ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_VDENC_ROW_STORE_BUFFER_CODEC , 1 , 0 , 0 , 0 , 3, 0 , 0, 0, 0, 0, 0, 0, NA ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_VDENC_STREAMIN_CODEC , 0 , EDRAM , 0 , 0 , 0, 0 , 0, 0, 0, 0, 0, 0, NA ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_HCP_MD_CODEC , 0 , EDRAM , 0 , 0 , 0, 0 , 0, 0, 0, 0, 0, 0, NA ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_HCP_SAO_CODEC , 0 , EDRAM , 0 , 0 , 0, 0 , 0, 0, 0, 0, 0, 0, NA ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_HCP_MV_CODEC , 0 , EDRAM , 0 , 0 , 0, 0 , 0, 0, 0, 0, 0, 0, NA ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_HCP_STATUS_ERROR_CODEC , 0 , 0 , 0 , 0 , 0, 0 , 0, 0, 0, 0, 0, 0, NA ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_HCP_LCU_ILDB_STREAMOUT_CODEC , 0 , 0 , 0 , 0 , 0, 0 , 0, 0, 0, 0, 0, 0, NA ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_VP9_PROBABILITY_BUFFER_CODEC , 1 , EDRAM , 0 , 0 , 3, 0 , 0, 0, 0, 0, 0, 0, NA ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_VP9_SEGMENT_ID_BUFFER_CODEC , 1 , EDRAM , 0 , 0 , 3, 0 , 0, 0, 0, 0, 0, 0, NA ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_VP9_HVD_ROWSTORE_BUFFER_CODEC , 1 , EDRAM , 0 , 0 , 3, 0 , 0, 0, 0, 0, 0, 0, NA ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_MACROBLOCK_ILDB_STREAM_OUT_BUFFER_CODEC , 0 , 0 , 0 , 0 , 0, 0 , 0, 0, 0, 0, 0, 0, NA ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_SSE_SRC_PIXEL_ROW_STORE_BUFFER_CODEC , 1 , EDRAM , 0 , 0 , 3, 0 , 0, 0, 0, 0, 0, 0, NA ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_SLICE_STATE_STREAM_OUT_BUFFER_CODEC , 0 , 0 , 0 , 0 , 0, 0 , 0, 0, 0, 0, 0, 0, NA ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_CABAC_SYNTAX_STREAM_OUT_BUFFER_CODEC , 0 , EDRAM , 0 , 0 , 0, 0 , 0, 0, 0, 0, 0, 0, NA ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_PRED_COL_STORE_BUFFER_CODEC , 1 , EDRAM , 0 , 0 , 3, 0 , 0, 0, 0, 0, 0, 0, NA ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_SURFACE_UNCACHED , 0 , 0 , 0 , 0 , 0, 0 , 0, 0, 0, 0, 0, 0, NA ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_SURFACE_ELLC_ONLY , 0 , EDRAM , 0 , 0 , 0, 0 , 0, 0, 0, 0, 0, 0, NA ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_SURFACE_ELLC_LLC_ONLY , 1 , EDRAM , 0 , 0 , 3, 0 , 0, 0, 0, 0, 0, 0, NA ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_SURFACE_ELLC_LLC_L3 , 1 , EDRAM , 1 , 0 , 3, 0 , 0, 0, 0, 0, 0, 0, RO ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_CCS_MEDIA_WRITABLE , 0 , EDRAM , 1 , EDRAM , 0, 0, 0, 0, NS, 0, 0, 0, SP ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_SURFACE_BRC_HISTORY_ENCODE , 1 , EDRAM , 1 , 0 , 3, 0, 0, 0, 0, 0, 0, 0, RO ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_SURFACE_SOFTWARE_SCOREBOARD_ENCODE , 1 , EDRAM , 1 , 0 , 3, 0, 0, 0, 0, 0, 0, 0, RO ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_SURFACE_ME_MV_DATA_ENCODE , 1 , EDRAM , 1 , 0 , 3, 0, 0, 0, 0, 0, 0, 0, RO ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_SURFACE_MV_DISTORTION_ENCODE , 1 , EDRAM , 1 , 0 , 3, 0, 0, 0, 0, 0, 0, 0, RO ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_SURFACE_4XME_DISTORTION_ENCODE , 1 , EDRAM , 1 , 0 , 3, 0, 0, 0, 0, 0, 0, 0, RO ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_SURFACE_INTRA_DISTORTION_ENCODE , 1 , EDRAM , 1 , 0 , 3, 0, 0, 0, 0, 0, 0, 0, RO ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_MB_STATS_ENCODE , 1 , EDRAM , 1 , 0 , 3, 0, 0, 0, 0, 0, 0, 0, RO ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_SURFACE_PAK_STATS_ENCODE , 1 , EDRAM , 1 , 0 , 3, 0, 0, 0, 0, 0, 0, 0, RO ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_SURFACE_PIC_STATE_READ_ENCODE , 1 , EDRAM , 1 , 0 , 3, 0, 0, 0, 0, 0, 0, 0, RO ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_SURFACE_PIC_STATE_WRITE_ENCODE , 1 , EDRAM , 1 , 0 , 3, 0, 0, 0, 0, 0, 0, 0, RO ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_SURFACE_COMBINED_ENC_ENCODE , 1 , EDRAM , 1 , 0 , 3, 0, 0, 0, 0, 0, 0, 0, RO ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_SURFACE_BRC_CONSTANT_DATA_ENCODE , 1 , EDRAM , 1 , 0 , 3, 0, 0, 0, 0, 0, 0, 0, RO ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_SURFACE_INTERMEDIATE_CU_RECORD_SURFACE_ENCODE , 1 , EDRAM , 0 , 0 , 3, 0, 0, 0, 0, 0, 0, 0, NA ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_SURFACE_SCRATCH_ENCODE , 1 , EDRAM , 0 , 0 , 3, 0, 0, 0, 0, 0, 0, 0, NA ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_SURFACE_LCU_LEVEL_DATA_ENCODE , 1 , EDRAM , 1 , 0 , 3, 0, 0, 0, 0, 0, 0, 0, RO ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_SURFACE_ENC_HISTORY_INPUT_ENCODE , 1 , EDRAM , 1 , 0 , 3, 0, 0, 0, 0, 0, 0, 0, RO ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_SURFACE_ENC_HISTORY_OUTPUT_ENCODE , 1 , EDRAM , 1 , 0 , 3, 0, 0, 0, 0, 0, 0, 0, RO ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_SURFACE_DEBUG_ENCODE , 0 , 0 , 0 , 0 , 0, 0, 0, 0, 0, 0, 0, 0, NA ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_SURFACE_ENC_CONSTANT_TABLE_ENCODE , 1 , EDRAM , 1 , 0 , 3, 0, 0, 0, 0, 0, 0, 0, RO ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_SURFACE_ENC_CU_RECORD_ENCODE , 1 , EDRAM , 1 , 0 , 3, 0, 0, 0, 0, 0, 0, 0, RO ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_SURFACE_ENC_MV_TEMPORAL_BUFFER_ENCODE , 1 , EDRAM , 1 , 0 , 3, 0, 0, 0, 0, 0, 0, 0, RO ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_SURFACE_ENC_CU_PACKET_FOR_PAK_ENCODE , 1 , EDRAM , 1 , 0 , 3, 0, 0, 0, 0, 0, 0, 0, RO ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_SURFACE_ENC_BCOMBINED1_ENCODE , 1 , EDRAM , 1 , 0 , 3, 0, 0, 0, 0, 0, 0, 0, RO ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_SURFACE_ENC_BCOMBINED2_ENCODE , 1 , EDRAM , 1 , 0 , 3, 0, 0, 0, 0, 0, 0, 0, RO ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_FRAME_STATS_STREAMOUT_DATA_CODEC , 1 , EDRAM , 0 , 0 , 3, 0, 0, 0, 0, 0, 0, 0, NA ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_DEBLOCKINGFILTER_ROWSTORE_TILE_LINE_BUFFER_CODEC , 1 , EDRAM , 0 , 0 , 3, 0, 0, 0, 0, 0, 0, 0, NA ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_DEBLOCKINGFILTER_ROWSTORE_TILE_COLUMN_BUFFER_CODEC , 1 , EDRAM , 0 , 0 , 3, 0, 0, 0, 0, 0, 0, 0, NA ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_HCP_MD_TILE_LINE_CODEC , 1 , EDRAM , 0 , 0 , 3, 0, 0, 0, 0, 0, 0, 0, NA ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_HCP_MD_TILE_COLUMN_CODEC , 1 , EDRAM , 0 , 0 , 3, 0, 0, 0, 0, 0, 0, 0, NA ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_HCP_SAO_TILE_LINE_CODEC , 1 , EDRAM , 0 , 0 , 3, 0, 0, 0, 0, 0, 0, 0, NA ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_HCP_SAO_TILE_COLUMN_CODEC , 1 , EDRAM , 0 , 0 , 3, 0, 0, 0, 0, 0, 0, 0, NA ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_VP9_PROBABILITY_COUNTER_BUFFER_CODEC , 1 , EDRAM , 1 , 0 , 3, 0, 0, 0, 0, 0, 0, 0, RO ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_HUC_VIRTUAL_ADDR_REGION_BUFFER_CODEC , 1 , EDRAM , 1 , 0 , 3, 0, 0, 0, 0, 0, 0, 0, RO ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_SIZE_STREAMOUT_CODEC , 1 , EDRAM , 0 , 0 , 3, 0, 0, 0, 0, 0, 0, 0, NA ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_COMPRESSED_HEADER_BUFFER_CODEC , 1 , EDRAM , 0 , 0 , 3, 0, 0, 0, 0, 0, 0, 0, NA ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_PROBABILITY_DELTA_BUFFER_CODEC , 1 , EDRAM , 0 , 0 , 3, 0, 0, 0, 0, 0, 0, 0, NA ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_TILE_RECORD_BUFFER_CODEC , 1 , EDRAM , 0 , 0 , 3, 0, 0, 0, 0, 0, 0, 0, NA ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_TILE_SIZE_STAS_BUFFER_CODEC , 1 , EDRAM , 0 , 0 , 3, 0, 0, 0, 0, 0, 0, 0, NA ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_SURFACE_MAD_ENCODE , 1 , EDRAM , 1 , 0 , 3, 0, 0, 0, 0, 0, 0, 0, RO ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_SURFACE_PAK_IMAGESTATE_ENCODE , 1 , EDRAM , 1 , 0 , 3, 0, 0, 0, 0, 0, 0, 0, RO ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_SURFACE_MBENC_BRC_ENCODE , 1 , EDRAM , 1 , 0 , 3, 0, 0, 0, 0, 0, 0, 0, RO ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_SURFACE_MB_BRC_CONST_ENCODE , 1 , EDRAM , 1 , 0 , 3, 0, 0, 0, 0, 0, 0, 0, RO ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_SURFACE_BRC_MB_QP_ENCODE , 1 , EDRAM , 1 , 0 , 3, 0, 0, 0, 0, 0, 0, 0, RO ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_SURFACE_BRC_ROI_ENCODE , 1 , EDRAM , 1 , 0 , 3, 0, 0, 0, 0, 0, 0, 0, RO ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_MBDISABLE_SKIPMAP_CODEC , 1 , EDRAM , 1 , 0 , 3, 0, 0, 0, 0, 0, 0, 0, RO ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_SURFACE_SLICE_MAP_ENCODE , 1 , EDRAM , 1 , 0 , 3, 0, 0, 0, 0, 0, 0, 0, RO ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_SURFACE_WP_DOWNSAMPLED_ENCODE , 1 , EDRAM , 1 , 0 , 3, 0, 0, 0, 0, 0, 0, 0, RO ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_SURFACE_VDENC_IMAGESTATE_ENCODE , 1 , EDRAM , 1 , 0 , 3, 0, 0, 0, 0, 0, 0, 0, RO ); /**********************************************************************************/ // // OCL Usages // DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_OCL_BUFFER , 1 , 1 , 1 , 0 , 3 , 0, 0, 0, 0, 0, 0, 0, RO ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_OCL_BUFFER_CONST , 1 , 1 , 1 , 0 , 3 , 0, 0, 0, 0, 0, 0, 1, RO ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_OCL_BUFFER_CSR_UC , 0 , 0 , 0 , 0 , 0 , 0, 0, 0, 0, 0, 0, 0, NA ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_OCL_BUFFER_CACHELINE_MISALIGNED , 1 , 1 , 0 , 0 , 3 , 0, 0, 0, 0, 0, 0, 0, NA ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_OCL_IMAGE , 1 , 1 , 1 , 0 , 3 , 0, 0, 0, 0, 0, 0, 0, RO ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_OCL_INLINE_CONST , 1 , 1 , 1 , 0 , 3 , 0, 0, 0, 0, 0, 0, 0, RO ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_OCL_INLINE_CONST_HDC , 1 , 1 , 1, 0 , 3 , 0, 0, 0, 0, 0, 0, 1, RO ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_OCL_SCRATCH , 1 , 1 , 1 , 0 , 3 , 0, 0, 0, 0, 0, 0, 0, RO ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_OCL_PRIVATE_MEM , 1 , 1 , 1 , 0 , 3 , 0, 0, 0, 0, 0, 0, 0, RO ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_OCL_PRINTF_BUFFER , 1 , 1 , 1 , 0 , 3 , 0, 0, 0, 0, 0, 0, 0, RO ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_OCL_STATE_HEAP_BUFFER , 1 , 1 , 1 , 0 , 3 , 0, 0, 0, 0, 0, 0, 0, RO ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_OCL_SYSTEM_MEMORY_BUFFER , 1 , 1 , 1 , 0 , 3 , 0, 0, 0, 0, 0, 0, 0, RO ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_OCL_SYSTEM_MEMORY_BUFFER_CACHELINE_MISALIGNED , 1 , 1 , 0 , 0 , 3 , 0, 0, 0, 0, 0, 0, 0, NA ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_OCL_ISH_HEAP_BUFFER , 1 , 1 , 1 , 0 , 3 , 0, 0, 0, 0, 0, 0, 0, RO ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_OCL_TAG_MEMORY_BUFFER , 1 , 1 , 1 , 0 , 3 , 0, 0, 0, 0, 0, 0, 0, RO ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_OCL_TEXTURE_BUFFER , 1 , 1 , 1 , 0 , 3 , 0, 0, 0, 0, 0, 0, 0, RO ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_OCL_SELF_SNOOP_BUFFER , 1 , 1 , 1 , 0 , 3 , 0, 0, 0, 0, 3, 0, 0, RO ); /**********************************************************************************/ // Cross Adapter DEFINE_CACHE_ELEMENT( GMM_RESOURCE_USAGE_XADAPTER_SHARED_RESOURCE , 0 , 0 , 0 , 0 , 0 , 0, 0, 0, 0, 0, 0, 0, NA ); /**********************************************************************************/ // BCS DEFINE_CACHE_ELEMENT( GMM_RESOURCE_USAGE_BLT_SOURCE , 0 , 0 , 0 , 0 , 0 , 0, 0, 0, 0, 0, 0, 0, NA ); DEFINE_CACHE_ELEMENT( GMM_RESOURCE_USAGE_BLT_DESTINATION , 0 , 0 , 0 , 0 , 0 , 0, 0, 0, 0, 0, 0, 0, NA ); /**********************************************************************************/ DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_CAMERA_CAPTURE , CAM$, 0 , 0 , 0 , CAM$ , 0, 0, 0, 0, 0, 0, 0, NA ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_KMD_NULL_CONTEXT_BB , 0 , 0 , 0 , 0 , 0 , 0, 0, 0, 0, 0, 0, 0, NA ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_COMMAND_STREAMER , 0 , 0 , 0 , 0 , 0 , 0, 0, 0, 0, 0, 0, 0, NA ); // Uncacheable copies DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_COPY_SOURCE , 0 , 0 , 0 , 0 , 0 , 0, 0, 0, 0, 0, 0, 0, NA); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_COPY_DEST , 0 , 0 , 0 , 0 , 0 , 0, 0, 0, 0, 0, 0, 0, NA); // Shader resource uncachable, needed for WA_18013889147 DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_SHADER_RESOURCE_L1_NOT_CACHED , 0 , 1 , 1 , 0 , 0 , 0, 0, 0, 0, 0, 0, 0, RO ); #include "GmmCachePolicyUndefineConditionals.h" gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/CachePolicy/GmmGen12dGPUCachePolicy.cpp000066400000000000000000000560771466655022700271220ustar00rootroot00000000000000/*============================================================================== Copyright(c) 2020 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ============================================================================*/ #include "Internal/Common/GmmLibInc.h" #include "External/Common/GmmCachePolicy.h" #include "External/Common/CachePolicy/GmmCachePolicyGen10.h" #include "External/Common/CachePolicy/GmmCachePolicyGen11.h" #include "External/Common/CachePolicy/GmmCachePolicyGen12.h" #include "External/Common/CachePolicy/GmmCachePolicyGen12dGPU.h" //============================================================================= // // Function: IsSpecialMOCSUsage // // Desc: This function returns special(hw-reserved) MocsIdx based on usage // // Parameters: usage -> Resource usage type // UpdateMOCS -> True if MOCS Table must be updated, ow false // // Return: int32_t // //----------------------------------------------------------------------------- int32_t GmmLib::GmmGen12dGPUCachePolicy::IsSpecialMOCSUsage(GMM_RESOURCE_USAGE_TYPE Usage, bool &UpdateMOCS) { int32_t MocsIdx = -1; UpdateMOCS = true; switch(Usage) { case GMM_RESOURCE_USAGE_CCS: __GMM_ASSERT(pCachePolicy[Usage].L3 == 0 && //Architecturally, CCS isn't L3-cacheable. pCachePolicy[Usage].UcLookup == 0); // On DG1/XE_HP_SDV/DG2, CCS Resource is never cached in L3, so LookUp is N/A MocsIdx = 60; break; case GMM_RESOURCE_USAGE_MOCS_62: __GMM_ASSERT(pCachePolicy[Usage].L3 == 0 && pCachePolicy[Usage].UcLookup == 0); //Architecturally, TR/Aux-TT node isn't L3-cacheable. MocsIdx = 62; break; case GMM_RESOURCE_USAGE_L3_EVICTION: MocsIdx = 63; break; case GMM_RESOURCE_USAGE_L3_EVICTION_SPECIAL: case GMM_RESOURCE_USAGE_CCS_MEDIA_WRITABLE: MocsIdx = 61; break; default: UpdateMOCS = false; break; } return MocsIdx; } //============================================================================= // // Function: __GmmGen12dGPUInitCachePolicy // // Desc: This function initializes the cache policy // // Parameters: pCachePolicy -> Ptr to array to be populated with the // mapping of usages -> cache settings. // // Return: GMM_STATUS // //----------------------------------------------------------------------------- GMM_STATUS GmmLib::GmmGen12dGPUCachePolicy::InitCachePolicy() { __GMM_ASSERTPTR(pCachePolicy, GMM_ERROR); #define DEFINE_CACHE_ELEMENT(usage, l3, l3_scc, hdcl1, go, uclookup, l1cc) DEFINE_CP_ELEMENT(usage, 0, 0, l3, 0, 0, 0, 0, l3_scc, 0, 0, 0, hdcl1, 0, 0, go, uclookup, l1cc, 0, 0, 0, 0, 0, 0) #include "GmmGen12dGPUCachePolicy.h" #define L3_UNCACHEABLE (0x1) #define L3_WB_CACHEABLE (0x3) #define L3_PAT_UNCACHEABLE (0x0) #define DISABLE_SKIP_CACHING_CONTROL (0x0) #define ENABLE_SKIP_CACHING_CONTROL (0x1) #define DISABLE_SELF_SNOOP_OVERRIDE (0x0) #define CLASS_SERVICE_ZERO (0x0) #define GMM_GEN12_MAX_NUMBER_MOCS_INDEXES (60) // On TGL last four (#60-#63) are reserved by h/w, few? are sw configurable though (#60) { SetUpMOCSTable(); } if(GFX_GET_CURRENT_PRODUCT(pGmmLibContext->GetPlatformInfo().Platform) == IGFX_PVC) { SetupPAT(); } { // Define index of cache element uint32_t Usage = 0; #if(_WIN32 && (_DEBUG || _RELEASE_INTERNAL)) void *pKmdGmmContext = NULL; OverrideCachePolicy(pKmdGmmContext); #endif // Process the cache policy and fill in the look up table for(; Usage < GMM_RESOURCE_USAGE_MAX; Usage++) { bool CachePolicyError = false; bool SpecialMOCS = false; int32_t CPTblIdx = -1, PATIdx = -1; uint32_t j = 0, i = 0; uint64_t PTEValue = 0; GMM_CACHE_POLICY_TBL_ELEMENT UsageEle = {0}; uint32_t StartMocsIdx = 0; GMM_PRIVATE_PAT UsagePATElement = {0}; switch(GFX_GET_CURRENT_PRODUCT(pGmmLibContext->GetPlatformInfo().Platform)) { case IGFX_DG1: case IGFX_XE_HP_SDV: case IGFX_PVC: StartMocsIdx = 1; // Index 0 is reserved for Error break; case IGFX_DG2: // DG2 provides 2 wires for MOCS Registers, gives 4(2^2) indexes to program. StartMocsIdx = 0; break; default: StartMocsIdx = 1; break; } // No Special MOCS handling for next platform if(GFX_GET_CURRENT_PRODUCT(pGmmLibContext->GetPlatformInfo().Platform) < IGFX_DG2) { CPTblIdx = IsSpecialMOCSUsage((GMM_RESOURCE_USAGE_TYPE)Usage, SpecialMOCS); } // Applicable upto Xe_HP only if(pCachePolicy[Usage].HDCL1 && (GFX_GET_CURRENT_PRODUCT(pGmmLibContext->GetPlatformInfo().Platform) <= IGFX_XE_HP_SDV)) { UsageEle.HDCL1 = 1; } UsageEle.L3.Reserved = 0; // Reserved bits zeroe'd, this is so we // we can compare the unioned L3.UshortValue. UsageEle.L3.ESC = DISABLE_SKIP_CACHING_CONTROL; UsageEle.L3.SCC = 0; UsageEle.L3.Cacheability = pCachePolicy[Usage].L3 ? L3_WB_CACHEABLE : L3_UNCACHEABLE; if(pCachePolicy[Usage].L3_SCC) { UsageEle.L3.ESC = ENABLE_SKIP_CACHING_CONTROL; UsageEle.L3.SCC = (uint16_t)pCachePolicy[Usage].L3_SCC; } if(GFX_GET_CURRENT_PRODUCT(pGmmLibContext->GetPlatformInfo().Platform) == IGFX_PVC) { pCachePolicy[Usage].GlbGo = 0; pCachePolicy[Usage].UcLookup = 0; } // Go/Lookup // N/A for SpecialMOCS // N/A for DG1, RKL, PVC // Applicable for IGFX_XE_HP_SDV and DG2 only if(!SpecialMOCS && (FROMPRODUCT(XE_HP_SDV)) && (GFX_GET_CURRENT_PRODUCT(pGmmLibContext->GetPlatformInfo().Platform) != IGFX_PVC)) { if(pCachePolicy[Usage].L3 == 0) { UsageEle.L3.GlobalGo = pCachePolicy[Usage].GlbGo; } UsageEle.L3.UCLookup = pCachePolicy[Usage].UcLookup; __GMM_ASSERT((pCachePolicy[Usage].UcLookup) || (pCachePolicy[Usage].L3 == 0 && pCachePolicy[Usage].UcLookup == 0)); } //Special-case MOCS handling for MOCS Table Index 60-63 if(CPTblIdx >= GMM_GEN12_MAX_NUMBER_MOCS_INDEXES) { GMM_CACHE_POLICY_TBL_ELEMENT *TblEle = &pGmmLibContext->GetCachePolicyTlbElement()[CPTblIdx]; if(SpecialMOCS && !(TblEle->L3.UshortValue == UsageEle.L3.UshortValue)) { //Assert if being overwritten! __GMM_ASSERT(TblEle->L3.UshortValue == 0); } } //For HDC L1 caching, MOCS Table index 48-59 should be used else if(UsageEle.HDCL1) { for(j = GMM_GEN10_HDCL1_MOCS_INDEX_START; j <= CurrentMaxL1HdcMocsIndex; j++) { GMM_CACHE_POLICY_TBL_ELEMENT *TblEle = &pGmmLibContext->GetCachePolicyTlbElement()[j]; if(TblEle->L3.UshortValue == UsageEle.L3.UshortValue && TblEle->HDCL1 == UsageEle.HDCL1) { CPTblIdx = j; break; } } } else { for(j = StartMocsIdx; j <= CurrentMaxMocsIndex; j++) { if(pCachePolicy[Usage].L3 == 0 && pCachePolicy[Usage].GlbGo == 0 && pCachePolicy[Usage].UcLookup == 0) { CPTblIdx = StartMocsIdx; break; } else { GMM_CACHE_POLICY_TBL_ELEMENT *TblEle = &pGmmLibContext->GetCachePolicyTlbElement()[j]; if(TblEle->L3.UshortValue == UsageEle.L3.UshortValue) { CPTblIdx = j; break; } } } } // Didn't find the caching settings in one of the already programmed lookup table entries. // Need to add a new lookup table entry. if(CPTblIdx == -1) { { GMM_ASSERTDPF(false, "CRITICAL ERROR: Cache Policy Usage value specified by Client is not defined in Fixed MOCS Table!"); CachePolicyError = true; GMM_ASSERTDPF( "Cache Policy Init Error: Invalid Cache Programming, too many unique caching combinations" "(we only support GMM_GEN_MAX_NUMBER_MOCS_INDEXES = %d)", CurrentMaxMocsIndex); // Set cache policy index to uncached. CPTblIdx = StartMocsIdx; } } // PTE entries do not control caching on SKL+ (for legacy context) if(!GetUsagePTEValue(pCachePolicy[Usage], Usage, &PTEValue)) { CachePolicyError = true; } pCachePolicy[Usage].PTE.DwordValue = PTEValue & 0xFFFFFFFF; pCachePolicy[Usage].PTE.HighDwordValue = 0; pCachePolicy[Usage].MemoryObjectOverride.Gen12.Index = CPTblIdx; pCachePolicy[Usage].Override = ALWAYS_OVERRIDE; if(CachePolicyError) { GMM_ASSERTDPF("Cache Policy Init Error: Invalid Cache Programming - Element %d", Usage); } if(GFX_GET_CURRENT_PRODUCT(pGmmLibContext->GetPlatformInfo().Platform) == IGFX_PVC) { // PAT data { UsagePATElement.Xe_HPC.Reserved = 0; UsagePATElement.Xe_HPC.MemoryType = pCachePolicy[Usage].L3 ? L3_WB_CACHEABLE : L3_PAT_UNCACHEABLE; // try to find a match in static PAT table for(i = 0; i <= CurrentMaxPATIndex; i++) { GMM_PRIVATE_PAT PAT = GetPrivatePATEntry(i); if(UsagePATElement.Xe_HPC.MemoryType == PAT.Xe_HPC.MemoryType) { PATIdx = i; break; } } if(PATIdx == -1) { GMM_ASSERTDPF( "Cache Policy Init Error: Invalid Cache Programming, too many unique caching combinations" "(we only support NumPATRegisters = %d)", CurrentMaxPATIndex); CachePolicyError = true; // add rterror here PATIdx = PAT0; // default to uncached PAT index 0: GMM_CP_NON_COHERENT_UC // Log Error using regkey to indicate the above error } } pCachePolicy[Usage].PATIndex = PATIdx; pCachePolicy[Usage].PTE.DwordValue = GMM_GET_PTE_BITS_FROM_PAT_IDX(PATIdx) & 0xFFFFFFFF; pCachePolicy[Usage].PTE.HighDwordValue = GMM_GET_PTE_BITS_FROM_PAT_IDX(PATIdx) >> 32; } } } return GMM_SUCCESS; } #pragma optimize("", on) //============================================================================= // // Function: SetUpMOCSTable // // Desc: For Gen12dGPU, Define new Fixed MOCS table // // Parameters: // // Return: GMM_STATUS // //----------------------------------------------------------------------------- void GmmLib::GmmGen12dGPUCachePolicy::SetUpMOCSTable() { GMM_CACHE_POLICY_TBL_ELEMENT *pCachePolicyTlbElement = &(pGmmLibContext->GetCachePolicyTlbElement()[0]); CurrentMaxL1HdcMocsIndex = 0; CurrentMaxSpecialMocsIndex = 0; #define GMM_DEFINE_MOCS(Index, L3_ESC, L3_SCC, L3_CC, L3_Go, L3_LookUp, _HDCL1) \ { \ pCachePolicyTlbElement[Index].L3.ESC = L3_ESC; \ pCachePolicyTlbElement[Index].L3.SCC = L3_SCC; \ pCachePolicyTlbElement[Index].L3.Cacheability = L3_CC; \ pCachePolicyTlbElement[Index].L3.GlobalGo = L3_Go; \ pCachePolicyTlbElement[Index].L3.UCLookup = L3_LookUp; \ pCachePolicyTlbElement[Index].LeCC.Cacheability = 1; \ pCachePolicyTlbElement[Index].LeCC.TargetCache = 0; \ pCachePolicyTlbElement[Index].LeCC.LRUM = 0; \ pCachePolicyTlbElement[Index].LeCC.AOM = 0; \ pCachePolicyTlbElement[Index].LeCC.ESC = 0; \ pCachePolicyTlbElement[Index].LeCC.SCC = 0; \ pCachePolicyTlbElement[Index].LeCC.PFM = 0; \ pCachePolicyTlbElement[Index].LeCC.SCF = 0; \ pCachePolicyTlbElement[Index].LeCC.CoS = CLASS_SERVICE_ZERO; \ pCachePolicyTlbElement[Index].LeCC.SelfSnoop = DISABLE_SELF_SNOOP_OVERRIDE; \ pCachePolicyTlbElement[Index].HDCL1 = _HDCL1; \ } // clang-format off if (GFX_GET_CURRENT_PRODUCT(pGmmLibContext->GetPlatformInfo().Platform) == IGFX_DG1) { //Default MOCS Table for(int index = 0; index < GMM_MAX_NUMBER_MOCS_INDEXES; index++) { // Index ESC SCC L3CC Go LookUp HDCL1 GMM_DEFINE_MOCS( index , 0 , 0 , 3 , 0 , 0 , 0 ) } // Fixed MOCS Table // Index ESC SCC L3CC Go LookUp HDCL1 GMM_DEFINE_MOCS( 0 , 0 , 0 , 1 , 0 , 0 , 0 ) GMM_DEFINE_MOCS( 1 , 0 , 0 , 1 , 0 , 0 , 0 ) GMM_DEFINE_MOCS( 2 , 0 , 0 , 0 , 0 , 0 , 0 ) GMM_DEFINE_MOCS( 3 , 0 , 0 , 0 , 0 , 0 , 0 ) GMM_DEFINE_MOCS( 4 , 0 , 0 , 0 , 0 , 0 , 0 ) GMM_DEFINE_MOCS( 5 , 0 , 0 , 3 , 0 , 0 , 0 ) GMM_DEFINE_MOCS( 6 , 1 , 1 , 3 , 0 , 0 , 0 ) GMM_DEFINE_MOCS( 7 , 1 , 3 , 3 , 0 , 0 , 0 ) GMM_DEFINE_MOCS( 8 , 1 , 7 , 3 , 0 , 0 , 0 ) GMM_DEFINE_MOCS( 48 , 0 , 0 , 3 , 0 , 0 , 1 ) GMM_DEFINE_MOCS( 49 , 0 , 0 , 1 , 0 , 0 , 1 ) GMM_DEFINE_MOCS( 60 , 0 , 0 , 1 , 0 , 0 , 0 ) GMM_DEFINE_MOCS( 61 , 0 , 0 , 1 , 0 , 0 , 0 ) GMM_DEFINE_MOCS( 62 , 0 , 0 , 1 , 0 , 0 , 0 ) GMM_DEFINE_MOCS( 63 , 0 , 0 , 1 , 0 , 0 , 0 ) CurrentMaxMocsIndex = 8; CurrentMaxL1HdcMocsIndex = 49; CurrentMaxSpecialMocsIndex = 63; } else if (GFX_GET_CURRENT_PRODUCT(pGmmLibContext->GetPlatformInfo().Platform) == IGFX_XE_HP_SDV) { //Default MOCS Table for(int index = 0; index < GMM_MAX_NUMBER_MOCS_INDEXES; index++) { // Index ESC SCC L3CC Go LookUp HDCL1 GMM_DEFINE_MOCS( index , 0 , 0 , 3 , 0 , 1 , 0 ) } // Fixed MOCS Table // Index ESC SCC L3CC Go LookUp HDCL1 GMM_DEFINE_MOCS( 1 , 0 , 0 , 1 , 0 , 1 , 0 ) GMM_DEFINE_MOCS( 2 , 0 , 0 , 1 , 1 , 1 , 0 ) GMM_DEFINE_MOCS( 3 , 0 , 0 , 1 , 1 , 0 , 0 ) GMM_DEFINE_MOCS( 4 , 0 , 0 , 1 , 0 , 0 , 0 ) GMM_DEFINE_MOCS( 5 , 0 , 0 , 3 , 0 , 1 , 0 ) GMM_DEFINE_MOCS( 48 , 0 , 0 , 3 , 0 , 1 , 1 ) GMM_DEFINE_MOCS( 49 , 0 , 0 , 1 , 0 , 1 , 1 ) GMM_DEFINE_MOCS( 60 , 0 , 0 , 1 , 0 , 0 , 0 ) GMM_DEFINE_MOCS( 61 , 0 , 0 , 1 , 0 , 0 , 0 ) GMM_DEFINE_MOCS( 62 , 0 , 0 , 1 , 0 , 0 , 0 ) GMM_DEFINE_MOCS( 63 , 0 , 0 , 1 , 0 , 0 , 0 ) CurrentMaxMocsIndex = 5; CurrentMaxL1HdcMocsIndex = 49; CurrentMaxSpecialMocsIndex = 63; } else if ((GFX_GET_CURRENT_PRODUCT(pGmmLibContext->GetPlatformInfo().Platform) == IGFX_DG2)) { //Default MOCS Table for(int index = 0; index < GMM_MAX_NUMBER_MOCS_INDEXES; index++) { // Index ESC SCC L3CC Go LookUp HDCL1 GMM_DEFINE_MOCS( index , 0 , 0 , 3 , 0 , 1 , 0 ) } // Fixed MOCS Table // Index ESC SCC L3CC Go LookUp HDCL1 GMM_DEFINE_MOCS( 0 , 0 , 0 , 1 , 0 , 1 , 0 ) GMM_DEFINE_MOCS( 1 , 0 , 0 , 1 , 1 , 1 , 0 ) GMM_DEFINE_MOCS( 2 , 0 , 0 , 1 , 1 , 0 , 0 ) GMM_DEFINE_MOCS( 3 , 0 , 0 , 3 , 0 , 1 , 0 ) CurrentMaxMocsIndex = 3; } else if (GFX_GET_CURRENT_PRODUCT(pGmmLibContext->GetPlatformInfo().Platform) == IGFX_PVC) { //Default MOCS Table for(int index = 0; index < GMM_MAX_NUMBER_MOCS_INDEXES; index++) { // Index ESC SCC L3CC Go LookUp HDCL1 GMM_DEFINE_MOCS( index , 0 , 0 , 3 , 0 , 0 , 0 ) } // Fixed MOCS Table // Index ESC SCC L3CC Go LookUp HDCL1 GMM_DEFINE_MOCS( 1 , 0 , 0 , 1 , 0 , 0 , 0 ) GMM_DEFINE_MOCS( 2 , 0 , 0 , 3 , 0 , 0 , 0 ) CurrentMaxMocsIndex = 2; } // clang-format on #undef GMM_DEFINE_MOCS } //============================================================================= // // Function: SetupPAT // // Desc: // // Parameters: // // Return: GMM_STATUS // //----------------------------------------------------------------------------- GMM_STATUS GmmLib::GmmGen12dGPUCachePolicy::SetupPAT() { GMM_PRIVATE_PAT *pPATTlbElement = &(pGmmLibContext->GetPrivatePATTable()[0]); #define L3_UC (0x0) #define L3_WC (0x1) #define L3_WT (0x2) #define L3_WB (0x3) #define GMM_DEFINE_PAT_ELEMENT(indx, CLOS, L3Caching) \ { \ pPATTlbElement[indx].Xe_HPC.MemoryType = L3Caching; \ pPATTlbElement[indx].Xe_HPC.L3CLOS = CLOS; \ pPATTlbElement[indx].Xe_HPC.Reserved = 0; \ } // clang-format off // Default PAT Table for (uint32_t i = 0; i < NumPATRegisters; i++) { // Index CLOS CachingPolicy GMM_DEFINE_PAT_ELEMENT( i, 0 , L3_UC ); } // Fixed PAT Table // Group: CLOS0 // Index CLOS CachingPolicy GMM_DEFINE_PAT_ELEMENT( 0 , 0 , L3_UC ) // PATRegValue = 0x0 GMM_DEFINE_PAT_ELEMENT( 1 , 0 , L3_WC ) // PATRegValue = 0x1 GMM_DEFINE_PAT_ELEMENT( 2 , 0 , L3_WT ) // PATRegValue = 0x2 GMM_DEFINE_PAT_ELEMENT( 3 , 0 , L3_WB ) // PATRegValue = 0x3 //Group: CLOS1 GMM_DEFINE_PAT_ELEMENT( 4 , 1 , L3_WT ) // PATRegValue = 0x6 GMM_DEFINE_PAT_ELEMENT( 5 , 1 , L3_WB ) // PATRegValue = 0x7 //Group: CLOS2 GMM_DEFINE_PAT_ELEMENT( 6 , 2 , L3_WT ) // PATRegValue = 0xA GMM_DEFINE_PAT_ELEMENT( 7 , 2 , L3_WB ) // PATRegValue = 0xB CurrentMaxPATIndex = 7; // clang-format on #undef GMM_DEFINE_PAT_ELEMENT #undef L3_UC #undef L3_WC #undef L3_WT #undef L3_WB return GMM_SUCCESS; } ///////////////////////////////////////////////////////////////////////////////////// /// A simple getter function returning the PAT (cache policy) for a given /// use Usage of the named resource pResInfo. /// Typically used to populate PPGTT/GGTT. /// /// @param[in] pResInfo: Resource info for resource, can be NULL. /// @param[in] Usage: Current usage for resource. /// /// @return PATIndex ///////////////////////////////////////////////////////////////////////////////////// uint32_t GMM_STDCALL GmmLib::GmmGen12dGPUCachePolicy::CachePolicyGetPATIndex(GMM_RESOURCE_INFO *pResInfo, GMM_RESOURCE_USAGE_TYPE Usage, bool *pCompressionEnable, bool IsCpuCacheable) { __GMM_ASSERT(pGmmLibContext->GetCachePolicyElement(Usage).Initialized); GMM_UNREFERENCED_PARAMETER(pCompressionEnable); GMM_UNREFERENCED_PARAMETER(IsCpuCacheable); // Prevent wrong Usage for XAdapter resources. UMD does not call GetMemoryObject on shader resources but, // when they add it someone could call it without knowing the restriction. if(pResInfo && pResInfo->GetResFlags().Info.XAdapter && Usage != GMM_RESOURCE_USAGE_XADAPTER_SHARED_RESOURCE) { __GMM_ASSERT(false); } return pGmmLibContext->GetCachePolicyElement(Usage).PATIndex; } gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/CachePolicy/GmmGen12dGPUCachePolicy.h000066400000000000000000000757441466655022700265710ustar00rootroot00000000000000/*============================================================================== Copyright(c) 2020 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ============================================================================*/ #include "GmmCachePolicyConditionals.h" #define EDRAM (SKU(FtrEDram)) #define FBLLC (SKU(FtrFrameBufferLLC)) #define L1 (!WA(Wa_1606955757)) //Macros for segment-preference #define NoP 0x0 #define SYS 0x1 #define LOC 0x2 #define LoP 0x3 #define SyP 0x4 // Cache Policy Definition // L3_SCC = L3 skip caching control (disabled if L3_SCC = 0) // HDCL1 = HDC L1 cache control (1 = cached in HDC L1, 0 = not cached in HDC L1) // Faster PushWrite(Gen10+) used iff !WT, eLLC-only cacheable - Globally visible surface (eg display surface) should be marked WT // GO = Global observable point for L3-uncached (0=Default is L3, 1= Memory)// GO = Global observable point for L3-uncached (0=Default is L3, 1= Memory) // UcLookup = Snoop L3 for uncached (0=Default is no-snoop, 1 =Snoop) // L1CC: L1 cache control (0: WBP write bypass mode, 1: UC uncached, 2: WB Write back, 3:WT write-through, 4: WS Write-Streaming) : Valid only for DG2 //***********************************************************************************************************************************************************/ // USAGE TYPE , L3 , L3_SCC, HDCL1, GO, UcLookup, L1CC) /************************************************************************************************************************************************************/ // KMD Usages DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_BATCH_BUFFER , 0 , 0 , 0, 0, 1, 1); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_COMP_FRAME_BUFFER , 0 , 0 , 0, 0, 1, 1); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_CONTEXT_SWITCH_BUFFER , 0 , 0 , 0, 0, 1, 1); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_CURSOR , 0 , 0 , 0, 0, 1, 1); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_DISPLAY_STATIC_IMG_FOR_SMOOTH_ROTATION_BUFFER , 0 , 0 , 0, 0, 1, 1); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_DUMMY_PAGE , 0 , 0 , 0, 0, 1, 1); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_GDI_SURFACE , 1 , 0 , 0, 0, 1, 1); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_GENERIC_KMD_RESOURCE , 0 , 0 , 0, 0, 1, 1); // GMM_RESOURCE_USAGE_GFX_RING is only used if WaEnableRingHostMapping is enabled. DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_GFX_RING , 0 , 0 , 0, 0, 1, 1); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_GTT_TRANSFER_REGION , 0 , 0 , 0, 0, 1, 1); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_HW_CONTEXT , 0 , 0 , 0, 0, 1, 1); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_STATE_MANAGER_KERNEL_STATE , 0 , 0 , 0, 0, 1, 1); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_KMD_STAGING_SURFACE , 1 , 0 , 0, 0, 1, 1); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_MBM_BUFFER , 0 , 0 , 0, 0, 1, 1); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_NNDI_BUFFER , 0 , 0 , 0, 0, 1, 1); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_OVERLAY_MBM , 0 , 0 , 0, 0, 1, 1); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_PRIMARY_SURFACE , 0 , 0 , 0, 0, 1, 1); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_SCREEN_PROTECTION_INTERMEDIATE_SURFACE , 0 , 0 , 0, 0, 1, 1); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_SHADOW_SURFACE , 1 , 0 , 0, 0, 1, 1); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_SM_SCRATCH_STATE , 0 , 0 , 0, 0, 1, 1); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_STATUS_PAGE , 1 , 0 , 0, 0, 1, 1); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_TIMER_PERF_QUEUE , 0 , 0 , 0, 0, 1, 1); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_UNKNOWN , 0 , 0 , 0, 0, 1, 1); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_UNMAP_PAGING_RESERVED_GTT_DMA_BUFFER , 0 , 0 , 0, 0, 1, 1); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_VSC_BATCH_BUFFER , 0 , 0 , 0, 0, 1, 1); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_WA_BATCH_BUFFER , 0 , 0 , 0, 0, 1, 1); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_KMD_OCA_BUFFER , 0 , 0 , 0, 0, 1, 1); // // 3D Usages // DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_UMD_BATCH_BUFFER , 0 , 0 , 0, 0, 1, 1); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_BINDING_TABLE_POOL , 1 , 0 , 0, 0, 1, 1); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_CCS , 0 , 0 , 0, 1, 0, 1); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_CONSTANT_BUFFER_POOL , 1 , 0 , 0, 0, 1, 1); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_DEPTH_BUFFER , 1 , 0 , 0, 0, 1, 1); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_DISPLAYABLE_RENDER_TARGET , 1 , 0 , 0, 0, 1, 1); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_GATHER_POOL , 1 , 0 , 0, 0, 1, 1); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_HEAP_SURFACE_STATE , 1 , 0 , 0, 0, 1, 1); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_HEAP_DYNAMIC_STATE , 1 , 0 , 0, 0, 1, 1); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_HEAP_GENERAL_STATE , 1 , 0 , 0, 0, 1, 1); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_HEAP_GENERAL_STATE_UC , 0 , 0 , 0, 0, 1, 1); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_HEAP_STATELESS_DATA_PORT , 1 , 0 , 0, 0, 1, 1); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_HEAP_STATELESS_DATA_PORT_L1_CACHED , 1 , 0 , L1, 0, 1, 2); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_HEAP_INDIRECT_OBJECT , 1 , 0 , 0, 0, 1, 1); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_HEAP_INSTRUCTION , 1 , 0 , 0, 0, 1, 1); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_HIZ , 1 , 0 , 0, 0, 1, 1); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_INDEX_BUFFER , 1 , 0 , 0, 0, 1, 1); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_INDEX_BUFFER_L3_COHERENT_UC , 0 , 0 , 0, 0, 1, 1); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_INDEX_BUFFER_L3_CACHED , 1 , 0 , 0, 0, 1, 1); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_MCS , 1 , 0 , 0, 0, 1, 1); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_PUSH_CONSTANT_BUFFER , 1 , 0 , 0, 0, 1, 1); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_PULL_CONSTANT_BUFFER , 1 , 0 , 1, 0, 1, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_QUERY , 1 , 0 , 0, 0, 1, 1); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_RENDER_TARGET , 1 , 0 , 0, 0, 1, 1); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_SHADER_RESOURCE , 1 , 0 , 1, 0, 1, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_STAGING , 1 , 0 , 0, 0, 1, 1); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_STENCIL_BUFFER , 1 , 0 , 0, 0, 1, 1); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_STREAM_OUTPUT_BUFFER , 1 , 0 , 0, 0, 1, 1); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_TILE_POOL , 1 , 0 , 0, 0, 1, 1); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_SHADER_RESOURCE_LLC_BYPASS , 1 , 0 , 1, 0, 1, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_MOCS_62 , 0 , 0 , 0, 1, 0, 1); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_L3_EVICTION , 0 , 0 , 0, 1, 0, 1); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_L3_EVICTION_SPECIAL , 0 , 0 , 0, 1, 0, 1); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_PROCEDURAL_TEXTURE , 1 , 0 , 0, 0, 1, 1); // Tiled Resource DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_TILED_DEPTH_BUFFER , 1 , 0 , 0, 0, 1, 1); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_TILED_HIZ , 1 , 0 , 0, 0, 1, 1); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_TILED_MCS , 1 , 0 , 0, 0, 1, 1); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_TILED_CCS , 1 , 0 , 0, 0, 1, 1); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_TILED_RENDER_TARGET , 1 , 0 , 0, 0, 1, 1); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_TILED_RENDER_TARGET_AND_SHADER_RESOURCE , 1 , 0 , 1, 0, 1, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_TILED_SHADER_RESOURCE , 1 , 0 , 1, 0, 1, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_TILED_UAV , 1 , 0 , 0, 0, 1, 1); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_UAV , 1 , 0 , 0, 0, 1, 1); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_VERTEX_BUFFER , 1 , 0 , 0, 0, 1, 1); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_VERTEX_BUFFER_L3_COHERENT_UC , 0 , 0 , 0, 0, 1, 1); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_VERTEX_BUFFER_L3_CACHED , 1 , 0 , 0, 0, 1, 1); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_OGL_WSTN_VERTEX_BUFFER , 1 , 0 , 0, 0, 1, 1); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_POSH_VERTEX_BUFFER , 1 , 0 , 0, 0, 1, 1); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_RENDER_TARGET_AND_SHADER_RESOURCE , 1 , 0 , 1, 0, 1, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_WDDM_HISTORY_BUFFER , 1 , 0 , 0, 0, 1, 1); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_CONTEXT_SAVE_RESTORE , 1 , 0 , 0, 0, 1, 1); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_PTBR_PAGE_POOL , 1 , 0 , 0, 0, 1, 1); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_PTBR_BATCH_BUFFER , 1 , 0 , 0, 0, 1, 1); // // CM USAGES // // USAGE TYPE , L3 , L3_SCC, HDCL1, GO, UcLookup, L1CC) DEFINE_CACHE_ELEMENT(CM_RESOURCE_USAGE_SurfaceState, 1 , 0 , 0, 0, 1, 1); DEFINE_CACHE_ELEMENT(CM_RESOURCE_USAGE_L1_Enabled_SurfaceState, 1 , 0 , 1, 0, 1, 2); DEFINE_CACHE_ELEMENT(CM_RESOURCE_USAGE_StateHeap, 1 , 0 , 0, 0, 1, 1); DEFINE_CACHE_ELEMENT(CM_RESOURCE_USAGE_NO_L3_SurfaceState, 0 , 0 , 1, 0, 1, 1); DEFINE_CACHE_ELEMENT(CM_RESOURCE_USAGE_NO_CACHE_SurfaceState, 0 , 0 , 0, 1, 0, 1); // // MP USAGES // DEFINE_CACHE_ELEMENT(MP_RESOURCE_USAGE_BEGIN, 0 , 0 , 0, 1, 0, 1); DEFINE_CACHE_ELEMENT(MP_RESOURCE_USAGE_DEFAULT, 0 , 0 , 0, 1, 0, 1); DEFINE_CACHE_ELEMENT(MP_RESOURCE_USAGE_DEFAULT_FF, 0 , 0 , 0, 1, 0, 1); DEFINE_CACHE_ELEMENT(MP_RESOURCE_USAGE_DEFAULT_RCS, 0 , 0 , 0, 0, 1, 1); DEFINE_CACHE_ELEMENT(MP_RESOURCE_USAGE_SurfaceState, 1 , 0 , 0, 0, 1, 1); DEFINE_CACHE_ELEMENT(MP_RESOURCE_USAGE_SurfaceState_FF, 0 , 0 , 0, 1, 0, 1); DEFINE_CACHE_ELEMENT(MP_RESOURCE_USAGE_SurfaceState_RCS, 1 , 0 , 0, 0, 1, 1); DEFINE_CACHE_ELEMENT(MP_RESOURCE_USAGE_END, 0 , 0 , 0, 1, 0, 1); // MHW - SFC DEFINE_CACHE_ELEMENT(MHW_RESOURCE_USAGE_Sfc_CurrentOutputSurface, 0 , 0 , 0, 1, 0, 1); DEFINE_CACHE_ELEMENT(MHW_RESOURCE_USAGE_Sfc_AvsLineBufferSurface, 0 , 0 , 0, 1, 0, 1); DEFINE_CACHE_ELEMENT(MHW_RESOURCE_USAGE_Sfc_IefLineBufferSurface, 0 , 0 , 0, 1, 0, 1); //Media GMM Resource USAGES DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_PRE_DEBLOCKING_CODEC , 0 , 0 , 0, 1, 0, 1); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_POST_DEBLOCKING_CODEC , 0 , 0 , 0, 1, 0, 1); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_ORIGINAL_UNCOMPRESSED_PICTURE_ENCODE , 0 , 0 , 0, 1, 0, 1); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_ORIGINAL_UNCOMPRESSED_PICTURE_DECODE , 0 , 0 , 0, 1, 0, 1); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_STREAMOUT_DATA_CODEC , 0 , 0 , 0, 1, 0, 1); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_INTRA_ROWSTORE_SCRATCH_BUFFER_CODEC , 0 , 0 , 0, 1, 0, 1); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_DEBLOCKINGFILTER_ROWSTORE_SCRATCH_BUFFER_CODEC , 0 , 0 , 0, 1, 0, 1); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_REFERENCE_PICTURE_CODEC , 0 , 0 , 0, 1, 0, 1); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_MACROBLOCK_STATUS_BUFFER_CODEC , 0 , 0 , 0, 1, 0, 1); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_MFX_INDIRECT_BITSTREAM_OBJECT_DECODE , 0 , 0 , 0, 1, 0, 1); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_MFX_INDIRECT_MV_OBJECT_CODEC , 0 , 0 , 0, 1, 0, 1); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_MFD_INDIRECT_IT_COEF_OBJECT_DECODE , 0 , 0 , 0, 1, 0, 1); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_MFC_INDIRECT_PAKBASE_OBJECT_CODEC , 0 , 0 , 0, 1, 0, 1); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_BSDMPC_ROWSTORE_SCRATCH_BUFFER_CODEC , 0 , 0 , 0, 1, 0, 1); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_MPR_ROWSTORE_SCRATCH_BUFFER_CODEC , 0 , 0 , 0, 1, 0, 1); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_BITPLANE_READ_CODEC , 0 , 0 , 0, 1, 0, 1); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_AACSBIT_VECTOR_CODEC , 0 , 0 , 0, 1, 0, 1); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_DIRECTMV_BUFFER_CODEC , 0 , 0 , 0, 1, 0, 1); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_SURFACE_CURR_ENCODE , 1 , 0 , 0, 0, 1, 1); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_SURFACE_REF_ENCODE , 1 , 0 , 0, 0, 1, 1); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_SURFACE_MV_DATA_ENCODE , 1 , 0 , 0, 0, 1, 1); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_SURFACE_HME_DOWNSAMPLED_ENCODE , 1 , 0 , 0, 0, 1, 1); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_SURFACE_HME_DOWNSAMPLED_ENCODE_FF , 0 , 0 , 0, 0, 1, 1); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_SURFACE_HME_DOWNSAMPLED_ENCODE_DST , 1 , 0 , 0, 0, 1, 1); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_SURFACE_ME_DISTORTION_ENCODE , 1 , 0 , 0, 0, 1, 1); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_SURFACE_BRC_ME_DISTORTION_ENCODE , 1 , 0 , 0, 0, 1, 1); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_PAK_OBJECT_ENCODE , 1 , 0 , 0, 0, 1, 1); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_SURFACE_FLATNESS_CHECK_ENCODE , 1 , 0 , 0, 0, 1, 1); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_SURFACE_MBENC_CURBE_ENCODE , 1 , 0 , 0, 0, 1, 1); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_VDENC_ROW_STORE_BUFFER_CODEC , 0 , 0 , 0, 1, 0, 1); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_VDENC_STREAMIN_CODEC , 0 , 0 , 0, 1, 0, 1); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_HCP_MD_CODEC , 0 , 0 , 0, 1, 0, 1); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_HCP_SAO_CODEC , 0 , 0 , 0, 1, 0, 1); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_HCP_MV_CODEC , 0 , 0 , 0, 1, 0, 1); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_HCP_STATUS_ERROR_CODEC , 0 , 0 , 0, 1, 0, 1); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_HCP_LCU_ILDB_STREAMOUT_CODEC , 0 , 0 , 0, 1, 0, 1); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_VP9_PROBABILITY_BUFFER_CODEC , 0 , 0 , 0, 1, 0, 1); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_VP9_SEGMENT_ID_BUFFER_CODEC , 0 , 0 , 0, 1, 0, 1); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_VP9_HVD_ROWSTORE_BUFFER_CODEC , 0 , 0 , 0, 1, 0, 1); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_MACROBLOCK_ILDB_STREAM_OUT_BUFFER_CODEC , 0 , 0 , 0, 1, 0, 1); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_SSE_SRC_PIXEL_ROW_STORE_BUFFER_CODEC , 0 , 0 , 0, 1, 0, 1); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_SLICE_STATE_STREAM_OUT_BUFFER_CODEC , 0 , 0 , 0, 1, 0, 1); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_CABAC_SYNTAX_STREAM_OUT_BUFFER_CODEC , 0 , 0 , 0, 1, 0, 1); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_PRED_COL_STORE_BUFFER_CODEC , 0 , 0 , 0, 1, 0, 1); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_SURFACE_UNCACHED , 0 , 0 , 0, 1, 0, 1); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_SURFACE_ELLC_ONLY , 0 , 0 , 0, 1, 0, 1); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_SURFACE_ELLC_LLC_ONLY , 0 , 0 , 0, 1, 0, 1); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_SURFACE_ELLC_LLC_L3 , 1 , 0 , 0, 0, 1, 1); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_CCS_MEDIA_WRITABLE , 0 , 0 , 0, 1, 0, 1); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_SURFACE_BRC_HISTORY_ENCODE , 1 , 0 , 0, 0, 1, 1); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_SURFACE_SOFTWARE_SCOREBOARD_ENCODE , 1 , 0 , 0, 0, 1, 1); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_SURFACE_ME_MV_DATA_ENCODE , 1 , 0 , 0, 0, 1, 1); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_SURFACE_MV_DISTORTION_ENCODE , 1 , 0 , 0, 0, 1, 1); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_SURFACE_4XME_DISTORTION_ENCODE , 1 , 0 , 0, 0, 1, 1); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_SURFACE_INTRA_DISTORTION_ENCODE , 1 , 0 , 0, 0, 1, 1); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_MB_STATS_ENCODE , 1 , 0 , 0, 0, 1, 1); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_SURFACE_PAK_STATS_ENCODE , 1 , 0 , 0, 0, 1, 1); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_SURFACE_PIC_STATE_READ_ENCODE , 1 , 0 , 0, 0, 1, 1); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_SURFACE_PIC_STATE_WRITE_ENCODE , 1 , 0 , 0, 0, 1, 1); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_SURFACE_COMBINED_ENC_ENCODE , 1 , 0 , 0, 0, 1, 1); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_SURFACE_BRC_CONSTANT_DATA_ENCODE , 1 , 0 , 0, 0, 1, 1); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_SURFACE_INTERMEDIATE_CU_RECORD_SURFACE_ENCODE , 0 , 0 , 0, 1, 0, 1); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_SURFACE_SCRATCH_ENCODE , 0 , 0 , 0, 1, 0, 1); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_SURFACE_LCU_LEVEL_DATA_ENCODE , 1 , 0 , 0, 0, 1, 1); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_SURFACE_ENC_HISTORY_INPUT_ENCODE , 1 , 0 , 0, 0, 1, 1); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_SURFACE_ENC_HISTORY_OUTPUT_ENCODE , 1 , 0 , 0, 0, 1, 1); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_SURFACE_DEBUG_ENCODE , 0 , 0 , 0, 1, 0, 1); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_SURFACE_ENC_CONSTANT_TABLE_ENCODE , 1 , 0 , 0, 0, 1, 1); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_SURFACE_ENC_CU_RECORD_ENCODE , 1 , 0 , 0, 0, 1, 1); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_SURFACE_ENC_MV_TEMPORAL_BUFFER_ENCODE , 1 , 0 , 0, 0, 1, 1); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_SURFACE_ENC_CU_PACKET_FOR_PAK_ENCODE , 1 , 0 , 0, 0, 1, 1); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_SURFACE_ENC_BCOMBINED1_ENCODE , 1 , 0 , 0, 0, 1, 1); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_SURFACE_ENC_BCOMBINED2_ENCODE , 1 , 0 , 0, 0, 1, 1); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_FRAME_STATS_STREAMOUT_DATA_CODEC , 0 , 0 , 0, 1, 0, 1); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_DEBLOCKINGFILTER_ROWSTORE_TILE_LINE_BUFFER_CODEC , 0 , 0 , 0, 1, 0, 1); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_DEBLOCKINGFILTER_ROWSTORE_TILE_COLUMN_BUFFER_CODEC , 0 , 0 , 0, 1, 0, 1); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_HCP_MD_TILE_LINE_CODEC , 0 , 0 , 0, 1, 0, 1); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_HCP_MD_TILE_COLUMN_CODEC , 0 , 0 , 0, 1, 0, 1); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_HCP_SAO_TILE_LINE_CODEC , 0 , 0 , 0, 1, 0, 1); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_HCP_SAO_TILE_COLUMN_CODEC , 0 , 0 , 0, 1, 0, 1); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_VP9_PROBABILITY_COUNTER_BUFFER_CODEC , 0 , 0 , 0, 1, 0, 1); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_HUC_VIRTUAL_ADDR_REGION_BUFFER_CODEC , 0 , 0 , 0, 1, 0, 1); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_SIZE_STREAMOUT_CODEC , 0 , 0 , 0, 1, 0, 1); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_COMPRESSED_HEADER_BUFFER_CODEC , 0 , 0 , 0, 1, 0, 1); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_PROBABILITY_DELTA_BUFFER_CODEC , 0 , 0 , 0, 1, 0, 1); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_TILE_RECORD_BUFFER_CODEC , 0 , 0 , 0, 1, 0, 1); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_TILE_SIZE_STAS_BUFFER_CODEC , 0 , 0 , 0, 1, 0, 1); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_SURFACE_MAD_ENCODE , 1 , 0 , 0, 0, 1, 1); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_SURFACE_PAK_IMAGESTATE_ENCODE , 1 , 0 , 0, 0, 1, 1); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_SURFACE_MBENC_BRC_ENCODE , 1 , 0 , 0, 0, 1, 1); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_SURFACE_MB_BRC_CONST_ENCODE , 1 , 0 , 0, 0, 1, 1); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_SURFACE_BRC_MB_QP_ENCODE , 1 , 0 , 0, 0, 1, 1); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_SURFACE_BRC_ROI_ENCODE , 1 , 0 , 0, 0, 1, 1); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_MBDISABLE_SKIPMAP_CODEC , 1 , 0 , 0, 0, 1, 1); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_SURFACE_SLICE_MAP_ENCODE , 1 , 0 , 0, 0, 1, 1); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_SURFACE_WP_DOWNSAMPLED_ENCODE , 1 , 0 , 0, 0, 1, 1); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_SURFACE_VDENC_IMAGESTATE_ENCODE , 0 , 0 , 0, 1, 0, 1); /**********************************************************************************/ // // OCL Usages // DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_OCL_BUFFER , 1 , 0 , 0, 0, 1, 1); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_OCL_BUFFER_CONST , 1 , 0 , 1, 0, 1, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_OCL_BUFFER_CSR_UC , 0 , 0 , 0, 1, 1, 1); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_OCL_BUFFER_CACHELINE_MISALIGNED , 0 , 0 , 0, 1, 1, 1); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_OCL_IMAGE , 1 , 0 , 0, 0, 1, 1); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_OCL_INLINE_CONST , 1 , 0 , 0, 0, 1, 1); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_OCL_INLINE_CONST_HDC , 1 , 0 , 1, 0, 1, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_OCL_SCRATCH , 1 , 0 , 0, 0, 1, 1); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_OCL_PRIVATE_MEM , 1 , 0 , 0, 0, 1, 1); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_OCL_PRINTF_BUFFER , 1 , 0 , 0, 0, 1, 1); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_OCL_STATE_HEAP_BUFFER , 1 , 0 , 0, 0, 1, 1); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_OCL_SYSTEM_MEMORY_BUFFER , 1 , 0 , 0, 0, 1, 1); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_OCL_SYSTEM_MEMORY_BUFFER_CACHELINE_MISALIGNED , 0 , 0 , 0, 1, 1, 1); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_OCL_ISH_HEAP_BUFFER , 1 , 0 , 0, 0, 1, 1); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_OCL_TAG_MEMORY_BUFFER , 1 , 0 , 0, 0, 1, 1); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_OCL_TEXTURE_BUFFER , 1 , 0 , 0, 0, 1, 1); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_OCL_SELF_SNOOP_BUFFER , 1 , 0 , 0, 0, 1, 1); /**********************************************************************************/ // Cross Adapter DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_XADAPTER_SHARED_RESOURCE , 1 , 0 , 0, 0, 1, 1); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_KMD_NULL_CONTEXT_BB , 0 , 0 , 0, 0, 1, 1); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_COMMAND_STREAMER , 0 , 0 , 0, 1, 1, 1); /**********************************************************************************/ // Uncacheable copies DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_COPY_SOURCE , 0 , 0 , 0 , 1 , 0, 1); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_COPY_DEST , 0 , 0 , 0 , 1 , 0, 1); #include "GmmCachePolicyUndefineConditionals.h" gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/CachePolicy/GmmGen8CachePolicy.cpp000066400000000000000000000435011466655022700263130ustar00rootroot00000000000000/*============================================================================== Copyright(c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ============================================================================*/ #include "Internal/Common/GmmLibInc.h" #include "External/Common/GmmCachePolicy.h" //============================================================================= // // Function: __GmmGen8InitCachePolicy // // Desc: This function initializes the cache policy // // Parameters: pCachePolicy -> Ptr to array to be populated with the // mapping of usages -> cache settings. // // Return: GMM_STATUS //----------------------------------------------------------------------------- GMM_STATUS GmmLib::GmmGen8CachePolicy::InitCachePolicy() { __GMM_ASSERTPTR(pCachePolicy, GMM_ERROR); #define DEFINE_CACHE_ELEMENT(usage, llc, ellc, l3, wt, age) DEFINE_CP_ELEMENT(usage, llc, ellc, l3, wt, age, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) #include "GmmGen8CachePolicy.h" { // Gen8 Memory Object Definitions #define MO_ELLC 0x0 #define MO_LLC 0x1 #define MO_LLC_ELLC 0x2 #define MO_L3_LLC_ELLC 0x3 #define MO_USE_PTE 0x0 #define MO_UC 0x1 #define MO_WT 0x2 #define MO_WB 0x3 // Define index of cache element uint32_t Usage = 0; // Process Cache Policy and fill in look up table for(; Usage < GMM_RESOURCE_USAGE_MAX; Usage++) { bool CachePolicyError = false; uint64_t PTEValue = 0; if(pCachePolicy[Usage].LLC && pCachePolicy[Usage].ELLC && pCachePolicy[Usage].L3) pCachePolicy[Usage].MemoryObjectOverride.Gen8.TargetCache = MO_L3_LLC_ELLC; else if(pCachePolicy[Usage].LLC && pCachePolicy[Usage].ELLC) pCachePolicy[Usage].MemoryObjectOverride.Gen8.TargetCache = MO_LLC_ELLC; else if(pCachePolicy[Usage].ELLC) pCachePolicy[Usage].MemoryObjectOverride.Gen8.TargetCache = MO_ELLC; else if(pCachePolicy[Usage].LLC) pCachePolicy[Usage].MemoryObjectOverride.Gen8.TargetCache = MO_LLC; pCachePolicy[Usage].MemoryObjectOverride.Gen8.Age = pCachePolicy[Usage].AGE; if(pCachePolicy[Usage].WT) pCachePolicy[Usage].MemoryObjectOverride.Gen8.CacheControl = MO_WT; // L3 is not included because WT vs UC vs WB only effects uncore else if(!(pCachePolicy[Usage].LLC || pCachePolicy[Usage].ELLC)) pCachePolicy[Usage].MemoryObjectOverride.Gen8.CacheControl = MO_UC; else pCachePolicy[Usage].MemoryObjectOverride.Gen8.CacheControl = MO_WB; if(!GetUsagePTEValue(pCachePolicy[Usage], Usage, &PTEValue)) { CachePolicyError = true; } // On error, the PTE value is set to a UC PAT entry pCachePolicy[Usage].PTE.DwordValue = PTEValue & 0xFFFFFFFF; pCachePolicy[Usage].PTE.HighDwordValue = 0; pCachePolicy[Usage].Override = ALWAYS_OVERRIDE; if(CachePolicyError) { GMM_ASSERTDPF("Cache Policy Init Error: Invalid Cache Programming - Element %d", Usage); } } } return GMM_SUCCESS; } ///////////////////////////////////////////////////////////////////////////////////// /// Returns true if usage PTE entries are set for caching, false otherwise. /// /// @param[in] Usage: type of usage /// /// @return true if the usage PTE entry is set for cached, false otherwise. ///////////////////////////////////////////////////////////////////////////////////// uint8_t GMM_STDCALL GmmLib::GmmGen8CachePolicy::CachePolicyIsUsagePTECached(GMM_RESOURCE_USAGE_TYPE Usage) { GMM_UNREFERENCED_PARAMETER(Usage); return 0; } ///////////////////////////////////////////////////////////////////////////////////// /// Initializes the Gfx PAT tables for AdvCtx and Gfx MMIO/Private PAT /// PAT0 = WB_COHERENT or UC depending on WaGttPat0WB /// PAT1 = UC or WB_COHERENT depending on WaGttPat0WB /// PAT2 = WB_MOCSLESS, with TC = eLLC+LLC /// PAT3 = WB /// PAT4 = WT /// PAT5 = WC /// PAT6 = WC /// PAT7 = WC /// HLD says to set to PAT0/1 to WC, but since we don't have a WC in GPU, /// WC option is same as UC. Hence setting PAT0 or PAT1 to UC. /// Unused PAT's (5,6,7) are set to WC. /// /// @return GMM_STATUS ///////////////////////////////////////////////////////////////////////////////////// GMM_STATUS GmmLib::GmmGen8CachePolicy::SetupPAT() { GMM_STATUS Status = GMM_SUCCESS; #if(defined(__GMM_KMD__)) uint32_t i = 0; GMM_GFX_MEMORY_TYPE GfxMemType = GMM_GFX_UC_WITH_FENCE; // No optional selection on Age or Target Cache because for an SVM-OS Age and // Target Cache would not work [for an SVM-OS the Page Table is shared with IA // and we don't have control of the PAT Idx]. If there is a strong ask from D3D // or the performance analysis team, Age could be added. // Add Class of Service when required. GMM_GFX_TARGET_CACHE GfxTargetCache = GMM_GFX_TC_ELLC_LLC; uint8_t Age = 1; uint8_t ServiceClass = 0; int32_t * pPrivatePATTableMemoryType = NULL; pPrivatePATTableMemoryType = pGmmLibContext->GetPrivatePATTableMemoryType(); __GMM_ASSERT(pGmmLibContext->GetSkuTable().FtrIA32eGfxPTEs); for(i = 0; i < GMM_NUM_GFX_PAT_TYPES; i++) { pPrivatePATTableMemoryType[i] = -1; } // Set values for GmmGlobalInfo PrivatePATTable for(i = 0; i < NumPATRegisters; i++) { GMM_PRIVATE_PAT PAT = {0}; if(pGmmLibContext->GetWaTable().WaNoMocsEllcOnly) { GfxTargetCache = GMM_GFX_TC_ELLC_ONLY; } else { GfxTargetCache = GMM_GFX_TC_ELLC_LLC; } switch(i) { case PAT0: if(pGmmLibContext->GetWaTable().WaGttPat0) { if(pGmmLibContext->GetWaTable().WaGttPat0WB) { GfxMemType = GMM_GFX_WB; if(GFX_IS_ATOM_PLATFORM(pGmmLibContext)) { PAT.PreGen10.Snoop = 1; } pPrivatePATTableMemoryType[GMM_GFX_PAT_WB_COHERENT] = PAT0; } else { GfxMemType = GMM_GFX_UC_WITH_FENCE; pPrivatePATTableMemoryType[GMM_GFX_PAT_UC] = PAT0; } } else // if GTT is not tied to PAT0 then WaGttPat0WB is NA { GfxMemType = GMM_GFX_WB; if(GFX_IS_ATOM_PLATFORM(pGmmLibContext)) { PAT.PreGen10.Snoop = 1; } pPrivatePATTableMemoryType[GMM_GFX_PAT_WB_COHERENT] = PAT0; } break; case PAT1: if(pGmmLibContext->GetWaTable().WaGttPat0 && !pGmmLibContext->GetWaTable().WaGttPat0WB) { GfxMemType = GMM_GFX_WB; if(GFX_IS_ATOM_PLATFORM(pGmmLibContext)) { PAT.PreGen10.Snoop = 1; } pPrivatePATTableMemoryType[GMM_GFX_PAT_WB_COHERENT] = PAT1; } else { GfxMemType = GMM_GFX_UC_WITH_FENCE; pPrivatePATTableMemoryType[GMM_GFX_PAT_UC] = PAT1; } break; case PAT2: // This PAT idx shall be used for MOCS'Less resources like Page Tables // Page Tables have TC hardcoded to eLLC+LLC in Adv Ctxt. Hence making this to have same in Leg Ctxt. // For BDW-H, due to Perf issue, TC has to be eLLC only for Page Tables when eDRAM is present. GfxMemType = GMM_GFX_WB; if(pGmmLibContext->GetWaTable().WaNoMocsEllcOnly) { GfxTargetCache = GMM_GFX_TC_ELLC_ONLY; } else { GfxTargetCache = GMM_GFX_TC_ELLC_LLC; } pPrivatePATTableMemoryType[GMM_GFX_PAT_WB_MOCSLESS] = PAT2; break; case PAT3: GfxMemType = GMM_GFX_WB; pPrivatePATTableMemoryType[GMM_GFX_PAT_WB] = PAT3; break; case PAT4: GfxMemType = GMM_GFX_WT; pPrivatePATTableMemoryType[GMM_GFX_PAT_WT] = PAT4; break; case PAT5: case PAT6: case PAT7: GfxMemType = GMM_GFX_WC; pPrivatePATTableMemoryType[GMM_GFX_PAT_WC] = PAT5; break; default: __GMM_ASSERT(0); Status = GMM_ERROR; } PAT.PreGen10.MemoryType = GfxMemType; PAT.PreGen10.TargetCache = GfxTargetCache; PAT.PreGen10.Age = Age; SetPrivatePATEntry(i, PAT); } #else Status = GMM_ERROR; #endif return Status; } ///////////////////////////////////////////////////////////////////////////////////// /// Initializes WA's needed for setting up the Private PATs /// WaNoMocsEllcOnly, WaGttPat0, WaGttPat0GttWbOverOsIommuEllcOnly, WaGttPat0WB /// /// @return GMM_STATUS /// ///////////////////////////////////////////////////////////////////////////////////// GMM_STATUS GmmLib::GmmGen8CachePolicy::SetPATInitWA() { GMM_STATUS Status = GMM_SUCCESS; WA_TABLE * pWaTable = &const_cast(pGmmLibContext->GetWaTable()); #if(defined(__GMM_KMD__)) pWaTable->WaGttPat0 = 1; pWaTable->WaGttPat0WB = 1; pWaTable->WaGttPat0GttWbOverOsIommuEllcOnly = 1; // Platforms which support OS-IOMMU. if(pGmmLibContext->GetSkuTable().FtrWddm2Svm) { pWaTable->WaGttPat0GttWbOverOsIommuEllcOnly = 0; pWaTable->WaGttPat0WB = 0; } #else Status = GMM_ERROR; #endif return Status; } ///////////////////////////////////////////////////////////////////////////////////// /// Returns the PAT idx that best matches the cache policy for this usage. /// /// @param: CachePolicy: cache policy for a usage /// /// @return PAT Idx to use in the PTE ///////////////////////////////////////////////////////////////////////////////////// uint32_t GmmLib::GmmGen8CachePolicy::BestMatchingPATIdx(GMM_CACHE_POLICY_ELEMENT CachePolicy) { uint32_t i; uint32_t PATIdx = 0; GMM_GFX_MEMORY_TYPE WantedMemoryType = GMM_GFX_UC_WITH_FENCE, MemoryType; GMM_GFX_TARGET_CACHE WantedTC = GMM_GFX_TC_ELLC_LLC; WantedMemoryType = GetWantedMemoryType(CachePolicy); if(CachePolicy.LLC && CachePolicy.ELLC) { WantedTC = GMM_GFX_TC_ELLC_LLC; } else if(CachePolicy.LLC) { WantedTC = GMM_GFX_TC_LLC_ONLY; } else if(CachePolicy.ELLC) { WantedTC = GMM_GFX_TC_ELLC_ONLY; // Note: this overrides the MOCS target cache selection. } for(i = 1; i < NumPATRegisters; i++) { GMM_PRIVATE_PAT PAT1 = GetPrivatePATEntry(PATIdx); GMM_PRIVATE_PAT PAT2 = GetPrivatePATEntry(i); if(SelectNewPATIdx(WantedMemoryType, WantedTC, (GMM_GFX_MEMORY_TYPE)PAT1.PreGen10.MemoryType, (GMM_GFX_TARGET_CACHE)PAT1.PreGen10.TargetCache, (GMM_GFX_MEMORY_TYPE)PAT2.PreGen10.MemoryType, (GMM_GFX_TARGET_CACHE)PAT2.PreGen10.TargetCache)) { PATIdx = i; } } MemoryType = (GMM_GFX_MEMORY_TYPE)GetPrivatePATEntry(PATIdx).PreGen10.MemoryType; if(MemoryType != WantedMemoryType) { // Failed to find a matching PAT entry return GMM_PAT_ERROR; } return PATIdx; } ///////////////////////////////////////////////////////////////////////////////////// /// Sets the GMM Private PAT in the PrivatePATTable for the PATIdx, GMM_PRIVATE_PAT /// Entry passed /// /// @param[in] PATIdx /// @param[in] GMM_PRIVATE_PAT: PAT Entry /// /// @return Pass/ fail ///////////////////////////////////////////////////////////////////////////////////// bool GmmLib::GmmGen8CachePolicy::SetPrivatePATEntry(uint32_t PATIdx, GMM_PRIVATE_PAT Entry) { if(PATIdx >= NumPATRegisters) { GMM_ASSERTDPF(false, "CRITICAL ERROR: INVALID PAT IDX"); return false; } pGmmLibContext->GetPrivatePATTable()[PATIdx] = Entry; return true; } ///////////////////////////////////////////////////////////////////////////////////// /// Gets the GMM Private PAT from the PrivatePATTable for the PATIdx passed /// /// @param[in] PATIdx /// /// @return GMM_PRIVATE_PAT: Entry ///////////////////////////////////////////////////////////////////////////////////// GMM_PRIVATE_PAT GmmLib::GmmGen8CachePolicy::GetPrivatePATEntry(uint32_t PATIdx) { GMM_PRIVATE_PAT NullPAT = {0}; if(PATIdx >= NumPATRegisters) { GMM_ASSERTDPF(false, "CRITICAL ERROR: INVALID PAT IDX"); return NullPAT; } return pGmmLibContext->GetPrivatePATTable()[PATIdx]; } ///////////////////////////////////////////////////////////////////////////////////// /// Return true if (MT2, TC2) is a better match for (WantedMT, WantedTC) /// than (MT1, TC1) /// /// @param[in] WantedMT: Wanted Memory Type /// @param[in] WantedTC: Wanted Target Cache /// @param[in] MT1: Memory Type for PATIdx1 /// @param[in] TC1: Target Cache for PATIdx1 /// @param[in] MT2: Memory Type for PATIdx2 /// @param[in] TC2: Target Cache for PATIdx2 /// /// @return Select the new PAT Index True/False ///////////////////////////////////////////////////////////////////////////////////// bool GmmLib::GmmGen8CachePolicy::SelectNewPATIdx(GMM_GFX_MEMORY_TYPE WantedMT, GMM_GFX_TARGET_CACHE WantedTC, GMM_GFX_MEMORY_TYPE MT1, GMM_GFX_TARGET_CACHE TC1, GMM_GFX_MEMORY_TYPE MT2, GMM_GFX_TARGET_CACHE TC2) { bool SelectPAT2 = false; // select on Memory Type if(MT1 != WantedMT) { if(MT2 == WantedMT || MT2 == GMM_GFX_UC_WITH_FENCE) { SelectPAT2 = true; } goto EXIT; } // select on Target Cache if(WantedTC != TC1) { if(WantedMT == MT2 && WantedTC == TC2) { SelectPAT2 = true; } goto EXIT; } EXIT: return SelectPAT2; } ///////////////////////////////////////////////////////////////////////////////////// /// Returns PTE value /// /// @param[in] CachePolicyUsage: Cache Policy for Usage /// /// @return true: success, false: failure ///////////////////////////////////////////////////////////////////////////////////// bool GmmLib::GmmGen8CachePolicy::GetUsagePTEValue(GMM_CACHE_POLICY_ELEMENT CachePolicyUsage, uint32_t Usage, uint64_t * pPTEDwordValue) { GMM_PTE_CACHE_CONTROL_BITS PTE = {0}; bool Success = true; uint32_t PATIdx = 0; // Don't setup PTE values in UMD #if __GMM_KMD__ if((PATIdx = BestMatchingPATIdx(CachePolicyUsage)) == GMM_PAT_ERROR) { // IAe32 PAT table does not necessarily have an entry for WT memory type // => not a cache policy init error if WT is unavailable. Success = CachePolicyUsage.WT ? true : false; // degrade to UC { GMM_CACHE_POLICY_ELEMENT CachePolicyElement = {0}; const char *MemTypes[4] = {"UC", "WC", "WT", "WB"}; // matches GMM_GFX_MEMORY_TYPE enum values CachePolicyElement.Initialized = 1; GMM_DPF(GFXDBG_NORMAL, "Cache Policy Init: Degrading PAT settings to UC (uncached) from %s for Element %d\n", MemTypes[GetWantedMemoryType(CachePolicyUsage)], Usage); PATIdx = BestMatchingPATIdx(CachePolicyElement); if(PATIdx == GMM_PAT_ERROR) { Success = false; } } } if(PATIdx != GMM_PAT_ERROR) { PTE.Gen8.PAT = (PATIdx & __BIT(2)) ? 1 : 0; PTE.Gen8.PCD = (PATIdx & __BIT(1)) ? 1 : 0; PTE.Gen8.PWT = (PATIdx & __BIT(0)) ? 1 : 0; } else { PTE.DwordValue = 0x0; } #else GMM_UNREFERENCED_PARAMETER(CachePolicyUsage); GMM_UNREFERENCED_PARAMETER(Usage); #endif *pPTEDwordValue = PTE.DwordValue; return Success; } gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/CachePolicy/GmmGen8CachePolicy.h000077500000000000000000000445001466655022700257630ustar00rootroot00000000000000/*============================================================================== Copyright(c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ============================================================================*/ #include "GmmCachePolicyConditionals.h" #define ULT (SKU(FtrULT)) #define EDRAM (_ELLC > MB(0)) // [!] On Gen8, according to bpsec TC = 11b means L3, LLC and eLLC cachable. // In order for resources to be places in L3, LLC/ELLC/L3 should be set to 1. // ELLC = EDRAM indicate resource needed in EDRAM but ELLC = 1 indicate resource needed in L3 // Cache Policy Definition //********************************************************************************************************************/ // USAGE TYPE , LLC , ELLC , L3 , WT , AGE ) /*********************************************************************************************************************/ // KMD Usages DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_BATCH_BUFFER , 0 , 0 , 0 , 0 , 0 ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_COMP_FRAME_BUFFER , 0 , 0 , 0 , 0 , 0 ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_CONTEXT_SWITCH_BUFFER , 0 , 0 , 0 , 0 , 0 ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_CURSOR , 0 , 0 , 0 , 0 , 0 ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_DISPLAY_STATIC_IMG_FOR_SMOOTH_ROTATION_BUFFER , 0 , 0 , 0 , 0 , 0 ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_DUMMY_PAGE , 0 , 0 , 0 , 0 , 0 ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_GDI_SURFACE , 1 , 1 , 1 , 0 , 1 ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_GENERIC_KMD_RESOURCE , 0 , 0 , 0 , 0 , 0 ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_GFX_RING , 0 , 0 , 0 , 0 , 0 ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_GTT_TRANSFER_REGION , 0 , 0 , 0 , 0 , 0 ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_HW_CONTEXT , 0 , 0 , 0 , 0 , 0 ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_STATE_MANAGER_KERNEL_STATE , 0 , 0 , 0 , 0 , 0 ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_KMD_STAGING_SURFACE , 1 , 1 , 1 , 0 , 1 ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_MBM_BUFFER , 0 , 0 , 0 , 0 , 0 ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_NNDI_BUFFER , 0 , 0 , 0 , 0 , 0 ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_OVERLAY_MBM , 0 , 0 , 0 , 0 , 0 ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_PRIMARY_SURFACE , 1 , 1 , 1 , 1 , 1 ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_SCREEN_PROTECTION_INTERMEDIATE_SURFACE , 0 , 0 , 0 , 0 , 0 ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_SHADOW_SURFACE , !ULT , 1 , 1 , 0 , 1 ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_SM_SCRATCH_STATE , 0 , 0 , 0 , 0 , 0 ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_STATUS_PAGE , 1 , 1 , 1 , 0 , 1 ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_TIMER_PERF_QUEUE , 0 , 0 , 0 , 0 , 0 ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_UNKNOWN , 0 , 0 , 0 , 0 , 0 ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_UNMAP_PAGING_RESERVED_GTT_DMA_BUFFER , 0 , 0 , 0 , 0 , 0 ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_VSC_BATCH_BUFFER , 0 , 0 , 0 , 0 , 0 ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_WA_BATCH_BUFFER , 0 , 0 , 0 , 0 , 0 ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_KMD_OCA_BUFFER , 0 , 0 , 0 , 0 , 0 ); // // 3D Usages // DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_BINDING_TABLE_POOL , 1 , 1 , 1 , 0 , 3 ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_CONSTANT_BUFFER_POOL , 1 , 1 , 1 , 0 , 3 ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_DEPTH_BUFFER , !EDRAM, EDRAM , 0 , 0 , 1 ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_DISPLAYABLE_RENDER_TARGET , 0 , EDRAM , 0 , EDRAM , 1 ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_GATHER_POOL , 0 , EDRAM , 0 , 0 , 1 ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_HEAP_SURFACE_STATE , 1 , 1 , 1 , 0 , 3 ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_HEAP_DYNAMIC_STATE , 1 , 1 , 1 , 0 , 3 ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_HEAP_GENERAL_STATE , 1 , 1 , 1 , 0 , 3 ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_HEAP_STATELESS_DATA_PORT , 1 , 1 , 1 , 0 , 3 ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_HEAP_INDIRECT_OBJECT , 1 , 1 , 1 , 0 , 3 ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_HEAP_INSTRUCTION , 1 , 1 , 1 , 0 , 3 ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_HIZ , 1 , 1 , 1 , 0 , 1 ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_INDEX_BUFFER , !EDRAM, EDRAM , 0 , 0 , 1 ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_MCS , 0 , EDRAM , 0 , 0 , 1 ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_PUSH_CONSTANT_BUFFER , 0 , EDRAM , 0 , 0 , 1 ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_PULL_CONSTANT_BUFFER , 1 , 1 , 1 , 0 , 3 ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_QUERY , 0 , EDRAM , 0 , 0 , 1 ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_RENDER_TARGET , 1 , 1 , 1 , 0 , 1 ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_SHADER_RESOURCE , 1 , 1 , 1 , 0 , 1 ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_STAGING , 0 , EDRAM , 0 , 0 , 1 ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_STENCIL_BUFFER , 0 , EDRAM , 0 , 0 , 1 ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_STREAM_OUTPUT_BUFFER , 0 , EDRAM , 0 , 0 , 1 ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_TILE_POOL , 0 , EDRAM , 0 , 0 , 1 ); // Tiled Resource DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_TILED_DEPTH_BUFFER , !EDRAM, EDRAM , 0 , 0 , 1 ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_TILED_HIZ , 1 , 1 , 1 , 0 , 1 ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_TILED_MCS , 0 , EDRAM , 0 , 0 , 1 ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_TILED_RENDER_TARGET , 1 , 1 , 1 , 0 , 1 ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_TILED_RENDER_TARGET_AND_SHADER_RESOURCE , 1 , 1 , 1 , 0 , 1 ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_TILED_SHADER_RESOURCE , 1 , 1 , 1 , 0 , 1 ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_TILED_UAV , 1 , 1 , 1 , 0 , 1 ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_VERTEX_BUFFER , 0 , EDRAM , 0 , 0 , 1 ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_OGL_WSTN_VERTEX_BUFFER , 0 , EDRAM , 0 , 0 , 1 ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_UAV , 1 , 1 , 1 , 0 , 1 ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_RENDER_TARGET_AND_SHADER_RESOURCE , 1 , 1 , 1 , 0 , 1 ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_WDDM_HISTORY_BUFFER , 0 , EDRAM , 0 , 0 , 1 ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_CONTEXT_SAVE_RESTORE , 0 , EDRAM , 0 , 0 , 1 ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_PROCEDURAL_TEXTURE , 0 , 0 , 0 , 0 , 0 ); // // CM USAGES // DEFINE_CACHE_ELEMENT(CM_RESOURCE_USAGE_SurfaceState, 1 , 1 , 1 , 0 , 1 ); // // MP USAGES // DEFINE_CACHE_ELEMENT(MP_RESOURCE_USAGE_BEGIN, 0 , 0 , 0 , 0 , 0); DEFINE_CACHE_ELEMENT(MP_RESOURCE_USAGE_DEFAULT, 0 , 0 , 0 , 0 , 0); DEFINE_CACHE_ELEMENT(MP_RESOURCE_USAGE_SurfaceState, 1 , 1 , 1 , 0 , 1); DEFINE_CACHE_ELEMENT(MP_RESOURCE_USAGE_No_L3_SurfaceState, 1 , 1 , 0 , 0 , 1); DEFINE_CACHE_ELEMENT(MP_RESOURCE_USAGE_No_LLC_L3_SurfaceState, 0 , 1 , 0 , 0 , 1); DEFINE_CACHE_ELEMENT(MP_RESOURCE_USAGE_END, 0 , 0 , 0 , 0 , 0); //Media GMM Resource USAGES DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_PRE_DEBLOCKING_CODEC , 0 , 1 , 0 , 0 , 1); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_POST_DEBLOCKING_CODEC , 0 , 1 , 0 , 0 , 1); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_ORIGINAL_UNCOMPRESSED_PICTURE_ENCODE , 0 , 1 , 0 , 0 , 1); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_ORIGINAL_UNCOMPRESSED_PICTURE_DECODE , 0 , 1 , 0 , 0 , 1); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_STREAMOUT_DATA_CODEC , 0 , 1 , 0 , 0 , 1); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_INTRA_ROWSTORE_SCRATCH_BUFFER_CODEC , 1 , 1 , 0 , 0 , 1); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_DEBLOCKINGFILTER_ROWSTORE_SCRATCH_BUFFER_CODEC , 1 , 1 , 0 , 0 , 1); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_REFERENCE_PICTURE_CODEC , 0 , 1 , 0 , 0 , 1); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_MACROBLOCK_STATUS_BUFFER_CODEC , 0 , 1 , 0 , 0 , 1); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_MFX_INDIRECT_BITSTREAM_OBJECT_DECODE , 0 , 1 , 0 , 0 , 1); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_MFX_INDIRECT_MV_OBJECT_CODEC , 0 , 1 , 0 , 0 , 1); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_MFD_INDIRECT_IT_COEF_OBJECT_DECODE , 0 , 1 , 0 , 0 , 1); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_MFC_INDIRECT_PAKBASE_OBJECT_CODEC , 0 , 1 , 0 , 0 , 1); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_BSDMPC_ROWSTORE_SCRATCH_BUFFER_CODEC , 1 , 1 , 0 , 0 , 1); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_MPR_ROWSTORE_SCRATCH_BUFFER_CODEC , 1 , 1 , 0 , 0 , 1); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_BITPLANE_READ_CODEC , 0 , 1 , 0 , 0 , 1); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_AACSBIT_VECTOR_CODEC , 0 , 1 , 0 , 0 , 1); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_DIRECTMV_BUFFER_CODEC , 0 , 1 , 0 , 0 , 1); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_SURFACE_CURR_ENCODE , 1 , 1 , 1 , 0 , 1); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_SURFACE_REF_ENCODE , 1 , 1 , 1 , 0 , 1); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_SURFACE_HME_DOWNSAMPLED_ENCODE , 1 , 1 , 1 , 0 , 1); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_SURFACE_HME_DOWNSAMPLED_ENCODE_DST , 1 , 1 , 0 , 0 , 1); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_SURFACE_ME_DISTORTION_ENCODE , 1 , 1 , 1 , 0 , 1); #if defined(__linux__) && !defined(ANDROID) DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_SURFACE_MV_DATA_ENCODE , 1 , 1 , 0 , 0 , 1); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_SURFACE_BRC_ME_DISTORTION_ENCODE , 1 , 1 , 0 , 0 , 1); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_PAK_OBJECT_ENCODE , 1 , 1 , 0 , 0 , 1); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_SURFACE_FLATNESS_CHECK_ENCODE , 1 , 1 , 0 , 0 , 1); #else DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_SURFACE_MV_DATA_ENCODE , 1 , 1 , 1 , 0 , 1); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_SURFACE_BRC_ME_DISTORTION_ENCODE , 1 , 1 , 1 , 0 , 1); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_PAK_OBJECT_ENCODE , 1 , 1 , 1 , 0 , 1); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_SURFACE_FLATNESS_CHECK_ENCODE , 1 , 1 , 1 , 0 , 1); #endif DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_SURFACE_MBENC_CURBE_ENCODE , 1 , 1 , 1 , 0 , 1); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_VP8_BLOCK_MODE_COST_ENCODE , 1 , 1 , 1 , 0 , 1); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_VP8_MB_MODE_COST_ENCODE , 1 , 1 , 1 , 0 , 1); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_VP8_MBENC_OUTPUT_ENCODE , 1 , 1 , 0 , 0 , 1); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_VP8_HISTOGRAM_ENCODE , 1 , 1 , 1 , 0 , 1); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_VP8_L3_LLC_ENCODE , 1 , 1 , 1 , 0 , 1); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_HCP_MD_CODEC , 1 , 1 , 0 , 0 , 1); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_HCP_SAO_CODEC , 1 , 1 , 0 , 0 , 1); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_HCP_MV_CODEC , 1 , 1 , 0 , 0 , 1); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_SURFACE_MB_QP_CODEC , 1 , 1 , 1 , 0 , 1); /**********************************************************************************/ //OCL Usages DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_OCL_BUFFER , 1 , 1 , 1 , 0 , 1 ); // This case is used for cases where we have kernels compiled for BTI 253 (non-cohrent) and they are cacheline mis-aligned DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_OCL_BUFFER_CACHELINE_MISALIGNED , 1 , 1 , 0 , 0 , 1 ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_OCL_IMAGE , 1 , 1 , 1 , 0 , 1 ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_OCL_INLINE_CONST , 1 , 1 , 1 , 0 , 1 ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_OCL_SCRATCH , 1 , 1 , 1 , 0 , 1 ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_OCL_PRIVATE_MEM , 1 , 1 , 1 , 0 , 1 ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_OCL_PRINTF_BUFFER , 1 , 1 , 1 , 0 , 1 ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_OCL_STATE_HEAP_BUFFER , 1 , 1 , 1 , 0 , 1 ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_OCL_SYSTEM_MEMORY_BUFFER , 1 , 1 , 1 , 0 , 1 ); // This case is used for cases where we have kernels compiled for BTI 253 (non-cohrent) and they are cacheline mis-aligned DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_OCL_SYSTEM_MEMORY_BUFFER_CACHELINE_MISALIGNED , 1 , 1 , 0 , 0 , 1 ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_OCL_ISH_HEAP_BUFFER , 1 , 1 , 1 , 0 , 1 ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_OCL_TAG_MEMORY_BUFFER , 1 , 1 , 1 , 0 , 1 ); // Sampler overfetch issue is fixed on BDW /*Project: BDW:B0+ For SURFTYPE_BUFFER, SURFTYPE_1D, and SURFTYPE_2D non-array, non-MSAA, non-mip-mapped surfaces in linear memory, the only padding requirement is to the next aligned 64-byte boundary beyond the end of the surface. The rest of the padding requirements documented above do not apply to these surfaces.*/ DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_OCL_TEXTURE_BUFFER , 1 , 1 , 1 , 0 , 1 ); // Image from buffer when the image and buffer are on the kernel arguments list DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_OCL_IMAGE_FROM_BUFFER , 1 , 1 , 0 , 0 , 1 ); /**********************************************************************************/ // Cross Adapter DEFINE_CACHE_ELEMENT( GMM_RESOURCE_USAGE_XADAPTER_SHARED_RESOURCE , 0 , 0 , 0 , 0 , 0); /**********************************************************************************/ DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_CAMERA_CAPTURE , CAM$ , 0 , 0 , 0 , CAM$ ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_COPY_SOURCE , 0 , 0 , 0 , 0 , 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_COPY_DEST , 0 , 0 , 0 , 0 , 0); #include "GmmCachePolicyUndefineConditionals.h" gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/CachePolicy/GmmGen9CachePolicy.cpp000066400000000000000000000406011466655022700263120ustar00rootroot00000000000000/*============================================================================== Copyright(c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ============================================================================*/ #include "Internal/Common/GmmLibInc.h" #include "External/Common/GmmCachePolicy.h" //============================================================================= // // Function: __GmmGen9InitCachePolicy // // Desc: This function initializes the cache policy // // Parameters: pCachePolicy -> Ptr to array to be populated with the // mapping of usages -> cache settings. // // Return: GMM_STATUS // //----------------------------------------------------------------------------- GMM_STATUS GmmLib::GmmGen9CachePolicy::InitCachePolicy() { __GMM_ASSERTPTR(pCachePolicy, GMM_ERROR); #if defined(GMM_DYNAMIC_MOCS_TABLE) #define DEFINE_CACHE_ELEMENT(usage, llc, ellc, l3, age, i915) DEFINE_CP_ELEMENT(usage, llc, ellc, l3, 0, age, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) #else // i915 only supports three GEN9 MOCS entires: // MOCS[0]...LLC=0, ELLC=0, L3=0, AGE=0 // MOCS[1]... // MOCS[2]...LLC=1, ELLC=1, L3=1, AGE=3 #define DEFINE_CACHE_ELEMENT(usage, llc, ellc, l3, age, i915) \ do \ { \ if((i915) == 0) \ { \ DEFINE_CP_ELEMENT(usage, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);\ } \ else if((i915) == 2) \ { \ DEFINE_CP_ELEMENT(usage, 1, 1, 1, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);\ } \ else \ { \ GMM_ASSERTDPF(0, "Invalid i915 MOCS specified"); \ } \ } while(0) //////////////////////////////////////////////////////////////// #endif #include "GmmGen9CachePolicy.h" #define TC_LLC (1) #define TC_ELLC (0) #define TC_LLC_ELLC (2) #define LeCC_UNCACHEABLE (0x1) #define LeCC_WB_CACHEABLE (0x3) #define L3_UNCACHEABLE (0x1) #define L3_WB_CACHEABLE (0x3) #define DISABLE_SKIP_CACHING_CONTROL (0x0) #define ENABLE_SKIP_CACHING_CONTROL (0x1) { uint32_t CurrentMaxIndex = 0; GMM_CACHE_POLICY_TBL_ELEMENT *pCachePolicyTblElement = pGmmLibContext->GetCachePolicyTlbElement(); bool LLC = (pGmmLibContext->GetGtSysInfo()->LLCCacheSizeInKb > 0); // aka "Core -vs- Atom". #if defined(_WIN32) { pCachePolicyTblElement[0].L3.Cacheability = L3_UNCACHEABLE; pCachePolicyTblElement[0].LeCC.Cacheability = LeCC_UNCACHEABLE; pCachePolicyTblElement[0].LeCC.TargetCache = LLC ? TC_LLC_ELLC : TC_ELLC; // No LLC for Broxton, GLK - keep clear configuration for LLC } #else { #define I915_GEN9_MOCS_ENTRIES 3 GMM_CACHE_POLICY_TBL_ELEMENT *pEntry = pCachePolicyTblElement; C_ASSERT(I915_GEN9_MOCS_ENTRIES <= GMM_GEN9_MAX_NUMBER_MOCS_INDEXES); // I915_MOCS_UNCACHED(0)... pEntry[0].L3.Cacheability = L3_UNCACHEABLE; pEntry[0].LeCC.Cacheability = LeCC_UNCACHEABLE; pEntry[0].LeCC.TargetCache = TC_LLC_ELLC; // I915_MOCS_PTE(1)... pEntry[1] = pEntry[0]; // Unused by GmmLib clients, so set to UC. CurrentMaxIndex++; // I915_MOCS_CACHED(2)... pEntry[2].L3.Cacheability = L3_WB_CACHEABLE; pEntry[2].LeCC.Cacheability = LLC ? LeCC_WB_CACHEABLE : LeCC_UNCACHEABLE; pEntry[2].LeCC.TargetCache = TC_LLC_ELLC; pEntry[2].LeCC.LRUM = 3; CurrentMaxIndex++; } #endif // Process the cache policy and fill in the look up table for(uint32_t Usage = 0; Usage < GMM_RESOURCE_USAGE_MAX; Usage++) { bool CachePolicyError = false; uint64_t PTEValue = 0; int32_t CPTblIdx = -1; uint32_t j = 0; GMM_CACHE_POLICY_TBL_ELEMENT UsageEle = {0}; UsageEle.LeCC.Reserved = 0; // Reserved bits zeroe'd, this is so we // we can compare the unioned LeCC.DwordValue. UsageEle.LeCC.SCF = pCachePolicy[Usage].SCF; UsageEle.LeCC.PFM = 0; // TODO: decide what the page faulting mode should be UsageEle.LeCC.SCC = 0; UsageEle.LeCC.ESC = 0; if(pCachePolicy[Usage].LeCC_SCC) { UsageEle.LeCC.SCC = pCachePolicy[Usage].LeCC_SCC; UsageEle.LeCC.ESC = ENABLE_SKIP_CACHING_CONTROL; } UsageEle.LeCC.AOM = pCachePolicy[Usage].AOM; UsageEle.LeCC.LRUM = pCachePolicy[Usage].AGE; // default to LLC/ELLC target cache. UsageEle.LeCC.TargetCache = TC_LLC_ELLC; UsageEle.LeCC.Cacheability = LeCC_WB_CACHEABLE; if(pGmmLibContext->GetPlatformInfo().Platform.eProductFamily == IGFX_BROXTON || pGmmLibContext->GetPlatformInfo().Platform.eProductFamily == IGFX_GEMINILAKE) { UsageEle.LeCC.AOM = 0; UsageEle.LeCC.Cacheability = LeCC_UNCACHEABLE; // To avoid side effects use 01b even though 01b(UC) 11b(WB) are equivalent option #if defined(GMM_DYNAMIC_MOCS_TABLE) UsageEle.LeCC.TargetCache = TC_LLC; // No LLC for Broxton, but we still set it to LLC since it is needed for IA coherency cases UsageEle.LeCC.LRUM = 0; #else UsageEle.LeCC.TargetCache = TC_LLC_ELLC; // To match I915_GEN9_MOCS[0] #endif } else { if(pCachePolicy[Usage].LLC && pCachePolicy[Usage].ELLC) { UsageEle.LeCC.TargetCache = TC_LLC_ELLC; } else if(pCachePolicy[Usage].LLC) { UsageEle.LeCC.TargetCache = TC_LLC; } else if(pCachePolicy[Usage].ELLC) { UsageEle.LeCC.TargetCache = TC_ELLC; } else { UsageEle.LeCC.Cacheability = LeCC_UNCACHEABLE; } } UsageEle.L3.Reserved = 0; // Reserved bits zeroe'd, this is so we // we can compare the unioned L3.UshortValue. UsageEle.L3.ESC = DISABLE_SKIP_CACHING_CONTROL; UsageEle.L3.SCC = 0; UsageEle.L3.Cacheability = pCachePolicy[Usage].L3 ? L3_WB_CACHEABLE : L3_UNCACHEABLE; if(pCachePolicy[Usage].L3_SCC) { UsageEle.L3.ESC = ENABLE_SKIP_CACHING_CONTROL; UsageEle.L3.SCC = (uint16_t)pCachePolicy[Usage].L3_SCC; } for(j = 0; j <= CurrentMaxIndex; j++) { GMM_CACHE_POLICY_TBL_ELEMENT *TblEle = &pCachePolicyTblElement[j]; if(TblEle->LeCC.DwordValue == UsageEle.LeCC.DwordValue && TblEle->L3.UshortValue == UsageEle.L3.UshortValue) { CPTblIdx = j; break; } } // Didn't find the caching settings in one of the already programmed lookup table entries. // Need to add a new lookup table entry. if(CPTblIdx == -1) { if(CurrentMaxIndex < GMM_GEN9_MAX_NUMBER_MOCS_INDEXES - 1) { GMM_CACHE_POLICY_TBL_ELEMENT *TblEle = &(pCachePolicyTblElement[++CurrentMaxIndex]); CPTblIdx = CurrentMaxIndex; TblEle->LeCC.DwordValue = UsageEle.LeCC.DwordValue; TblEle->L3.UshortValue = UsageEle.L3.UshortValue; } else { // Too many unique caching combinations to program the // MOCS lookup table. CachePolicyError = true; GMM_ASSERTDPF( "Cache Policy Init Error: Invalid Cache Programming, too many unique caching combinations" "(we only support GMM_GEN_MAX_NUMBER_MOCS_INDEXES = %d)", GMM_GEN9_MAX_NUMBER_MOCS_INDEXES); // Set cache policy index to uncached. CPTblIdx = 0; } } if(!GetUsagePTEValue(pCachePolicy[Usage], Usage, &PTEValue)) { CachePolicyError = true; } pCachePolicy[Usage].PTE.DwordValue = PTEValue & 0xFFFFFFFF; pCachePolicy[Usage].PTE.HighDwordValue = 0; pCachePolicy[Usage].MemoryObjectOverride.Gen9.Index = CPTblIdx; pCachePolicy[Usage].Override = ALWAYS_OVERRIDE; if(CachePolicyError) { GMM_ASSERTDPF("Cache Policy Init Error: Invalid Cache Programming - Element %d", Usage); } } CurrentMaxMocsIndex = CurrentMaxIndex; CurrentMaxL1HdcMocsIndex = 0; } return GMM_SUCCESS; } ///////////////////////////////////////////////////////////////////////////////////// /// Initializes the Gfx PAT tables for AdvCtx and Gfx MMIO/Private PAT /// PAT0 = WB_COHERENT or UC depending on WaGttPat0WB /// PAT1 = UC or WB_COHERENT depending on WaGttPat0WB /// PAT2 = WB_MOCSLESS, with TC = eLLC+LLC /// PAT3 = WB /// PAT4 = WT /// PAT5 = WC /// PAT6 = WC /// PAT7 = WC /// HLD says to set to PAT0/1 to WC, but since we don't have a WC in GPU, /// WC option is same as UC. Hence setting PAT0 or PAT1 to UC. /// Unused PAT's (5,6,7) are set to WC. /// /// @return GMM_STATUS ///////////////////////////////////////////////////////////////////////////////////// GMM_STATUS GmmLib::GmmGen9CachePolicy::SetupPAT() { GMM_STATUS Status = GMM_SUCCESS; #if(defined(__GMM_KMD__)) uint32_t i = 0; GMM_GFX_MEMORY_TYPE GfxMemType = GMM_GFX_UC_WITH_FENCE; // No optional selection on Age or Target Cache because for an SVM-OS Age and // Target Cache would not work [for an SVM-OS the Page Table is shared with IA // and we don't have control of the PAT Idx]. If there is a strong ask from D3D // or the performance analysis team, Age could be added. // Add Class of Service when required. GMM_GFX_TARGET_CACHE GfxTargetCache = GMM_GFX_TC_ELLC_LLC; uint8_t Age = 1; uint8_t ServiceClass = 0; int32_t * pPrivatePATTableMemoryType = NULL; pPrivatePATTableMemoryType = pGmmLibContext->GetPrivatePATTableMemoryType(); __GMM_ASSERT(pGmmLibContext->GetSkuTable().FtrIA32eGfxPTEs); for(i = 0; i < GMM_NUM_GFX_PAT_TYPES; i++) { pPrivatePATTableMemoryType[i] = -1; } // Set values for GmmGlobalInfo PrivatePATTable for(i = 0; i < NumPATRegisters; i++) { GMM_PRIVATE_PAT PAT = {0}; if(pGmmLibContext->GetSkuTable().FtrMemTypeMocsDeferPAT) { GfxTargetCache = GMM_GFX_TC_ELLC_ONLY; } else { GfxTargetCache = GMM_GFX_TC_ELLC_LLC; } switch(i) { case PAT0: if(pGmmLibContext->GetWaTable().WaGttPat0) { if(pGmmLibContext->GetWaTable().WaGttPat0WB) { GfxMemType = GMM_GFX_WB; if(GFX_IS_ATOM_PLATFORM(pGmmLibContext)) { PAT.PreGen10.Snoop = 1; } pPrivatePATTableMemoryType[GMM_GFX_PAT_WB_COHERENT] = PAT0; } else { GfxMemType = GMM_GFX_UC_WITH_FENCE; pPrivatePATTableMemoryType[GMM_GFX_PAT_UC] = PAT0; } } else // if GTT is not tied to PAT0 then WaGttPat0WB is NA { GfxMemType = GMM_GFX_WB; if(GFX_IS_ATOM_PLATFORM(pGmmLibContext)) { PAT.PreGen10.Snoop = 1; } pPrivatePATTableMemoryType[GMM_GFX_PAT_WB_COHERENT] = PAT0; } break; case PAT1: if(pGmmLibContext->GetWaTable().WaGttPat0 && !pGmmLibContext->GetWaTable().WaGttPat0WB) { GfxMemType = GMM_GFX_WB; if(GFX_IS_ATOM_PLATFORM(pGmmLibContext)) { PAT.PreGen10.Snoop = 1; } pPrivatePATTableMemoryType[GMM_GFX_PAT_WB_COHERENT] = PAT1; } else { GfxMemType = GMM_GFX_UC_WITH_FENCE; pPrivatePATTableMemoryType[GMM_GFX_PAT_UC] = PAT1; } break; case PAT2: // This PAT idx shall be used for MOCS'Less resources like Page Tables // Page Tables have TC hardcoded to eLLC+LLC in Adv Ctxt. Hence making this to have same in Leg Ctxt. // For BDW-H, due to Perf issue, TC has to be eLLC only for Page Tables when eDRAM is present. GfxMemType = GMM_GFX_WB; GfxTargetCache = GMM_GFX_TC_ELLC_LLC; pPrivatePATTableMemoryType[GMM_GFX_PAT_WB_MOCSLESS] = PAT2; break; case PAT3: GfxMemType = GMM_GFX_WB; pPrivatePATTableMemoryType[GMM_GFX_PAT_WB] = PAT3; break; case PAT4: GfxMemType = GMM_GFX_WT; pPrivatePATTableMemoryType[GMM_GFX_PAT_WT] = PAT4; break; case PAT5: case PAT6: case PAT7: GfxMemType = GMM_GFX_WC; pPrivatePATTableMemoryType[GMM_GFX_PAT_WC] = PAT5; break; default: __GMM_ASSERT(0); Status = GMM_ERROR; } PAT.PreGen10.MemoryType = GfxMemType; PAT.PreGen10.TargetCache = GfxTargetCache; PAT.PreGen10.Age = Age; SetPrivatePATEntry(i, PAT); } #else Status = GMM_ERROR; #endif return Status; } gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/CachePolicy/GmmGen9CachePolicy.h000077500000000000000000000550261466655022700257710ustar00rootroot00000000000000/*============================================================================== Copyright(c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ============================================================================*/ #include "GmmCachePolicyConditionals.h" // true if edram is present #define EDRAM (_ELLC > MB(0)) // true if edram is present but not 128 MB (GT4e) #define GT3e (_ELLC > MB(0) && _ELLC < MB(128)) // true if edram is 128 MB #define GT4e (_ELLC == MB(128)) #define KBL_GT3e (PRODUCT(KABYLAKE) && GT3e) //eDRAM caching of displayables not supported on certain SKL CPUs #define DISP_IN_EDRAM (EDRAM && !pGmmLibContext->GetWaTable().WaDisableEdramForDisplayRT) //eDRAM-Only caching, for a usage that might be encrypted, must use ENCRYPTED_PARTIALS_EDRAM #define ENCRYPTED_PARTIALS_EDRAM (DISP_IN_EDRAM && !pGmmLibContext->GetWaTable().WaEncryptedEdramOnlyPartials) //eDRAM-only caching of unencrypted flip chains on SKL GT4 #define UNENCRYPTED_RT_EDRAM (DISP_IN_EDRAM && (!pGmmLibContext->GetWaTable().WaEncryptedEdramOnlyPartials || !GT3e)) // for SKL 3e we generally want EDRAM_ONLY mode (LLC=0,ELLC=1) = (!GT3e, EDRAM) // for SKL 4e we generally want "both" mode (LLC=1,ELLC=1) = (!GT3e, EDRAM) // i915 only supports three GEN9 MOCS entires: // MOCS[0]...LLC=0, ELLC=0, L3=0, AGE=0 // MOCS[1]... // MOCS[2]...LLC=1, ELLC=1, L3=1, AGE=3 #define UC 0 #define WB 2 //***************************************************************************************************************/ // USAGE TYPE , LLC , ELLC , L3 , AGE , i915) /****************************************************************************************************************/ // KMD Usages DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_BATCH_BUFFER , 0 , 0 , 0 , 0 , UC ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_COMP_FRAME_BUFFER , 0 , 0 , 0 , 0 , UC ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_CONTEXT_SWITCH_BUFFER , 0 , 0 , 0 , 0 , UC ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_CURSOR , 0 , 0 , 0 , 0 , UC ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_DISPLAY_STATIC_IMG_FOR_SMOOTH_ROTATION_BUFFER , 0 , 0 , 0 , 0 , UC ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_DUMMY_PAGE , 0 , 0 , 0 , 0 , UC ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_GDI_SURFACE , 1 , 1 , 1 , 3 , WB ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_GENERIC_KMD_RESOURCE , 0 , 0 , 0 , 0 , UC ); // GMM_RESOURCE_USAGE_GFX_RING is only used if WaEnableRingHostMapping is enabled. DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_GFX_RING , 0 , 0 , 0 , 0 , UC ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_GTT_TRANSFER_REGION , 0 , 0 , 0 , 0 , UC ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_HW_CONTEXT , 0 , 0 , 0 , 0 , UC ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_STATE_MANAGER_KERNEL_STATE , 0 , 0 , 0 , 0 , UC ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_KMD_STAGING_SURFACE , 1 , 1 , 1 , 3 , WB ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_MBM_BUFFER , 0 , 0 , 0 , 0 , UC ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_NNDI_BUFFER , 0 , 0 , 0 , 0 , UC ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_OVERLAY_MBM , 0 , DISP_IN_EDRAM, 0 , 0 , UC ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_PRIMARY_SURFACE , 0 , DISP_IN_EDRAM, 0 , 0 , UC ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_SCREEN_PROTECTION_INTERMEDIATE_SURFACE , 0 , 0 , 0 , 0 , UC ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_SHADOW_SURFACE , 1 , 1 , 1 , 3 , WB ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_SM_SCRATCH_STATE , 0 , 0 , 0 , 0 , UC ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_STATUS_PAGE , 1 , 1 , 1 , 3 , WB ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_TIMER_PERF_QUEUE , 0 , 0 , 0 , 0 , UC ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_UNKNOWN , 0 , 0 , 0 , 0 , UC ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_UNMAP_PAGING_RESERVED_GTT_DMA_BUFFER , 0 , 0 , 0 , 0 , UC ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_VSC_BATCH_BUFFER , 0 , 0 , 0 , 0 , UC ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_WA_BATCH_BUFFER , 0 , 0 , 0 , 0 , UC ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_KMD_OCA_BUFFER , 0 , 0 , 0 , 0 , UC ); // // 3D Usages // DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_UMD_BATCH_BUFFER , 0 , 0 , 0 ,0 , UC ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_BINDING_TABLE_POOL , !GT3e , EDRAM , 1 ,3 , WB ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_CCS , 0 , EDRAM , 1 ,3 , UC ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_CONSTANT_BUFFER_POOL , !GT3e , EDRAM , 1 ,3 , WB ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_DEPTH_BUFFER , !GT3e , EDRAM , 0 ,3 , WB ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_DISPLAYABLE_RENDER_TARGET , 0 , ENCRYPTED_PARTIALS_EDRAM , 0 ,3 , UC ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_GEN9_UNENCRYPTED_DISPLAYABLE , 0 , UNENCRYPTED_RT_EDRAM , 0 ,3 , UC ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_GATHER_POOL , 0 , EDRAM , 0 ,3 , UC ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_HEAP_SURFACE_STATE , !GT3e , EDRAM , 1 ,3 , WB ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_HEAP_DYNAMIC_STATE , !GT3e , EDRAM , 1 ,3 , WB ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_HEAP_GENERAL_STATE , !GT3e , EDRAM , 1 ,3 , WB ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_HEAP_GENERAL_STATE_UC , 0 , 0 , 0 ,3 , UC ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_HEAP_STATELESS_DATA_PORT , 1 , 1 , 1 ,3 , WB ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_HEAP_STATELESS_DATA_PORT_L1_CACHED , 1 , 1 , 1 ,3 , WB ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_HEAP_INDIRECT_OBJECT , 1 , 1 , 1 ,3 , WB ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_HEAP_INSTRUCTION , 1 , 1 , 1 ,3 , WB ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_HIZ , !GT3e , EDRAM , 1 ,3 , WB ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_INDEX_BUFFER , !GT3e , EDRAM , 1 ,3 , WB ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_MCS , 0 , EDRAM , 0 ,3 , UC ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_PUSH_CONSTANT_BUFFER , 0 , EDRAM , 0 ,3 , UC ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_PULL_CONSTANT_BUFFER , !GT3e , EDRAM , 1 ,3 , WB ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_QUERY , !GT3e , EDRAM , 0 ,3 , WB ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_RENDER_TARGET , !GT3e , EDRAM , 0 ,3 , WB ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_SHADER_RESOURCE , !GT3e , EDRAM , 1 ,3 , WB ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_STAGING , !GT3e , EDRAM , 0 ,3 , WB ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_STENCIL_BUFFER , !GT3e , EDRAM , 1 ,3 , WB ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_STREAM_OUTPUT_BUFFER , 0 , EDRAM , 0 ,3 , UC ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_TILE_POOL , !GT3e , EDRAM , 1 ,3 , WB ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_PROCEDURAL_TEXTURE , 0 , 0 , 0 ,0 , UC ); // Tiled Resource DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_TILED_DEPTH_BUFFER , !GT3e , EDRAM , 1 ,3 , WB ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_TILED_HIZ , !GT3e , EDRAM , 1 ,3 , WB ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_TILED_MCS , 0 , EDRAM , 0 ,3 , UC ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_TILED_CCS , 0 , EDRAM , 0 ,3 , UC ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_TILED_RENDER_TARGET , !GT3e , EDRAM , 1 ,3 , WB ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_TILED_RENDER_TARGET_AND_SHADER_RESOURCE , !GT3e , EDRAM , 1 ,3 , WB ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_TILED_SHADER_RESOURCE , !GT3e , EDRAM , 1 ,3 , WB ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_TILED_UAV , !GT3e , EDRAM , 1 ,3 , WB ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_UAV , !GT3e , EDRAM , 1 ,3 , WB ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_VERTEX_BUFFER , !GT3e , EDRAM , 0 ,1 , WB ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_OGL_WSTN_VERTEX_BUFFER , !GT3e, EDRAM , 0 ,3 , WB ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_RENDER_TARGET_AND_SHADER_RESOURCE , !GT3e , EDRAM , 1 ,3 , WB ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_RENDER_TARGET_AND_SHADER_RESOURCE_PARTIALENCSURFACES , !GT3e , ENCRYPTED_PARTIALS_EDRAM, 1, 3, WB ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_WDDM_HISTORY_BUFFER , 0 , EDRAM , 0 ,3 , UC ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_CONTEXT_SAVE_RESTORE , !GT3e , EDRAM , 1 ,3 , WB ); // // CM USAGES // DEFINE_CACHE_ELEMENT(CM_RESOURCE_USAGE_SurfaceState , 1 , 1 , 1 , 3 , WB ); DEFINE_CACHE_ELEMENT(CM_RESOURCE_USAGE_NO_L3_SurfaceState , 1 , 1 , 0 , 3 , WB ); DEFINE_CACHE_ELEMENT(CM_RESOURCE_USAGE_NO_LLC_ELLC_SurfaceState , 0 , 0 , 1 , 3 , UC ); DEFINE_CACHE_ELEMENT(CM_RESOURCE_USAGE_NO_LLC_SurfaceState , 0 , 1 , 1 , 3 , UC ); DEFINE_CACHE_ELEMENT(CM_RESOURCE_USAGE_NO_ELLC_SurfaceState , 1 , 0 , 1 , 3 , WB ); DEFINE_CACHE_ELEMENT(CM_RESOURCE_USAGE_NO_LLC_L3_SurfaceState , 0 , 1 , 0 , 3 , UC ); DEFINE_CACHE_ELEMENT(CM_RESOURCE_USAGE_NO_ELLC_L3_SurfaceState , 1 , 0 , 0 , 3 , WB ); DEFINE_CACHE_ELEMENT(CM_RESOURCE_USAGE_NO_CACHE_SurfaceState , 0 , 0 , 0 , 3 , UC ); // // MP USAGES // DEFINE_CACHE_ELEMENT(MP_RESOURCE_USAGE_BEGIN, 0 , 0 , 0 , 0, UC ); DEFINE_CACHE_ELEMENT(MP_RESOURCE_USAGE_DEFAULT, 0 , 0 , 0 , 0, UC ); DEFINE_CACHE_ELEMENT(MP_RESOURCE_USAGE_SurfaceState, 1 , EDRAM , 1 , 1, WB); DEFINE_CACHE_ELEMENT(MP_RESOURCE_USAGE_AGE3_SurfaceState, 1 , EDRAM , 1 , 3, WB); DEFINE_CACHE_ELEMENT(MP_RESOURCE_USAGE_No_L3_SurfaceState, 1 , EDRAM , 0 , 1, WB); DEFINE_CACHE_ELEMENT(MP_RESOURCE_USAGE_No_LLC_L3_SurfaceState, 0 , EDRAM , 0 , 1, UC); DEFINE_CACHE_ELEMENT(MP_RESOURCE_USAGE_No_LLC_L3_AGE_SurfaceState, 0 , EDRAM , 0 , 0, UC); DEFINE_CACHE_ELEMENT(MP_RESOURCE_USAGE_No_LLC_eLLC_L3_AGE_SurfaceState, 0 , 0 , 0 , 0, UC); DEFINE_CACHE_ELEMENT(MP_RESOURCE_USAGE_PartialEnc_No_LLC_L3_AGE_SurfaceState, 0 , ENCRYPTED_PARTIALS_EDRAM, 0 , 0, UC); DEFINE_CACHE_ELEMENT(MP_RESOURCE_USAGE_END, 0 , EDRAM , 0 , 0, UC ); // MHW - SFC DEFINE_CACHE_ELEMENT(MHW_RESOURCE_USAGE_Sfc_CurrentOutputSurface, 0 , EDRAM , 0 , 0, UC ); DEFINE_CACHE_ELEMENT(MHW_RESOURCE_USAGE_Sfc_CurrentOutputSurface_PartialEncSurface, 0 , ENCRYPTED_PARTIALS_EDRAM, 0, 0, UC ); DEFINE_CACHE_ELEMENT(MHW_RESOURCE_USAGE_Sfc_AvsLineBufferSurface, 1 , EDRAM , 1 , 1, WB ); DEFINE_CACHE_ELEMENT(MHW_RESOURCE_USAGE_Sfc_IefLineBufferSurface, 1 , EDRAM , 1 , 1, WB ); //Media GMM Resource USAGES DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_PRE_DEBLOCKING_CODEC , 0 , EDRAM , 0 , 3, UC ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_PRE_DEBLOCKING_CODEC_PARTIALENCSURFACE , 0 , ENCRYPTED_PARTIALS_EDRAM, 0, 3, UC ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_POST_DEBLOCKING_CODEC , 0 , EDRAM , 0 , 3, UC ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_ORIGINAL_UNCOMPRESSED_PICTURE_ENCODE , 0 , EDRAM , 0 , 3, UC ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_ORIGINAL_UNCOMPRESSED_PICTURE_DECODE , 0 , EDRAM , 0 , 3, UC ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_STREAMOUT_DATA_CODEC , 0 , EDRAM , 0 , 3, UC ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_INTRA_ROWSTORE_SCRATCH_BUFFER_CODEC , 1 , EDRAM , 0 , 3, WB ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_DEBLOCKINGFILTER_ROWSTORE_SCRATCH_BUFFER_CODEC , 1 , EDRAM , 0 , 3, WB ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_REFERENCE_PICTURE_CODEC , 1 , EDRAM , 0 , 1, WB ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_MACROBLOCK_STATUS_BUFFER_CODEC , 0 , EDRAM , 0 , 3, UC ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_MFX_INDIRECT_BITSTREAM_OBJECT_DECODE , 0 , EDRAM , 0 , 3, UC ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_MFX_INDIRECT_MV_OBJECT_CODEC , 0 , EDRAM , 0 , 3, UC ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_MFD_INDIRECT_IT_COEF_OBJECT_DECODE , 0 , EDRAM , 0 , 3, UC ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_MFC_INDIRECT_PAKBASE_OBJECT_CODEC , 0 , EDRAM , 0 , 3, UC ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_BSDMPC_ROWSTORE_SCRATCH_BUFFER_CODEC , 1 , EDRAM , 0 , 3, WB ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_MPR_ROWSTORE_SCRATCH_BUFFER_CODEC , 1 , EDRAM , 0 , 3, WB ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_BITPLANE_READ_CODEC , 0 , EDRAM , 0 , 3, UC ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_AACSBIT_VECTOR_CODEC , 0 , EDRAM , 0 , 3, UC ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_DIRECTMV_BUFFER_CODEC , 0 , EDRAM , 0 , 3, UC ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_SURFACE_CURR_ENCODE , 1 , EDRAM , 1 , 3, WB ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_SURFACE_REF_ENCODE , 1 , EDRAM , 1 , 3, WB ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_SURFACE_MV_DATA_ENCODE , 1 , EDRAM , 1 , 3, WB ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_SURFACE_HME_DOWNSAMPLED_ENCODE , 1 , EDRAM , 1 , 3, WB ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_SURFACE_HME_DOWNSAMPLED_ENCODE_DST , 1 , EDRAM , 0 , 3, WB ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_SURFACE_ME_DISTORTION_ENCODE , 1 , EDRAM , 1 , 3, WB ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_SURFACE_BRC_ME_DISTORTION_ENCODE , 1 , EDRAM , 1 , 3, WB ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_PAK_OBJECT_ENCODE , 1 , EDRAM , 1 , 3, WB ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_SURFACE_FLATNESS_CHECK_ENCODE , 1 , EDRAM , 1 , 3, WB ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_SURFACE_MBENC_CURBE_ENCODE , 1 , EDRAM , 1 , 3, WB ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_VDENC_ROW_STORE_BUFFER_CODEC , 1 , EDRAM , 0 , 3, WB ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_VDENC_STREAMIN_CODEC , 1 , EDRAM , 0 , 3, WB ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_SURFACE_MB_QP_CODEC , 1 , EDRAM , 1 , 3, WB ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_HCP_MD_CODEC , 1 , EDRAM , 0 , 3, WB ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_HCP_SAO_CODEC , 1 , EDRAM , 0 , 3, WB ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_HCP_MV_CODEC , 1 , EDRAM , 0 , 3, WB ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_HCP_STATUS_ERROR_CODEC , 0 , EDRAM , 0 , 3, UC ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_HCP_LCU_ILDB_STREAMOUT_CODEC , 0 , EDRAM , 0 , 3, UC ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_VP9_PROBABILITY_BUFFER_CODEC , 0 , EDRAM , 0 , 3, UC ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_VP9_SEGMENT_ID_BUFFER_CODEC , 0 , EDRAM , 0 , 3, UC ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_VP9_HVD_ROWSTORE_BUFFER_CODEC , 0 , EDRAM , 0 , 3, UC ); /**********************************************************************************/ // // OCL Usages // DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_OCL_BUFFER , 1 , 1 , 1 , 3 , WB ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_OCL_BUFFER_CSR_UC , 0 , 0 , 0 , 3 , UC ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_OCL_BUFFER_CACHELINE_MISALIGNED , 1 , 1 , 0 , 3 , UC ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_OCL_IMAGE , 1 , 1 , 1 , 3 , WB ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_OCL_INLINE_CONST , 1 , 1 , 1 , 3 , WB ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_OCL_SCRATCH , 1 , 1 , 1 , 3 , WB ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_OCL_PRIVATE_MEM , 1 , 1 , 1 , 3 , WB ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_OCL_PRINTF_BUFFER , 1 , 1 , 1 , 3 , WB ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_OCL_STATE_HEAP_BUFFER , 1 , 1 , 1 , 3 , WB ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_OCL_SYSTEM_MEMORY_BUFFER , 1 , 1 , 1 , 3 , WB ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_OCL_SYSTEM_MEMORY_BUFFER_CACHELINE_MISALIGNED , 1 , 1 , 0 , 3 , UC ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_OCL_ISH_HEAP_BUFFER , 1 , 1 , 1 , 3 , WB ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_OCL_TAG_MEMORY_BUFFER , 1 , 1 , 1 , 3 , WB ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_OCL_TEXTURE_BUFFER , 1 , 1 , 1 , 3 , WB ); // Image from buffer when the image and buffer are on the kernel arguments list DEFINE_CACHE_ELEMENT( GMM_RESOURCE_USAGE_OCL_IMAGE_FROM_BUFFER , 1 , 1 , 0 , 3 , WB ); DEFINE_CACHE_ELEMENT( GMM_RESOURCE_USAGE_OCL_BUFFER_NO_LLC_CACHING , 0 , 1 , 1 , 3 , UC ); DEFINE_CACHE_ELEMENT( GMM_RESOURCE_USAGE_OCL_IMAGE_NO_LLC_CACHING , 0 , 1 , 1 , 3 , UC ); /**********************************************************************************/ // Cross Adapter DEFINE_CACHE_ELEMENT( GMM_RESOURCE_USAGE_XADAPTER_SHARED_RESOURCE , 0 , 0 , 0 , 0, UC ); /**********************************************************************************/ DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_CAMERA_CAPTURE , CAM$, 0 , 0 , CAM$ , WB ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_COMMAND_STREAMER , 0 , 0 , 0 , 0 , UC ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_COPY_SOURCE , 0 , 0 , 0 , 0 , UC); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_COPY_DEST , 0 , 0 , 0 , 0 , UC); #undef UC #undef WB #include "GmmCachePolicyUndefineConditionals.h" gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/CachePolicy/GmmXe2_LPGCachePolicy.cpp000066400000000000000000000670351466655022700266620ustar00rootroot00000000000000/*============================================================================== Copyright(c) 2024 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ============================================================================*/ #include "Internal/Common/GmmLibInc.h" #include "External/Common/GmmCachePolicy.h" #include "External/Common/CachePolicy/GmmCachePolicyXe2_LPG.h" //============================================================================= // // Function: GmmXe2_LPGCachePolicy::InitCachePolicy() // // Desc: This function initializes the Xe2 cache policy // // Return: GMM_STATUS // //----------------------------------------------------------------------------- GMM_STATUS GmmLib::GmmXe2_LPGCachePolicy::InitCachePolicy() { __GMM_ASSERTPTR(pCachePolicy, GMM_ERROR); #define DEFINE_CACHE_ELEMENT(usage, l3_cc, l3_clos, l1cc, l2cc, l4cc, coherency, igPAT, segov) DEFINE_CP_ELEMENT(usage, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, segov, 0, 0, l1cc, l2cc, l4cc, coherency, l3_cc, l3_clos, igPAT) #include "GmmXe2_LPGCachePolicy.h" SetUpMOCSTable(); SetupPAT(); // Define index of cache element uint32_t Usage = 0; uint32_t ReservedPATIdx = 13; /* Rsvd PAT section 13-19 */ #if (_WIN32 && (_DEBUG || _RELEASE_INTERNAL)) void *pKmdGmmContext = NULL; #if (defined(__GMM_KMD__)) pKmdGmmContext = pGmmLibContext->GetGmmKmdContext(); #endif OverrideCachePolicy(pKmdGmmContext); #endif // Process the cache policy and fill in the look up table for (; Usage < GMM_RESOURCE_USAGE_MAX; Usage++) { bool CachePolicyError = false; int32_t PATIdx = -1, CPTblIdx = -1, PATIdxCompressed = -1, CoherentPATIdx = -1; uint32_t i, j; GMM_XE2_PRIVATE_PAT UsagePATElement = {0}; GMM_CACHE_POLICY_TBL_ELEMENT UsageEle = {0}; GMM_PTE_CACHE_CONTROL_BITS PTE = {0}; // MOCS data { // Get L3 ,L4 and Convert GMM indicative values to actual regiser values. GetL3L4(&UsageEle, &UsagePATElement, Usage); // Convert L1 GMM indicative values to actual regiser values and store into pCachePolicy to return to UMD's. SetL1CachePolicy(Usage); if ((!pGmmLibContext->GetSkuTable().FtrL3TransientDataFlush) && (UsageEle.L3.PhysicalL3.L3CC == GMM_GFX_PHY_L3_MT_WB_XD)) { UsageEle.L3.PhysicalL3.L3CC = GMM_GFX_PHY_L3_MT_WB; // No Transient Flush Support } /* If MOCS is not needed fall back to Defer to PAT i.e MOCS#0 */ if (false == UsageEle.L3.PhysicalL3.igPAT) { /* Set cache policy index to defered to PAT i.e. MOCS Index 0 */ CPTblIdx = 0; } else { /* MOCS Index 1-3 are valid */ for (j = 1; j <= CurrentMaxMocsIndex; j++) { GMM_CACHE_POLICY_TBL_ELEMENT *TblEle = &pGmmLibContext->GetCachePolicyTlbElement()[j]; if (UsageEle.L3.PhysicalL3.L4CC == TblEle->L3.PhysicalL3.L4CC && UsageEle.L3.PhysicalL3.L3CC == TblEle->L3.PhysicalL3.L3CC && UsageEle.L3.PhysicalL3.L3CLOS == TblEle->L3.PhysicalL3.L3CLOS && UsageEle.L3.PhysicalL3.igPAT == true) { CPTblIdx = j; break; } } } if (CPTblIdx == -1) { { /* Invalid MOCS setting Fail the GMM Initialzation */ GMM_ASSERTDPF(false, "CRITICAL: Cache Policy Usage value for L3/L4 specified by Client is not defined in Fixed MOCS Table"); CachePolicyError = true; } } } /* Validate Caching restrictions as below 1. MemoryType WB-XD must be used in Non-Coherent and allowed only for displayable surfaces 2. Coherent mode(1-way/2-way) must be Memory Type WB 3. No 2-way coherency on dGPU 4. Memory Type WT is available only for L4 in Non Coherent Mode 5. Memory Type UC must be used in Non-Coherent Mode */ // PAT data { if (!pGmmLibContext->GetSkuTable().FtrL3TransientDataFlush && (UsagePATElement.Xe2.L3CC == GMM_GFX_PHY_L3_MT_WB_XD)) { UsagePATElement.Xe2.L3CC = GMM_GFX_PHY_L3_MT_WB; // No Transient Flush Support } /* Find a PATIndex from the PAT table for uncompressed case*/ if ((UsagePATElement.Xe2.L4CC == GMM_GFX_PHY_L4_MT_WT) && (UsagePATElement.Xe2.L3CC == GMM_GFX_PHY_L3_MT_WB_XD)) { // With L3:XD, L4:WT, NC combination if (pGmmLibContext->GetSkuTable().FtrDiscrete) { // On BMG, L4 is a pass through, demote L4 to UC, keep L3 at XD PATIdx = PAT6; } else { // On LNL, L3:XD is not needed PATIdx = PAT13; } } else { for (i = 0; i <= CurrentMaxPATIndex; i++) { GMM_PRIVATE_PAT PAT = GetPrivatePATEntry(i); if (UsagePATElement.Xe2.L4CC == PAT.Xe2.L4CC && UsagePATElement.Xe2.Coherency == PAT.Xe2.Coherency && UsagePATElement.Xe2.L3CC == PAT.Xe2.L3CC && UsagePATElement.Xe2.L3CLOS == PAT.Xe2.L3CLOS && false == PAT.Xe2.LosslessCompressionEn) { PATIdx = i; break; } } } /* Find a PATIndex from the PAT table for compressed case*/ for (i = 0; i <= CurrentMaxPATIndex; i++) { GMM_PRIVATE_PAT PAT = GetPrivatePATEntry(i); if (UsagePATElement.Xe2.L4CC == PAT.Xe2.L4CC && UsagePATElement.Xe2.Coherency == PAT.Xe2.Coherency && UsagePATElement.Xe2.L3CC == PAT.Xe2.L3CC && UsagePATElement.Xe2.L3CLOS == PAT.Xe2.L3CLOS && true == PAT.Xe2.LosslessCompressionEn) { PATIdxCompressed = i; break; } } if (PATIdx == -1) { // Didn't find the caching settings in one of the already programmed PAT table entries. // Need to add a new lookup table entry. GMM_ASSERTDPF( "Cache Policy Init Error: Invalid Cache Programming, too many unique caching combinations" "(we only support NumPATRegisters = %d)", CurrentMaxPATIndex); CachePolicyError = true; PATIdx = GMM_PAT_ERROR; } /* Find a PATIndex for a coherent uncompressed case, if usage is 2-way or 1-way already, take that, otherwise search for oneway*/ if ((UsagePATElement.Xe2.Coherency == GMM_GFX_PHY_COHERENT_ONE_WAY_IA_SNOOP) || (UsagePATElement.Xe2.Coherency == GMM_GFX_PHY_COHERENT_TWO_WAY_IA_GPU_SNOOP)) { //Already coherent CoherentPATIdx = PATIdx; } else { // search for equivalent one way coherent index for (i = 0; i <= CurrentMaxPATIndex; i++) { GMM_PRIVATE_PAT PAT = GetPrivatePATEntry(i); if (UsagePATElement.Xe2.L4CC == PAT.Xe2.L4CC && UsagePATElement.Xe2.L3CC == PAT.Xe2.L3CC && UsagePATElement.Xe2.L3CLOS == PAT.Xe2.L3CLOS && GMM_GFX_PHY_COHERENT_ONE_WAY_IA_SNOOP == PAT.Xe2.Coherency) { if ((false == PAT.Xe2.LosslessCompressionEn) && (CoherentPATIdx == -1)) { CoherentPATIdx = i; } if (CoherentPATIdx != -1) { break; } } } if (CoherentPATIdx == -1) { //redo matching based on L3:UC, L4:UC, we should find one for (i = 0; i <= CurrentMaxPATIndex; i++) { GMM_PRIVATE_PAT PAT = GetPrivatePATEntry(i); if (GMM_GFX_PHY_L4_MT_UC == PAT.Xe2.L4CC && GMM_GFX_PHY_L3_MT_UC == PAT.Xe2.L3CC && UsagePATElement.Xe2.L3CLOS == PAT.Xe2.L3CLOS && GMM_GFX_PHY_COHERENT_ONE_WAY_IA_SNOOP == PAT.Xe2.Coherency) { if ((false == PAT.Xe2.LosslessCompressionEn) && (CoherentPATIdx == -1)) { CoherentPATIdx = i; } if (CoherentPATIdx != -1) { break; } } } } } } pCachePolicy[Usage].PATIndex = PATIdx; pCachePolicy[Usage].CoherentPATIndex = GET_COHERENT_PATINDEX_LOWER_BITS(CoherentPATIdx); // Coherent uncompressed lower bits pCachePolicy[Usage].CoherentPATIndexHigherBit = GET_COHERENT_PATINDEX_HIGHER_BIT(CoherentPATIdx); // Coherent uncompressed higher bits pCachePolicy[Usage].PATIndexCompressed = PATIdxCompressed; pCachePolicy[Usage].PTE.DwordValue = GMM_GET_PTE_BITS_FROM_PAT_IDX(PATIdx) & 0xFFFFFFFF; pCachePolicy[Usage].PTE.HighDwordValue = GMM_GET_PTE_BITS_FROM_PAT_IDX(PATIdx) >> 32; pCachePolicy[Usage].MemoryObjectOverride.XE_HP.Index = CPTblIdx; pCachePolicy[Usage].MemoryObjectOverride.XE_HP.EncryptedData = 0; pCachePolicy[Usage].Override = ALWAYS_OVERRIDE; if (CachePolicyError) { GMM_ASSERTDPF(false, "Cache Policy Init Error: Invalid Cache Programming "); return GMM_INVALIDPARAM; } } return GMM_SUCCESS; } //============================================================================= // // Function: __:GetL3L4 // // Desc: This function // converting GMM indicative values to actual register values // // Parameters: // // Return: GMM_STATUS // //----------------------------------------------------------------------------- void GmmLib::GmmXe2_LPGCachePolicy::GetL3L4(GMM_CACHE_POLICY_TBL_ELEMENT *pUsageEle, GMM_XE2_PRIVATE_PAT *pUsagePATElement, uint32_t Usage) { //MOCS pUsageEle->L3.PhysicalL3.Reserved0 = pUsageEle->L3.PhysicalL3.Reserved = 0; //L3CLOS pUsageEle->L3.PhysicalL3.L3CLOS = 0; //IgPAT pUsageEle->L3.PhysicalL3.igPAT = pCachePolicy[Usage].IgnorePAT; //PAT pUsagePATElement->Xe2.Reserved1 = 0; pUsagePATElement->Xe2.Reserved2 = 0; pUsagePATElement->Xe2.L3CLOS = 0; switch (pCachePolicy[Usage].L3CC) { case GMM_UC: pUsageEle->L3.PhysicalL3.L3CC = GMM_GFX_PHY_L3_MT_UC; pUsagePATElement->Xe2.L3CC = GMM_GFX_PHY_L3_MT_UC; break; case GMM_WB: pUsageEle->L3.PhysicalL3.L3CC = GMM_GFX_PHY_L3_MT_WB; pUsagePATElement->Xe2.L3CC = GMM_GFX_PHY_L3_MT_WB; break; case GMM_WBTD: pUsageEle->L3.PhysicalL3.L3CC = GMM_GFX_PHY_L3_MT_WB_XD; // Transient:Display on Xe2 pUsagePATElement->Xe2.L3CC = GMM_GFX_PHY_L3_MT_WB_XD; break; default: pUsageEle->L3.PhysicalL3.L3CC = GMM_GFX_PHY_L3_MT_UC; pUsagePATElement->Xe2.L3CC = GMM_GFX_PHY_L3_MT_UC; } switch (pCachePolicy[Usage].L4CC) { case GMM_UC: pUsageEle->L3.PhysicalL3.L4CC = GMM_GFX_PHY_L4_MT_UC; pUsagePATElement->Xe2.L4CC = GMM_GFX_PHY_L4_MT_UC; break; case GMM_WB: pUsageEle->L3.PhysicalL3.L4CC = GMM_GFX_PHY_L4_MT_WB; pUsagePATElement->Xe2.L4CC = GMM_GFX_PHY_L4_MT_WB; break; case GMM_WT: pUsageEle->L3.PhysicalL3.L4CC = GMM_GFX_PHY_L4_MT_WT; pUsagePATElement->Xe2.L4CC = GMM_GFX_PHY_L4_MT_WT; break; default: pUsageEle->L3.PhysicalL3.L4CC = GMM_GFX_PHY_L4_MT_UC; pUsagePATElement->Xe2.L4CC = GMM_GFX_PHY_L4_MT_UC; } switch (pCachePolicy[Usage].Coherency) { case GMM_NON_COHERENT_NO_SNOOP: pUsagePATElement->Xe2.Coherency = GMM_GFX_NON_COHERENT_NO_SNOOP; break; case GMM_COHERENT_ONE_WAY_IA_SNOOP: pUsagePATElement->Xe2.Coherency = GMM_GFX_COHERENT_ONE_WAY_IA_SNOOP; break; case GMM_COHERENT_TWO_WAY_IA_GPU_SNOOP: pUsagePATElement->Xe2.Coherency = GMM_GFX_COHERENT_TWO_WAY_IA_GPU_SNOOP; break; default: pUsagePATElement->Xe2.Coherency = GMM_GFX_NON_COHERENT_NO_SNOOP; break; } if (pGmmLibContext->GetWaTable().Wa_14018443005 && (pCachePolicy[Usage].L3CC == GMM_UC) && (ISWA_1401844305USAGE(Usage)) && (pGmmLibContext->GetClientType() != GMM_KMD_VISTA) && (pGmmLibContext->GetClientType() != GMM_OCL_VISTA)) { pUsageEle->L3.PhysicalL3.L3CC = GMM_GFX_PHY_L3_MT_WB; pUsagePATElement->Xe2.L3CC = GMM_GFX_PHY_L3_MT_WB; pCachePolicy[Usage].L3CC = GMM_WB; } } ///////////////////////////////////////////////////////////////////////////////////// /// A simple getter function returning the PAT (cache policy) for a given /// use Usage of the named resource pResInfo. /// Typically used to populate PPGTT/GGTT. /// /// @param[in] pResInfo: Resource info for resource, can be NULL. /// @param[in] Usage: Current usage for resource. /// @param[in] pCompressionEnabl: for Xe2 compression parameter /// @param[in] IsCpuCacheable: Indicates Cacheability /// @return PATIndex ///////////////////////////////////////////////////////////////////////////////////// uint32_t GMM_STDCALL GmmLib::GmmXe2_LPGCachePolicy::CachePolicyGetPATIndex(GMM_RESOURCE_INFO *pResInfo, GMM_RESOURCE_USAGE_TYPE Usage, bool *pCompressionEnable, bool IsCpuCacheable) { __GMM_ASSERT(pGmmLibContext->GetCachePolicyElement(Usage).Initialized); uint32_t PATIndex = pGmmLibContext->GetCachePolicyElement(Usage).PATIndex; GMM_CACHE_POLICY_ELEMENT TempElement = pGmmLibContext->GetCachePolicyElement(Usage); uint32_t TempCoherentPATIndex = 0; // This is to check if PATIndexCompressed, CoherentPATIndex are valid // Increment by 1 to have the rollover and value resets to 0 if the PAT in not valid. TempElement.PATIndexCompressed += 1; TempCoherentPATIndex = (uint32_t)GET_COHERENT_PATINDEX_VALUE(pGmmLibContext, Usage); // Higher bit of CoherentPATIndex would tell us if its a valid or not.0--> valid, 1-->invalid uint32_t CoherentPATIndex = (uint32_t)((GET_COHERENT_PATINDEX_HIGHER_BIT(TempCoherentPATIndex) == 1) ? GMM_PAT_ERROR : GET_COHERENT_PATINDEX_VALUE(pGmmLibContext, Usage)); //For PATIndexCompressed, rollover value would be 0 if its invalid uint32_t PATIndexCompressed = (uint32_t)(TempElement.PATIndexCompressed == 0 ? GMM_PAT_ERROR : pGmmLibContext->GetCachePolicyElement(Usage).PATIndexCompressed); uint32_t ReturnPATIndex = GMM_PAT_ERROR; bool CompressionEnable = (pCompressionEnable) ? *pCompressionEnable : false; // Prevent wrong Usage for XAdapter resources. UMD does not call GetMemoryObject on shader resources but, // when they add it someone could call it without knowing the restriction. if (pResInfo && pResInfo->GetResFlags().Info.XAdapter && (Usage != GMM_RESOURCE_USAGE_XADAPTER_SHARED_RESOURCE)) { __GMM_ASSERT(false); } #if (defined __linux__ || defined(WDDM_LINUX)) IsCpuCacheable = false; #endif // requested compressed and coherent if (CompressionEnable && IsCpuCacheable) { // return coherent uncompressed ReturnPATIndex = CoherentPATIndex; CompressionEnable = false; GMM_ASSERTDPF(false, "Coherent Compressed is not supported on Xe2. However, respecting the coherency and returning CoherentPATIndex"); } // requested compressed only else if (CompressionEnable) { if (GMM_PAT_ERROR != PATIndexCompressed) { // return compresed, may or may not coherent which depends on orinigal usage ReturnPATIndex = PATIndexCompressed; CompressionEnable = true; } else { // return original index ReturnPATIndex = PATIndex; CompressionEnable = false; } } // requested coherent only else if (IsCpuCacheable) { //return coherent uncompressed ReturnPATIndex = CoherentPATIndex; CompressionEnable = false; } /* Requested UnCompressed PAT */ else { if (GMM_PAT_ERROR != PATIndex) { ReturnPATIndex = PATIndex; CompressionEnable = false; } } /* No valid PAT Index found */ if (GMM_PAT_ERROR == ReturnPATIndex) { ReturnPATIndex = GMM_XE2_DEFAULT_PAT_INDEX; //default to uncached PAT index 2: GMM_CP_NON_COHERENT_UC CompressionEnable = false; __GMM_ASSERT(false); } if (pCompressionEnable) { *pCompressionEnable = CompressionEnable; } return ReturnPATIndex; } //============================================================================= // // Function: SetUpMOCSTable // // Desc: // // Parameters: // // Return: GMM_STATUS // //----------------------------------------------------------------------------- void GmmLib::GmmXe2_LPGCachePolicy::SetUpMOCSTable() { GMM_CACHE_POLICY_TBL_ELEMENT *pCachePolicyTlbElement = &(pGmmLibContext->GetCachePolicyTlbElement()[0]); #define L4_WB (0x0) #define L4_WT (0x1) #define L4_UC (0x3) #define L3_WB (0x0) #define L3_XD (pGmmLibContext->GetSkuTable().FtrL3TransientDataFlush ? 0x1 : 0x0) #define L3_UC (0x3) #define GMM_DEFINE_MOCS(indx, L4Caching, L3Caching, L3ClassOfService, ignorePAT) \ { \ pCachePolicyTlbElement[indx].L3.PhysicalL3.L4CC = L4Caching; \ pCachePolicyTlbElement[indx].L3.PhysicalL3.Reserved0 = 0; \ pCachePolicyTlbElement[indx].L3.PhysicalL3.L3CC = L3Caching; \ pCachePolicyTlbElement[indx].L3.PhysicalL3.L3CLOS = L3ClassOfService; \ pCachePolicyTlbElement[indx].L3.PhysicalL3.igPAT = ignorePAT; \ } // clang-format off // Default MOCS Table for(uint32_t j = 0; j < GMM_XE2_NUM_MOCS_ENTRIES; j++) { // Index CachingPolicy L3Caching L3ClassOfService ignorePAT GMM_DEFINE_MOCS( j, L4_UC, L3_UC, 0 , 0 ) } // Index L4 CachingPolicy L3 CachingPolicy L3 CLOS ignorePAT GMM_DEFINE_MOCS( 0 , L4_UC , L3_WB , 0 , 0) // Defer to PAT GMM_DEFINE_MOCS( 1 , L4_UC , L3_WB , 0 , 1) // L3 GMM_DEFINE_MOCS( 2 , L4_WB , L3_UC , 0 , 1) // L4 GMM_DEFINE_MOCS( 3 , L4_UC , L3_UC , 0 , 1) // UC GMM_DEFINE_MOCS( 4 , L4_WB , L3_WB , 0 , 1) // L3+L4 CurrentMaxMocsIndex = 4; CurrentMaxL1HdcMocsIndex = 0; CurrentMaxSpecialMocsIndex = 0; // clang-format on #undef GMM_DEFINE_MOCS #undef L4_WB #undef L4_WT #undef L4_UC #undef L3_WB #undef L3_XD #undef L3_UC } //============================================================================= // // Function: SetupPAT // // Desc: // // Parameters: // // Return: GMM_STATUS // //----------------------------------------------------------------------------- GMM_STATUS GmmLib::GmmXe2_LPGCachePolicy::SetupPAT() { GMM_PRIVATE_PAT *pPATTlbElement = &(pGmmLibContext->GetPrivatePATTable()[0]); #define L4_WB (0x0) #define L4_WT (0x1) #define L4_UC (0x3) #define L3_WB (0x0) #define L3_XD (pGmmLibContext->GetSkuTable().FtrL3TransientDataFlush ? 0x1 : 0x0) #define L3_UC (0x3) #define L3_XA (0x2) // WB Transient App #define GMM_DEFINE_PAT_ELEMENT(indx, Coh, L4Caching, L3Caching, L3ClassOfService, CompressionEn, NoCachePromote) \ { \ pPATTlbElement[indx].Xe2.Coherency = Coh; \ pPATTlbElement[indx].Xe2.L4CC = L4Caching; \ pPATTlbElement[indx].Xe2.Reserved1 = 0; \ pPATTlbElement[indx].Xe2.Reserved2 = 0; \ pPATTlbElement[indx].Xe2.L3CC = L3Caching; \ pPATTlbElement[indx].Xe2.L3CLOS = L3ClassOfService; \ pPATTlbElement[indx].Xe2.LosslessCompressionEn = CompressionEn; \ pPATTlbElement[indx].Xe2.NoCachingPromote = NoCachePromote; \ } // clang-format off // Default PAT Table // 32 nos for (uint32_t i = 0; i < (NumPATRegisters); i++) { // Index Coherency CachingPolicy L3Caching L3ClassOfService CompressionEn NoCachingPromote GMM_DEFINE_PAT_ELEMENT( i, 3, L4_UC, L3_UC, 0, 0, 0); } // Fixed PAT Table // Index Coherency L4 CachingPolicy L3 CachingPolicy L3 CLOS CompressionEn NoCachingPromote //Group: GGT/PPGTT[4] GMM_DEFINE_PAT_ELEMENT( 0 , 0 , L4_UC , L3_WB , 0 , 0 , 0) // | L3_WB GMM_DEFINE_PAT_ELEMENT( 1 , 2 , L4_UC , L3_WB , 0 , 0 , 0) // | L3_WB | 1 way coherent GMM_DEFINE_PAT_ELEMENT( 2 , 3 , L4_UC , L3_WB , 0 , 0 , 0) // | L3_WB | 2 way coherent GMM_DEFINE_PAT_ELEMENT( 3 , 0 , L4_UC , L3_UC , 0 , 0 , 0) // **UC //Group: 1 way Coh GMM_DEFINE_PAT_ELEMENT( 4 , 2 , L4_WB , L3_UC , 0 , 0 , 0) // L4_WB | 1 way coherent GMM_DEFINE_PAT_ELEMENT( 5 , 2 , L4_UC , L3_UC , 0 , 0 , 0) // **UC | 1 way coherent //Group: Compression Disabled GMM_DEFINE_PAT_ELEMENT( 6 , 0 , L4_UC , L3_XD , 0 , 0 , 1) // | L3_XD GMM_DEFINE_PAT_ELEMENT( 7 , 3 , L4_WB , L3_UC , 0 , 0 , 0) // L4_WB | 2 way coherent GMM_DEFINE_PAT_ELEMENT( 8 , 0 , L4_WB , L3_UC , 0 , 0 , 0) // L4_WB //Group: Compression Enabled GMM_DEFINE_PAT_ELEMENT( 9 , 0 , L4_UC , L3_WB , 0 , 1 , 0) // | L3_WB | Comp GMM_DEFINE_PAT_ELEMENT( 10 , 0 , L4_WB , L3_UC , 0 , 1 , 0) // L4_WB | Comp GMM_DEFINE_PAT_ELEMENT( 11 , 0 , L4_UC , L3_XD , 0 , 1 , 1) // | L3_XD | Comp GMM_DEFINE_PAT_ELEMENT( 12 , 0 , L4_UC , L3_UC , 0 , 1 , 0) // **UC | Comp GMM_DEFINE_PAT_ELEMENT( 13 , 0 , L4_WB , L3_WB , 0 , 0 , 0) // L4_WB | L3_WB GMM_DEFINE_PAT_ELEMENT( 14 , 0 , L4_WB , L3_WB , 0 , 1 , 0) // L4_WB | L3_WB | Comp GMM_DEFINE_PAT_ELEMENT( 15 , 0 , L4_WT , L3_XD , 0 , 1 , 1) // L4_WT | L3_XD | Comp //Reserved 16-19 //Group: CLOS1 GMM_DEFINE_PAT_ELEMENT( 20 , 0 , L4_UC , L3_WB , 1 , 0 , 0) // | L3_WB GMM_DEFINE_PAT_ELEMENT( 21 , 0 , L4_UC , L3_WB , 1 , 1 , 0) // | L3_WB | Comp GMM_DEFINE_PAT_ELEMENT( 22 , 2 , L4_UC , L3_WB , 1 , 0 , 0) // | L3_WB | 1 way coherent GMM_DEFINE_PAT_ELEMENT( 23 , 3 , L4_UC , L3_WB , 1 , 0 , 0) // | L3_WB | 2 way coherent //Group:CLOS2=>Clone of CLOS1 GMM_DEFINE_PAT_ELEMENT( 24 , 0 , L4_UC , L3_WB , 2 , 0 , 0) // | L3_WB GMM_DEFINE_PAT_ELEMENT( 25 , 0 , L4_UC , L3_WB , 2 , 1 , 0) // | L3_WB | Comp GMM_DEFINE_PAT_ELEMENT( 26 , 2 , L4_UC , L3_WB , 2 , 0 , 0) // | L3_WB | 1 way coherent GMM_DEFINE_PAT_ELEMENT( 27 , 3 , L4_UC , L3_WB , 2 , 0 , 0) // | L3_WB | 2 way coherent //Group:CLOS3=>Clone of CLOS1 GMM_DEFINE_PAT_ELEMENT( 28 , 0 , L4_UC , L3_WB , 3 , 0 , 0) // | L3_WB GMM_DEFINE_PAT_ELEMENT( 29 , 0 , L4_UC , L3_WB , 3 , 1 , 0) // | L3_WB | Comp GMM_DEFINE_PAT_ELEMENT( 30 , 2 , L4_UC , L3_WB , 3 , 0 , 0) // | L3_WB | 1 way coherent GMM_DEFINE_PAT_ELEMENT( 31 , 3 , L4_UC , L3_WB , 3 , 0 , 0) // | L3_WB | 2 way coherent CurrentMaxPATIndex = 31; // clang-format on #undef GMM_DEFINE_PAT #undef L4_WB #undef L4_WT #undef L4_UC #undef L3_WB #undef L3_XD #undef L3_UC return GMM_SUCCESS; } gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/CachePolicy/GmmXe2_LPGCachePolicy.h000066400000000000000000000736371466655022700263340ustar00rootroot00000000000000/*============================================================================== Copyright(c) 2024 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ============================================================================*/ #include "GmmCachePolicyConditionals.h" #define _SN 0x1 #define _IA_GPU_SN 0x2 #define _WT 0x2 #define _L1_WB 0x2 #define dGPU SKU(FtrDiscrete) #if (_DEBUG || _RELEASE_INTERNAL) #define _WA_WB_Emu (WA(Wa_EmuMufasaSupportOnBmg)) #else #define _WA_WB_Emu 0 #endif // GmmLib can apply 2Way WA to GMM_RESOURCE_USAGE_HW_CONTEXT. #define _WA_2W (WA(Wa_14018976079) || WA(Wa_14018984349)) ? 2 : 0 #define _L3_P ((_WA_2W == 2) ? 1 : 0) // L3 Promotion to WB if 2Way Coh WA is set // clang-format off //typedef enum GMM_CACHING_POLICY_REC //{ // GMM_UC = 0x0, //uncached // GMM_WB = 0x1, // Write back // GMM_WT = 0x2, // write-through // GMM_WBTD = 0x3, // WB_T_Display // GMM_WBTA = 0x4, // WB_T_App // GMM_WBP = 0x5, // write bypass mode // GMM_WS = 0x6, // Write-Streaming //} GMM_CACHING_POLICY; // // typedef enum GMM_COHERENCY_TYPE_REC //{ //GMM_NON_COHERENT_NO_SNOOP = 0x0, //GMM_COHERENT_ONE_WAY_IA_SNOOP = 0x1, //GMM_COHERENT_TWO_WAY_IA_GPU_SNOOP = 0x2 //} GMM_COHERENCY_TYPE; // Cache Policy Definition // L3_CLOS : L3 class of service (0,1,2,3) // IgPAT : Ignore PAT 1 = Override by MOCS, 0 = Defer to PAT //Macros for segment-preference #define NoP 0x0 //Wa_14018443005 #define COMPRESSED_PAT_WITH_L4WB_L3UC_0 PAT10 #define COMPRESSED_PAT_WITH_L4WB_L3WB_0 PAT14 #define COMPRESSED_PAT_WITH_L4UC_L3UC_0 PAT12 #define COMPRESSED_PAT_WITH_L4UC_L3WB_0 PAT9 #define ISWA_1401844305USAGE(usage) ((Usage == GMM_RESOURCE_USAGE_BLT_SOURCE) || \ (Usage == GMM_RESOURCE_USAGE_BLT_DESTINATION) || \ (Usage == GMM_RESOURCE_USAGE_COPY_SOURCE) || \ (Usage == GMM_RESOURCE_USAGE_COPY_DEST)) //******************************************************************************************************************************************************************/ // USAGE TYPE L3_CC, L3_CLOS, L1CC, L2CC, L4CC, Coherency, IgPAT, SegOv) /*******************************************************************************************************************************************************************/ // KMD Usages DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_BATCH_BUFFER , 0, 0, 0, 0 , 0 , 0 , 1, NoP); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_COMP_FRAME_BUFFER , 0, 0, 0, 0 , 0 , 0 , 1, NoP); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_CONTEXT_SWITCH_BUFFER , 0, 0, 0, 0 , 0 , 0 , 1, NoP); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_CURSOR , 3, 0, 0, 0 , 0 , 0 , 0, NoP); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_DISPLAY_STATIC_IMG_FOR_SMOOTH_ROTATION_BUFFER , 3, 0, 0, 0 , 0 , 0 , 0, NoP); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_DUMMY_PAGE , 0, 0, 0, 0 , 0 , 0 , 1, NoP); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_GDI_SURFACE , 1, 0, 0, 0 , 0 , 0 , 1, NoP); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_GENERIC_KMD_RESOURCE , 1, 0, 0, 0 , 0 , _WA_2W, 1, NoP); // GMM_RESOURCE_USAGE_GFX_RING is only used if WaEnableRingHostMapping is enabled . DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_GFX_RING , 0, 0, 0, 0 , 0 , 0 , 1, NoP); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_GTT_TRANSFER_REGION , 0, 0, 0, 0 , 0 , 0 , 1, NoP); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_HW_CONTEXT , 1, 0, 0, 0 , 0 , _WA_2W, 1, NoP); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_STATE_MANAGER_KERNEL_STATE , 0, 0, 0, 0 , 0 , 0 , 1, NoP); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_KMD_STAGING_SURFACE , 1, 0, 0, 0 , 0 , 0 , 1, NoP); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_MBM_BUFFER , 0, 0, 0, 0 , 0 , 0 , 1, NoP); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_NNDI_BUFFER , 0, 0, 0, 0 , 0 , 0 , 1, NoP); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_OVERLAY_MBM , 0, 0, 0, 0 , 0 , 0 , 1, NoP); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_PRIMARY_SURFACE , 3, 0, 0, 0 , 0 , 0 , 0, NoP); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_SCREEN_PROTECTION_INTERMEDIATE_SURFACE , 0, 0, 0, 0 , 0 , 0 , 1, NoP); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_SHADOW_SURFACE , 1, 0, 0, 0 , 0 , 0 , 1, NoP); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_SM_SCRATCH_STATE , 0, 0, 0, 0 , 0 , 0 , 1, NoP); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_STATUS_PAGE , 1, 0, 0, 0 , 0 , 0 , 1, NoP); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_TIMER_PERF_QUEUE , 0, 0, 0, 0 , 0 , 0 , 1, NoP); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_UNKNOWN , 0, 0, 0, 0 , 0 , 0 , 1, NoP); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_UNMAP_PAGING_RESERVED_GTT_DMA_BUFFER , 0, 0, 0, 0 , 0 , 0 , 1, NoP); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_VSC_BATCH_BUFFER , 0, 0, 0, 0 , 0 , 0 , 1, NoP); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_WA_BATCH_BUFFER , 0, 0, 0, 0 , 0 , 0 , 1, NoP); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_KMD_OCA_BUFFER , 0, 0, 0, 0 , 0 , 0 , 1, NoP); // // 3D Usages // // USAGE TYPE L3_CC, L3_CLOS,L1CC, L2CC, L4CC, Coherency , IgPAT) DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_TILED_DEPTH_BUFFER , 1, 0, 0, 0 , 0 , 0 , 1, NoP); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_TILED_HIZ , 1, 0, 0, 0 , 0 , 0 , 1, NoP); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_UMD_BATCH_BUFFER , 0, 0, 0, 0 , 0 , 0 , 1, NoP); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_BINDING_TABLE_POOL , 1, 0, 0, 0 , 0 , 0 , 1, NoP); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_CCS , 0, 0, 0, 0 , 0 , 0 , 1, NoP); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_CONSTANT_BUFFER_POOL , 1, 0, 0, 0 , 0 , 0 , 1, NoP); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_DEPTH_BUFFER , 1, 0, 0, 0 , 0 , 0 , 1, NoP); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_DISPLAYABLE_RENDER_TARGET , 3, 0, 0, 0 , 0 , 0 , 0, NoP); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_GATHER_POOL , 1, 0, 0, 0 , 0 , 0 , 1, NoP); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_HEAP_SURFACE_STATE , 1, 0, 0, 0 , 0 , 0 , 1, NoP); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_HEAP_DYNAMIC_STATE , 1, 0, 0, 0 , 0 , 0 , 1, NoP); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_HEAP_GENERAL_STATE , 1, 0, 0, 0 , 0 , 0 , 1, NoP); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_HEAP_GENERAL_STATE_UC , 0, 0, 0, 0 , 0 , 0 , 1, NoP); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_HEAP_STATELESS_DATA_PORT , 1, 0, 0, 0 , 0 , 0 , 1, NoP); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_HEAP_STATELESS_DATA_PORT_L1_CACHED , 1, 0, 1, 0 , 0 , 0 , 1, NoP); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_HEAP_INDIRECT_OBJECT , 1, 0, 0, 0 , 0 , 0 , 1, NoP); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_HEAP_INSTRUCTION , 1, 0, 0, 0 , 0 , 0 , 1, NoP); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_HIZ , 1, 0, 0, 0 , 0 , 0 , 1, NoP); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_INDEX_BUFFER , 1, 0, 0, 0 , 0 , 0 , 1, NoP); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_INDEX_BUFFER_L3_COHERENT_UC , 0, 0, 0, 0 , 0 , 0 , 1, NoP); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_INDEX_BUFFER_L3_CACHED , 1, 0, 0, 0 , 0 , 0 , 1, NoP); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_MCS , 1, 0, 0, 0 , 0 , 0 , 1, NoP); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_PUSH_CONSTANT_BUFFER , 1, 0, 0, 0 , 0 , 0 , 1, NoP); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_PULL_CONSTANT_BUFFER , 1, 0, 5, 0 , 0 , 0 , 1, NoP); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_QUERY , _WA_WB_Emu, 0, 0, 0 , 0 , 1 , 1, NoP); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_RENDER_TARGET , 1, 0, 0, 0 , 0 , 0 , 1, NoP); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_SHADER_RESOURCE , 1, 0, 5, 0 , 0 , 0 , 1, NoP); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_STAGING , _WA_WB_Emu, 0, 0, 0 , 0 , 1 , 1, NoP); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_STENCIL_BUFFER , 1, 0, 0, 0 , 0 , 0 , 1, NoP); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_STREAM_OUTPUT_BUFFER , 1, 0, 0, 0 , 0 , 0 , 1, NoP); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_TILE_POOL , 1, 0, 0, 0 , 0 , 0 , 1, NoP); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_SHADER_RESOURCE_LLC_BYPASS , 1, 0, 5, 0 , 0 , 0 , 1, NoP); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_MOCS_62 , 0, 0, 0, 0 , 0 , 0 , 1, NoP); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_L3_EVICTION , 0, 0, 0, 0 , 0 , 0 , 1, NoP); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_L3_EVICTION_SPECIAL , 0, 0, 0, 0 , 0 , 0 , 1, NoP); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_UMD_OCA_BUFFER , 0, 0, 0, 0 , 0 , 0 , 1, NoP); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_PROCEDURAL_TEXTURE , 1, 0, 0, 0 , 0 , 0 , 1, NoP); // Tiled Resource // // USAGE TYPE L3_CC, L3_CLOS,L1CC, L2CC, L4CC, Coherency, IgPAT) DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_TILED_DEPTH_BUFFER , 1, 0, 0, 0 , 0 , 0 , 1, NoP); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_TILED_HIZ , 1, 0, 0, 0 , 0 , 0 , 1, NoP); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_TILED_MCS , 1, 0, 0, 0 , 0 , 0 , 1, NoP); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_TILED_CCS , 1, 0, 0, 0 , 0 , 0 , 1, NoP); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_TILED_RENDER_TARGET , 1, 0, 0, 0 , 0 , 0 , 1, NoP); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_TILED_RENDER_TARGET_AND_SHADER_RESOURCE , 1, 0, 5, 0 , 0 , 0 , 1, NoP); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_TILED_SHADER_RESOURCE , 1, 0, 5, 0 , 0 , 0 , 1, NoP); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_TILED_UAV , 1, 0, 0, 0 , 0 , 0 , 1, NoP); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_UAV , 1, 0, 0, 0 , 0 , 0 , 1, NoP); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_VERTEX_BUFFER , 1, 0, 0, 0 , 0 , 0 , 1, NoP); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_VERTEX_BUFFER_L3_COHERENT_UC , 0, 0, 0, 0 , 0 , 0 , 1, NoP); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_VERTEX_BUFFER_L3_CACHED , 1, 0, 0, 0 , 0 , 0 , 1, NoP); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_OGL_WSTN_VERTEX_BUFFER , 1, 0, 0, 0 , 0 , 0 , 1, NoP); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_POSH_VERTEX_BUFFER , 1, 0, 0, 0 , 0 , 0 , 1, NoP); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_RENDER_TARGET_AND_SHADER_RESOURCE , 1, 0, 5, 0 , 0 , 0 , 1, NoP); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_WDDM_HISTORY_BUFFER , 1, 0, 0, 0 , 0 , 0 , 1, NoP); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_CONTEXT_SAVE_RESTORE , 1, 0, 0, 0 , 0 , 0 , 1, NoP); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_PTBR_PAGE_POOL , 1, 0, 0, 0 , 0 , 0 , 1, NoP); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_PTBR_BATCH_BUFFER , 1, 0, 0, 0 , 0 , 0 , 1, NoP); // // CM USAGES // // USAGE TYPE L3_CC, L3_CLOS,L1CC, L2CC, L4CC, Coherency, IgPAT) DEFINE_CACHE_ELEMENT(CM_RESOURCE_USAGE_SurfaceState, 1, 0, 0, 0 , 1 , 0 , 1, NoP); DEFINE_CACHE_ELEMENT(CM_RESOURCE_USAGE_L1_Enabled_SurfaceState, 1, 0, 1, 0 , 1 , 0 , 1, NoP); DEFINE_CACHE_ELEMENT(CM_RESOURCE_USAGE_StateHeap, 1, 0, 0, 0 , 1 , 0 , 1, NoP); DEFINE_CACHE_ELEMENT(CM_RESOURCE_USAGE_NO_L3_SurfaceState, 0, 0, 0, 0 , 1 , 0 , 1, NoP); DEFINE_CACHE_ELEMENT(CM_RESOURCE_USAGE_NO_CACHE_SurfaceState, 0, 0, 0, 0 , 0 , 0 , 1, NoP); // // MP USAGES // // USAGE TYPE L3_CC, L3_CLOS,L1CC, L2CC, L4CC, Coherency, IgPAT ) DEFINE_CACHE_ELEMENT(MP_RESOURCE_USAGE_BEGIN, 0, 0, 0, 0 , 0 , 0 , 1, NoP); DEFINE_CACHE_ELEMENT(MP_RESOURCE_USAGE_DEFAULT, 0, 0, 0, 0 , 0 , 0 , 1, NoP); DEFINE_CACHE_ELEMENT(MP_RESOURCE_USAGE_DEFAULT_FF, 0, 0, 0, 0 , 0 , 0 , 1, NoP); DEFINE_CACHE_ELEMENT(MP_RESOURCE_USAGE_DEFAULT_RCS, 0, 0, 0, 0 , 0 , 0 , 1, NoP); DEFINE_CACHE_ELEMENT(MP_RESOURCE_USAGE_SurfaceState, 1, 0, 0, 0 , 1 , 0 , 1, NoP); DEFINE_CACHE_ELEMENT(MP_RESOURCE_USAGE_SurfaceState_FF, 0, 0, 0, 0 , 0 , 0 , 1, NoP); DEFINE_CACHE_ELEMENT(MP_RESOURCE_USAGE_SurfaceState_RCS, 1, 0, 0, 0 , 1 , 0 , 1, NoP); DEFINE_CACHE_ELEMENT(MP_RESOURCE_USAGE_END, 0, 0, 0, 0 , 0 , 0 , 1, NoP); // MHW - SFC // USAGE TYPE , L3_CC, L3_CLOS,L1CC, L2CC, L4CC, Coherency, IgPAT) DEFINE_CACHE_ELEMENT(MHW_RESOURCE_USAGE_Sfc_CurrentOutputSurface, 0, 0, 0, 0 , 0 , 0 , 1, NoP); DEFINE_CACHE_ELEMENT(MHW_RESOURCE_USAGE_Sfc_AvsLineBufferSurface, 0, 0, 0, 0 , 0 , 0 , 1, NoP); DEFINE_CACHE_ELEMENT(MHW_RESOURCE_USAGE_Sfc_IefLineBufferSurface, 0, 0, 0, 0 , 0 , 0 , 1, NoP); /**********************************************************************************/ // // OCL Usages // // USAGE TYPE L3_CC, L3_CLOS,L1CC, L2CC, L4CC, Coherency , IgPAT) DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_OCL_BUFFER , 1, 0, 0, 0 , 0 , 0 , 1, NoP); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_OCL_BUFFER_CONST , 1, 0, 5, 0 , 0 , 0 , 1, NoP); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_OCL_BUFFER_CSR_UC , 0, 0, 0, 0 , 0 , 0 , 1, NoP); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_OCL_BUFFER_CACHELINE_MISALIGNED , 0, 0, 0, 0 , 0 , 0 , 1, NoP); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_OCL_IMAGE , 1, 0, 0, 0 , 0 , 0 , 1, NoP); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_OCL_INLINE_CONST , 1, 0, 0, 0 , 0 , 0 , 1, NoP); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_OCL_INLINE_CONST_HDC , 1, 0, 5, 0 , 0 , 0 , 1, NoP); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_OCL_SCRATCH , 1, 0, 0, 0 , 0 , 0 , 1, NoP); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_OCL_PRIVATE_MEM , 1, 0, 0, 0 , 0 , 0 , 1, NoP); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_OCL_PRINTF_BUFFER , 1, 0, 0, 0 , 0 , 0 , 1, NoP); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_OCL_STATE_HEAP_BUFFER , 1, 0, 0, 0 , 0 , 0 , 1, NoP); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_OCL_SYSTEM_MEMORY_BUFFER , 1, 0, 0, 0 , 0 , 1 , 1, NoP); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_OCL_SYSTEM_MEMORY_BUFFER_CACHELINE_MISALIGNED , 0, 0, 0, 0 , 0 , 0 , 1, NoP); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_OCL_ISH_HEAP_BUFFER , 1, 0, 0, 0 , 0 , 0 , 1, NoP); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_OCL_TAG_MEMORY_BUFFER , 1, 0, 0, 0 , 0 , 0 , 1, NoP); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_OCL_TEXTURE_BUFFER , 1, 0, 0, 0 , 0 , 0 , 1, NoP); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_OCL_SELF_SNOOP_BUFFER , 1, 0, 0, 0 , 0 , 0 , 1, NoP); /**********************************************************************************/ // Cross Adapter // USAGE TYPE ,L3_CC, L3_CLOS,L1CC, L2CC, L4CC, Coherency , IgPAT) DEFINE_CACHE_ELEMENT( GMM_RESOURCE_USAGE_XADAPTER_SHARED_RESOURCE , 0, 0, 1, 0 , 0 , 0 , 1, NoP); /**********************************************************************************/ // BCS // USAGE TYPE L3_CC, L3_CLOS, L1CC, L2CC, L4CC, Coherency, IgPAT) DEFINE_CACHE_ELEMENT( GMM_RESOURCE_USAGE_BLT_SOURCE , 0, 0, 0, 0, 0, 0, 1, NoP); DEFINE_CACHE_ELEMENT( GMM_RESOURCE_USAGE_BLT_DESTINATION , 0, 0, 0, 0, 0, 0, 1, NoP); /**********************************************************************************/ // // MEDIA USAGES // USAGE TYPE L3_CC, L3_CLOS,L1CC, L2CC, L4CC, Coherency, IgPAT ) DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_MEDIA_BATCH_BUFFERS , 0, 0, 0, 0, 0, 0 , 1, NoP ); // DECODE DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_DECODE_INPUT_BITSTREAM , dGPU, 0, 0, 0, 1, 0 , 1, NoP ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_DECODE_INPUT_REFERENCE , dGPU, 0, 0, 1, 1, 0 , 1, NoP ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_DECODE_INTERNAL_READ , dGPU, 0, 0, 0, 1, 0 , 1, NoP ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_DECODE_INTERNAL_WRITE , 0, 0, 0, 0, 0, 0 , 1, NoP ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_DECODE_INTERNAL_READ_WRITE_CACHE , dGPU, 0, 0, 0, 1, 0 , 1, NoP ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_DECODE_INTERNAL_READ_WRITE_NOCACHE , 0, 0, 0, 0, 0, 0 , 1, NoP ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_DECODE_OUTPUT_PICTURE , 3, 0, 0, 0, 2, 0 , 0, NoP ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_DECODE_OUTPUT_STATISTICS_WRITE , 0, 0, 0, 0, 0, 1 , 1, NoP ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_DECODE_OUTPUT_STATISTICS_READ_WRITE , dGPU, 0, 0, 0, 1, 0 , 1, NoP ); // ENCODE DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_ENCODE_INPUT_RAW , dGPU, 0, 0, 0, 1, 0 , 1, NoP ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_ENCODE_INPUT_RECON , dGPU, 0, 0, 1, 1, 0 , 1, NoP ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_ENCODE_INTERNAL_READ , dGPU, 0, 0, 0, 1, 0 , 1, NoP ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_ENCODE_INTERNAL_WRITE , 0, 0, 0, 0, 0, 0 , 1, NoP ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_ENCODE_INTERNAL_READ_WRITE_CACHE , dGPU, 0, 0, 0, 1, 0 , 1, NoP ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_ENCODE_INTERNAL_READ_WRITE_NOCACHE , 0, 0, 0, 0, 0, 0 , 1, NoP ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_ENCODE_EXTERNAL_READ , 0, 0, 0, 0, 0, 0 , 1, NoP ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_ENCODE_OUTPUT_PICTURE , dGPU, 0, 0, 0, 1, 0 , 1, NoP ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_ENCODE_OUTPUT_BITSTREAM , 0, 0, 0, 0, 0, 1 , 1, NoP ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_ENCODE_OUTPUT_STATISTICS_WRITE , 0, 0, 0, 0, 0, 1 , 1, NoP ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_ENCODE_OUTPUT_STATISTICS_READ_WRITE , dGPU, 0, 0, 0, 1, 0 , 1, NoP ); // VP DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_VP_INPUT_PICTURE_FF , dGPU, 0, 0, 0, 1, 0 , 1, NoP ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_VP_INPUT_REFERENCE_FF , dGPU, 0, 0, 0, 1, 0 , 1, NoP ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_VP_INTERNAL_READ_FF , 0, 0, 0, 0, 1, 0 , 1, NoP ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_VP_INTERNAL_WRITE_FF , 0, 0, 0, 0, 1, 0 , 1, NoP ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_VP_INTERNAL_READ_WRITE_FF , dGPU, 0, 0, 0, 1, 0 , 1, NoP ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_VP_OUTPUT_PICTURE_FF , 3, 0, 0, 0, 2, 0 , 0, NoP ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_VP_INPUT_PICTURE_RENDER , 1, 0, 0, 0, 0, 0 , 1, NoP ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_VP_INPUT_REFERENCE_RENDER , 1, 0, 0, 0, 0, 0 , 1, NoP ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_VP_INTERNAL_READ_RENDER , 0, 0, 0, 0, 0, 0 , 1, NoP ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_VP_INTERNAL_WRITE_RENDER , 0, 0, 0, 0, 0, 0 , 1, NoP ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_VP_INTERNAL_READ_WRITE_RENDER , 1, 0, 0, 0, 0, 0 , 1, NoP ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_VP_OUTPUT_PICTURE_RENDER , 3, 0, 0, 0, 0, 0 , 0, NoP ); // CP DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_CP_EXTERNAL_READ , 0, 0, 0, 0, 0, 0 , 1, NoP ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_CP_INTERNAL_WRITE , 0, 0, 0, 0, 0, 0 , 1, NoP ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_GSC_KMD_RESOURCE , 0, 0, 0, 0, 0, 0 , 1, NoP ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_KMD_NULL_CONTEXT_BB , 0, 0, 0, 0 , 0, 0 , 1, NoP ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_COMMAND_STREAMER , 0, 0, 0, 0 , 0, 0 , 1, NoP ); // USAGE TYPE , L3_CC, L3_CLOS, L1CC, L2CC, L4CC, Coherency, IgPAT) // Uncacheable copies DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_COPY_SOURCE , 0, 0, 0 , 0, 0, 0, 1, NoP); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_COPY_DEST , 0, 0, 0 , 0, 0, 0, 1, NoP); // clang-format on #undef _WT #include "GmmCachePolicyUndefineConditionals.h" gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/CachePolicy/GmmXe_LPGCachePolicy.cpp000066400000000000000000000516011466655022700265700ustar00rootroot00000000000000/*============================================================================== Copyright(c) 2022 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ============================================================================*/ #include "Internal/Common/GmmLibInc.h" #include "External/Common/GmmCachePolicy.h" #include "External/Common/CachePolicy/GmmCachePolicyXe_LPG.h" //============================================================================= // // Function: __:GmmXe_LPGInitCachePolicy // // Desc: This function initializes the cache policy // // Parameters: pCachePolicy -> Ptr to array to be populated with the // mapping of usages -> cache settings. // // Return: GMM_STATUS // //----------------------------------------------------------------------------- GMM_STATUS GmmLib::GmmXe_LPGCachePolicy::InitCachePolicy() { __GMM_ASSERTPTR(pCachePolicy, GMM_ERROR); #define DEFINE_CACHE_ELEMENT(usage, l3, l3_scc, go, uclookup, l1cc, l2cc, l4cc, coherency) DEFINE_CP_ELEMENT(usage, 0, 0, l3, 0, 0, 0, 0, l3_scc, 0, 0, 0, 0, 0, 0, go, uclookup, l1cc, l2cc, l4cc, coherency, l3, 0, 0) #include "GmmXe_LPGCachePolicy.h" #define L3_UNCACHEABLE (0x1) #define L3_WB_CACHEABLE (0x3) #define DISABLE_SKIP_CACHING_CONTROL (0x0) #define ENABLE_SKIP_CACHING_CONTROL (0x1) #define ONE_WAY_COHERENT (0x2) SetUpMOCSTable(); SetupPAT(); // Define index of cache element uint32_t Usage = 0; uint32_t ReservedMocsIdx = 10; /* Rsvd MOCS section 10-12 */ #if(_WIN32 && (_DEBUG || _RELEASE_INTERNAL)) void *pKmdGmmContext = NULL; #if(defined(__GMM_KMD__)) pKmdGmmContext = pGmmLibContext->GetGmmKmdContext(); #endif OverrideCachePolicy(pKmdGmmContext); #endif // Process the cache policy and fill in the look up table for(; Usage < GMM_RESOURCE_USAGE_MAX; Usage++) { bool CachePolicyError = false; int32_t CPTblIdx = -1, PATIdx = -1, CoherentPATIdx = -1; uint32_t i, j, k; GMM_CACHE_POLICY_TBL_ELEMENT UsageEle = {0}; uint32_t StartMocsIdx = 0; GMM_L4_CACHING_POLICY PATCachePolicy; GMM_PRIVATE_PAT UsagePATElement = {0}; GMM_PTE_CACHE_CONTROL_BITS PTE = {0}; // MOCS data { //L3 UsageEle.L3.Reserved = 0; // Reserved bits zeroe'd, this is so we // we can compare the unioned L3.UshortValue. UsageEle.L3.ESC = DISABLE_SKIP_CACHING_CONTROL; UsageEle.L3.SCC = 0; UsageEle.L3.Cacheability = pCachePolicy[Usage].L3 ? L3_WB_CACHEABLE : L3_UNCACHEABLE; if(pCachePolicy[Usage].L3 == 0) { UsageEle.L3.GlobalGo = pCachePolicy[Usage].GlbGo; } UsageEle.L3.UCLookup = pCachePolicy[Usage].UcLookup; __GMM_ASSERT((pCachePolicy[Usage].UcLookup) || (pCachePolicy[Usage].L3 == 0 && pCachePolicy[Usage].UcLookup == 0)); // L4 Data UsageEle.LeCC.Xe_LPG.L4CC = (pCachePolicy[Usage].L4CC - 1) % 4; // coverting indicator values to actual regiser values 0->3(GMM_CP_NON_COHERENT_UC), 2->1(GMM_CP_NON_COHERENT_WT) 1->0(GMM_CP_NON_COHERENT_WB) /* Valid MOCS Index starts from 1 */ for(j = 1; j <= CurrentMaxMocsIndex; j++) { GMM_CACHE_POLICY_TBL_ELEMENT *TblEle = &pGmmLibContext->GetCachePolicyTlbElement()[j]; if((TblEle->L3.UshortValue == UsageEle.L3.UshortValue) && (TblEle->LeCC.Xe_LPG.L4CC == UsageEle.LeCC.Xe_LPG.L4CC)) { CPTblIdx = j; break; } } if(CPTblIdx == -1) { #if(_WIN32 && (_DEBUG || _RELEASE_INTERNAL)) // If the Cache Policy setting is overriden through regkey if((pCachePolicy[Usage].IsOverridenByRegkey) && (ReservedMocsIdx < 13)) /* Reserved MOCS 10-12 */ { /*Use the Reserved Section to add new MOCS settings,*/ GMM_CACHE_POLICY_TBL_ELEMENT *TblEle = &(pGmmLibContext->GetCachePolicyTlbElement()[ReservedMocsIdx++]); CPTblIdx = ReservedMocsIdx; TblEle->L3.UshortValue = UsageEle.L3.UshortValue; TblEle->LeCC.Xe_LPG.DwordValue = UsageEle.LeCC.Xe_LPG.DwordValue; GMM_ASSERTDPF(false, "CRITICAL: Cache Policy Usage value for L3/L4 specified by Client is not defined in Fixed MOCS Table and added to reserved MOCS section !!"); } else #endif { // Log Error using regkey to indicate the above error #if(_WIN32 && (_DEBUG || _RELEASE_INTERNAL) && __GMM_KMD__) REGISTRY_OVERRIDE_WRITE(pKmdGmmContext, Usage, UnSupportedMOCSEntryL3Value, UsageEle.L3.UshortValue); #endif CachePolicyError = true; GMM_ASSERTDPF(false, "CRITICAL ERROR: Cache Policy Usage value for L3 specified by Client is not defined in Fixed MOCS Table!"); // Set cache policy index to default MOCS. CPTblIdx = 0; } } } // PAT data { UsagePATElement.Xe_LPG.Reserved = 0; UsagePATElement.Xe_LPG.L4CC = (pCachePolicy[Usage].L4CC - 1) % 4; // coverting indicator values to actual regiser values 0->3(GMM_CP_NON_COHERENT_UC), 2->1(GMM_CP_NON_COHERENT_WT) 1->0(GMM_CP_NON_COHERENT_WB) UsagePATElement.Xe_LPG.Coherency = pCachePolicy[Usage].Coherency ? (pCachePolicy[Usage].Coherency + 1) : GMM_GFX_NON_COHERENT_NO_SNOOP; // pCachePolicy[Usage].Coherency -> UsagePATElement.Xe_LPG.Coherency : 0 -> GMM_GFX_NON_COHERENT_NO_SNOOP, 1 -> GMM_GFX_COHERENT_ONE_WAY_IA_SNOOP(2), 2 -> GMM_GFX_COHERENT_TWO_WAY_IA_GPU_SNOOP(3) if((UsagePATElement.Xe_LPG.L4CC >= GMM_CP_NON_COHERENT_WT) && (UsagePATElement.Xe_LPG.Coherency >= GMM_GFX_COHERENT_ONE_WAY_IA_SNOOP)) { // restrictions // __GMM_ASSERT(FALSE); // disable assert till there is more clarity on Snoop + UC combination support in PAT register // unsupported combination of coherency and L4cachepolicy // Promote caching to _WB and support snoop UsagePATElement.Xe_LPG.L4CC = GMM_CP_COHERENT_WB; } // try to find a match in static PAT table for(i = 0; i <= CurrentMaxPATIndex; i++) { GMM_PRIVATE_PAT PAT = GetPrivatePATEntry(i); if(UsagePATElement.Xe_LPG.L4CC == PAT.Xe_LPG.L4CC && UsagePATElement.Xe_LPG.Coherency == PAT.Xe_LPG.Coherency) { PATIdx = i; break; } } if(PATIdx == -1) { // Didn't find the caching settings in one of the already programmed PAT table entries. // Need to add a new lookup table entry. #if(_WIN32 && (_DEBUG || _RELEASE_INTERNAL)) // If the Cache Policy setting is overriden through regkey, if(pCachePolicy[Usage].IsOverridenByRegkey) { if(CurrentMaxPATIndex < NumPATRegisters) { SetPrivatePATEntry(++CurrentMaxPATIndex, UsagePATElement); // updates private PAT table PATIdx = CurrentMaxPATIndex; } else { GMM_ASSERTDPF( "Cache Policy Init Error: Invalid Cache Programming, too many unique caching combinations" "(we only support NumPATRegisters = %d)", NumPATRegisters - 1); CachePolicyError = true; // add rterror here PATIdx = PAT2; //default to uncached PAT index 2: GMM_CP_NON_COHERENT_UC } } #else { GMM_ASSERTDPF( "Cache Policy Init Error: Invalid Cache Programming, too many unique caching combinations" "(we only support NumPATRegisters = %d)", CurrentMaxPATIndex); CachePolicyError = true; // add rterror here PATIdx = PAT2; // default to uncached PAT index 2: GMM_CP_NON_COHERENT_UC // Log Error using regkey to indicate the above error #if(_WIN32 && (_DEBUG || _RELEASE_INTERNAL) && __GMM_KMD__) REGISTRY_OVERRIDE_WRITE(pKmdGmmContext, Usage, NewPATCachingPolicy, UsagePATElement.Xe_LPG.L4CC); REGISTRY_OVERRIDE_WRITE(pKmdGmmContext, Usage, NewPATCoherency, UsagePATElement.Xe_LPG.Coherency); #endif } #endif } // Find PATIndex matching coherency value of 2 in static PAT table (1 way coherent) for(k = 0; k <= CurrentMaxPATIndex; k++) { GMM_PRIVATE_PAT PAT = GetPrivatePATEntry(k); if(UsagePATElement.Xe_LPG.L4CC == PAT.Xe_LPG.L4CC && (ONE_WAY_COHERENT == PAT.Xe_LPG.Coherency)) { CoherentPATIdx = k; break; } } if(CoherentPATIdx == -1) { // redo PAT idnex mathcing with just coherency value, // ignore L4 cache setting since MTL is MOCS centric and only the coherency value comes from PAT anyways, caching policy is bound to come from MOCS on MTL for(k = 0; k <= CurrentMaxPATIndex; k++) { GMM_PRIVATE_PAT PAT = GetPrivatePATEntry(k); if(ONE_WAY_COHERENT == PAT.Xe_LPG.Coherency) { CoherentPATIdx = k; break; } } } if(CoherentPATIdx == -1) // no match, switch to PATIndex { CachePolicyError = true; CoherentPATIdx = PATIdx; } } pCachePolicy[Usage].PATIndex = PATIdx; pCachePolicy[Usage].CoherentPATIndex = GET_COHERENT_PATINDEX_LOWER_BITS(CoherentPATIdx); pCachePolicy[Usage].CoherentPATIndexHigherBit = GET_COHERENT_PATINDEX_HIGHER_BIT(CoherentPATIdx); pCachePolicy[Usage].PTE.DwordValue = GMM_GET_PTE_BITS_FROM_PAT_IDX(PATIdx) & 0xFFFFFFFF; pCachePolicy[Usage].PTE.HighDwordValue = GMM_GET_PTE_BITS_FROM_PAT_IDX(PATIdx) >> 32; pCachePolicy[Usage].MemoryObjectOverride.XE_LPG.Index = CPTblIdx; pCachePolicy[Usage].Override = ALWAYS_OVERRIDE; if(CachePolicyError) { GMM_ASSERTDPF(false, "Cache Policy Init Error: Invalid Cache Programming "); // add rterror here } } return GMM_SUCCESS; } //============================================================================= // // Function: __:SetL1CachePolicy // // Desc: This function converting indicator values to actual register values and store into pCachePolicy to return to UMD's. // Gmm not using this values. UMD's queries for this values. // // Parameters: Usage // // Return: VOID // //----------------------------------------------------------------------------- void GmmLib::GmmXe_LPGCachePolicy::SetL1CachePolicy(uint32_t Usage) { // As per HW, L1 cache control(L1CC) values (0: WBP write bypass mode, 1: 0 uncached, 2: WB Write back, 3:WT write-through, 4: WS Write-Streaming). #define L1_WBP_CACHEABLE (0x0) #define L1_UNCACHEABLE (0x1) #define L1_WB_CACHEABLE (0x2) #define L1_WT_CACHEABLE (0x3) #define L1_WS_CACHEABLE (0x4) switch (pCachePolicy[Usage].L1CC) { case GMM_UC: pCachePolicy[Usage].L1CC = L1_UNCACHEABLE; break; case GMM_WB: pCachePolicy[Usage].L1CC = L1_WB_CACHEABLE; break; case GMM_WT: pCachePolicy[Usage].L1CC = L1_WT_CACHEABLE; break; case GMM_WBP: pCachePolicy[Usage].L1CC = L1_WBP_CACHEABLE; break; case GMM_WS: pCachePolicy[Usage].L1CC = L1_WS_CACHEABLE; break; default: pCachePolicy[Usage].L1CC = L1_UNCACHEABLE; } #undef L1_WBP_CACHEABLE #undef L1_UNCACHEABLE #undef L1_WB_CACHEABLE #undef L1_WT_CACHEABLE #undef L1_WS_CACHEABLE } ///////////////////////////////////////////////////////////////////////////////////// /// A simple getter function returning the PAT (cache policy) for a given /// use Usage of the named resource pResInfo. /// Typically used to populate PPGTT/GGTT. /// /// @param[in] pResInfo: Resource info for resource, can be NULL. /// @param[in] Usage: Current usage for resource. /// @param[Optional] Not Applicable for MTL /// @param[in] Applicable for MTL /// @return PATIndex ///////////////////////////////////////////////////////////////////////////////////// uint32_t GMM_STDCALL GmmLib::GmmXe_LPGCachePolicy::CachePolicyGetPATIndex(GMM_RESOURCE_INFO *pResInfo, GMM_RESOURCE_USAGE_TYPE Usage, bool *pCompressionEnable, bool IsCpuCacheable) { __GMM_ASSERT(pGmmLibContext->GetCachePolicyElement(Usage).Initialized); GMM_UNREFERENCED_PARAMETER(pCompressionEnable); // Prevent wrong Usage for XAdapter resources. UMD does not call GetMemoryObject on shader resources but, // when they add it someone could call it without knowing the restriction. if(pResInfo && pResInfo->GetResFlags().Info.XAdapter && Usage != GMM_RESOURCE_USAGE_XADAPTER_SHARED_RESOURCE) { __GMM_ASSERT(false); } if(IsCpuCacheable) { return (uint32_t)(GET_COHERENT_PATINDEX_VALUE(pGmmLibContext, Usage)); } else { return pGmmLibContext->GetCachePolicyElement(Usage).PATIndex; } } //============================================================================= // // Function: SetUpMOCSTable // // Desc: // // Parameters: // // Return: GMM_STATUS // //----------------------------------------------------------------------------- void GmmLib::GmmXe_LPGCachePolicy::SetUpMOCSTable() { GMM_CACHE_POLICY_TBL_ELEMENT *pCachePolicyTlbElement = &(pGmmLibContext->GetCachePolicyTlbElement()[0]); CurrentMaxL1HdcMocsIndex = 0; CurrentMaxSpecialMocsIndex = 0; #define L3_UC (0x1) #define L3_WB (0x3) #define L4_WB (0x0) #define L4_WT (0x1) #define L4_UC (0x3) #define GMM_DEFINE_MOCS(Index, L3_LookUp, L3_Go, L3_CC, L4Caching, ignorePAT) \ { \ pCachePolicyTlbElement[Index].L3.Cacheability = L3_CC; \ pCachePolicyTlbElement[Index].L3.GlobalGo = L3_Go; \ pCachePolicyTlbElement[Index].L3.UCLookup = L3_LookUp; \ pCachePolicyTlbElement[Index].LeCC.Xe_LPG.L4CC = L4Caching; \ pCachePolicyTlbElement[Index].LeCC.Xe_LPG.igPAT = ignorePAT; \ } // clang-format off //Default MOCS Table for(int index = 0; index < GMM_MAX_NUMBER_MOCS_INDEXES; index++) { // Index LookUp Go L3CC L4CC ignorePAT GMM_DEFINE_MOCS( index , 1 , 0 , L3_UC , L4_UC , 0) } // Fixed MOCS Table // Index LookUp Go L3CC L4CC ignorePAT GMM_DEFINE_MOCS( 0 , 1 , 0 , L3_WB , L4_WB , 1) GMM_DEFINE_MOCS( 1 , 1 , 0 , L3_WB , L4_WB , 1) GMM_DEFINE_MOCS( 2 , 1 , 0 , L3_UC , L4_WB , 1) GMM_DEFINE_MOCS( 3 , 1 , 0 , L3_UC , L4_UC , 1) GMM_DEFINE_MOCS( 4 , 1 , 1 , L3_UC , L4_WB , 1) GMM_DEFINE_MOCS( 5 , 1 , 1 , L3_UC , L4_UC , 1) GMM_DEFINE_MOCS( 6 , 0 , 0 , L3_UC , L4_WB , 1) GMM_DEFINE_MOCS( 7 , 0 , 0 , L3_UC , L4_UC , 1) GMM_DEFINE_MOCS( 8 , 0 , 1 , L3_UC , L4_WB , 1) GMM_DEFINE_MOCS( 9 , 0 , 1 , L3_UC , L4_UC , 1) //Reserved 10-13 GMM_DEFINE_MOCS( 14 , 1 , 0 , L3_WB , L4_WT , 1) /* Note Update GMM_CC_DISP_MOCS_INDEX*/ GMM_DEFINE_MOCS( 15 , 0 , 1 , L3_UC , L4_WB , 1) /* Note Update GMM_NON_CC_DISP_MOCS_INDEX */ CurrentMaxMocsIndex = 15; CurrentMaxL1HdcMocsIndex = 0; CurrentMaxSpecialMocsIndex = 0; // clang-format on #undef GMM_DEFINE_MOCS #undef L4_WB #undef L4_WT #undef L4_UC #undef L3_UC #undef L3_WB } //============================================================================= // // Function: SetupPAT // // Desc: // // Parameters: // // Return: GMM_STATUS // //----------------------------------------------------------------------------- GMM_STATUS GmmLib::GmmXe_LPGCachePolicy::SetupPAT() { GMM_PRIVATE_PAT *pPATTlbElement = &(pGmmLibContext->GetPrivatePATTable()[0]); #define L4_WB (0x0) #define L4_WT (0x1) #define L4_UC (0x3) #define GMM_DEFINE_PAT_ELEMENT(indx, L4Caching, Coh) \ { \ pPATTlbElement[indx].Xe_LPG.Coherency = Coh; \ pPATTlbElement[indx].Xe_LPG.L4CC = L4Caching; \ pPATTlbElement[indx].Xe_LPG.Reserved = 0; \ } // clang-format off // Default PAT Table for (uint32_t i = 0; i < NumPATRegisters; i++) { // Index CachingPolicy Coherency GMM_DEFINE_PAT_ELEMENT( i, L4_UC , 0 ); } // Fixed PAT Table // Index CachingPolicy Coherency GMM_DEFINE_PAT_ELEMENT( 0 , L4_WB , 0) // PATRegValue = 0x0 GMM_DEFINE_PAT_ELEMENT( 1 , L4_WT , 0) // PATRegValue = 0x4 GMM_DEFINE_PAT_ELEMENT( 2 , L4_UC , 0) // PATRegValue = 0xC GMM_DEFINE_PAT_ELEMENT( 3 , L4_WB , 2) // PATRegValue = 0x2 GMM_DEFINE_PAT_ELEMENT( 4 , L4_WB , 3) // PATRegValue = 0x3 CurrentMaxPATIndex = 4; // clang-format on #undef GMM_DEFINE_PAT #undef L4_WB #undef L4_WT #undef L4_UC return GMM_SUCCESS; } uint32_t GMM_STDCALL GmmLib::GmmXe_LPGCachePolicy::GetSurfaceStateL1CachePolicy(GMM_RESOURCE_USAGE_TYPE Usage) { __GMM_ASSERT(pCachePolicy[Usage].Initialized); return pCachePolicy[Usage].L1CC; } ///////////////////////////////////////////////////////////////////////////////////// /// A simple getter function returning the MOCS (cache policy) for a given /// use Usage of the named resource pResInfo. /// Typically used to populate a SURFACE_STATE for a GPU task. /// /// @param[in] pResInfo: Resource info for resource, can be NULL. /// @param[in] Usage: Current usage for resource. /// /// @return MEMORY_OBJECT_CONTROL_STATE: Gen adjusted MOCS structure (cache /// policy) for the given buffer use. ///////////////////////////////////////////////////////////////////////////////////// MEMORY_OBJECT_CONTROL_STATE GMM_STDCALL GmmLib::GmmXe_LPGCachePolicy::CachePolicyGetMemoryObject(GMM_RESOURCE_INFO *pResInfo, GMM_RESOURCE_USAGE_TYPE Usage) { __GMM_ASSERT(pCachePolicy[Usage].Initialized); // Prevent wrong Usage for XAdapter resources. UMD does not call GetMemoryObject on shader resources but, // when they add it someone could call it without knowing the restriction. if (pResInfo && pResInfo->GetResFlags().Info.XAdapter && (Usage != GMM_RESOURCE_USAGE_XADAPTER_SHARED_RESOURCE)) { __GMM_ASSERT(false); } if (!pResInfo || (pCachePolicy[Usage].Override & pCachePolicy[Usage].IDCode) || (pCachePolicy[Usage].Override == ALWAYS_OVERRIDE)) { return pCachePolicy[Usage].MemoryObjectOverride; } else { return pCachePolicy[Usage].MemoryObjectNoOverride; } } gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/CachePolicy/GmmXe_LPGCachePolicy.h000066400000000000000000000734731466655022700262500ustar00rootroot00000000000000/*============================================================================== Copyright(c) 2022 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ============================================================================*/ #include "GmmCachePolicyConditionals.h" #define _SN 0x1 #define _IA_GPU_SN 0x2 #define _WT 0x2 #define _L1_WB 0x2 // Cache Policy Definition // L3_SCC : L3 skip caching control (disabled if L3_SCC = 0) // GO : Global observable point for L3-uncached (0=Default is L3, 1= Memory) // UcLookup : Snoop L3 for uncached (0=Default is no-snoop, 1 =Snoop) // L1CC : L1 cache control (0: WBP write bypass mode, 1: 0 uncached, 2: WB Write back, 3:WT write-through, 4: WS Write-Streaming) : Valid only for DG2+ // L2CC : 0 : 0, 1: WB // L4CC : 0 : UC, 1: wB, 2: WT // Coherency : 0= NoSnoop (non coherent) 1: 1 way coherent with IA Snoop (GPU snoop of CPU cache) 2: 2 way coherent IA GPU Snoop [Snoop is always to LLC from CPU/GPU internal caches] //******************************************************************************************************************************************************************/ // USAGE TYPE , L3, L3_SCC, GO, UcLookup, L1CC, L2CC, L4CC, Coherency) /*******************************************************************************************************************************************************************/ // KMD Usages DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_BATCH_BUFFER , 0 , 0 , 0, 1, 1, 0 , 0 , 0 ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_COMP_FRAME_BUFFER , 0 , 0 , 0, 1, 1, 0 , 0 , 0 ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_CONTEXT_SWITCH_BUFFER , 0 , 0 , 0, 1, 1, 0 , 0 , 0 ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_CURSOR , 0 , 0 , 0, 1, 1, 0 , 0 , 0 ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_DISPLAY_STATIC_IMG_FOR_SMOOTH_ROTATION_BUFFER , 1 , 0 , 0, 1, 1, 0 , _WT , 0 ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_DUMMY_PAGE , 0 , 0 , 0, 1, 1, 0 , 0 , 0 ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_GDI_SURFACE , 1 , 0 , 0, 1, 1, 0 , 1 , 0 ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_GENERIC_KMD_RESOURCE , 0 , 0 , 0, 1, 1, 0 , 0 , 0 ); // GMM_RESOURCE_USAGE_GFX_RING is only used if WaEnableRingHostMapping is enabled. DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_GFX_RING , 0 , 0 , 0, 1, 1, 0 , 0 , 0 ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_GTT_TRANSFER_REGION , 0 , 0 , 0, 1, 1, 0 , 0 , 0 ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_HW_CONTEXT , 0 , 0 , 0, 1, 1, 0 , 0 , 0 ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_STATE_MANAGER_KERNEL_STATE , 0 , 0 , 0, 1, 1, 0 , 0 , 0 ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_KMD_STAGING_SURFACE , 1 , 0 , 0, 1, 1, 0 , 1 , 0 ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_MBM_BUFFER , 0 , 0 , 0, 1, 1, 0 , 0 , 0 ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_NNDI_BUFFER , 0 , 0 , 0, 1, 1, 0 , 0 , 0 ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_OVERLAY_MBM , 0 , 0 , 0, 1, 1, 0 , 0 , 0 ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_PRIMARY_SURFACE , 1 , 0 , 0, 1, 1, 0 , _WT , 0 ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_SCREEN_PROTECTION_INTERMEDIATE_SURFACE , 0 , 0 , 0, 1, 1, 0 , 0 , 0 ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_SHADOW_SURFACE , 1 , 0 , 0, 1, 1, 0 , 1 , 0 ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_SM_SCRATCH_STATE , 0 , 0 , 0, 1, 1, 0 , 0 , 0 ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_STATUS_PAGE , 1 , 0 , 0, 1, 1, 0 , 1 , 0 ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_TIMER_PERF_QUEUE , 0 , 0 , 0, 1, 1, 0 , 0 , 0 ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_UNKNOWN , 0 , 0 , 0, 1, 1, 0 , 0 , 0 ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_UNMAP_PAGING_RESERVED_GTT_DMA_BUFFER , 0 , 0 , 0, 1, 1, 0 , 0 , 0 ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_VSC_BATCH_BUFFER , 0 , 0 , 0, 1, 1, 0 , 0 , 0 ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_WA_BATCH_BUFFER , 0 , 0 , 0, 1, 1, 0 , 0 , 0 ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_KMD_OCA_BUFFER , 0 , 0 , 0, 1, 1, 0 , 0 , 0 ); // // 3D Usages // // USAGE TYPE , L3, L3_SCC, GO, UcLookup, L1CC, L2CC, L4CC, Coherency ) DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_TILED_DEPTH_BUFFER , 1 , 0 , 0, 1, 1, 0 , 1 , 0 ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_TILED_HIZ , 1 , 0 , 0, 1, 1, 0 , 1 , 0 ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_UMD_BATCH_BUFFER , 0 , 0 , 0, 1, 1, 0 , 1 , 0 ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_BINDING_TABLE_POOL , 1 , 0 , 0, 1, 1, 0 , 1 , 0 ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_CCS , 0 , 0 , 1, 0, 1, 0 , 1 , 0 ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_CONSTANT_BUFFER_POOL , 1 , 0 , 0, 1, 1, 0 , 1 , 0 ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_DEPTH_BUFFER , 1 , 0 , 0, 1, 1, 0 , 1 , 0 ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_DISPLAYABLE_RENDER_TARGET , 1 , 0 , 0, 1, 1, 0 , _WT , 0 ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_GATHER_POOL , 1 , 0 , 0, 1, 1, 0 , 1 , 0 ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_HEAP_SURFACE_STATE , 1 , 0 , 0, 1, 1, 0 , 1 , 0 ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_HEAP_DYNAMIC_STATE , 1 , 0 , 0, 1, 1, 0 , 1 , 0 ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_HEAP_GENERAL_STATE , 1 , 0 , 0, 1, 1, 0 , 1 , 0 ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_HEAP_GENERAL_STATE_UC , 0 , 0 , 0, 1, 1, 0 , 0 , 0 ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_HEAP_STATELESS_DATA_PORT , 1 , 0 , 0, 1, 1, 0 , 1 , 0 ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_HEAP_STATELESS_DATA_PORT_L1_CACHED , 1 , 0 , 0, 1, _L1_WB, 0 , 1 , 0 ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_HEAP_INDIRECT_OBJECT , 1 , 0 , 0, 1, 1, 0 , 1 , 0 ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_HEAP_INSTRUCTION , 1 , 0 , 0, 1, 1, 0 , 1 , 0 ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_HIZ , 1 , 0 , 0, 1, 1, 0 , 1 , 0 ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_INDEX_BUFFER , 1 , 0 , 0, 1, 1, 0 , 1 , 0 ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_INDEX_BUFFER_L3_COHERENT_UC , 0 , 0 , 0, 1, 1, 0 , 0 , 0 ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_INDEX_BUFFER_L3_CACHED , 1 , 0 , 0, 1, 1, 0 , 1 , 0 ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_MCS , 1 , 0 , 0, 1, 1, 0 , 1 , 0 ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_PUSH_CONSTANT_BUFFER , 1 , 0 , 0, 1, 1, 0 , 1 , 0 ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_PULL_CONSTANT_BUFFER , 1 , 0 , 0, 1, 0, 0 , 1 , 0 ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_QUERY , 0 , 0 , 0, 1, 1, 0 , 1 , _SN ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_RENDER_TARGET , 1 , 0 , 0, 1, 1, 0 , 1 , 0 ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_SHADER_RESOURCE , 1 , 0 , 0, 1, 0, 0 , 1 , 0 ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_STAGING , 0 , 0 , 1, 0, 1, 0 , 1 , _SN ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_STENCIL_BUFFER , 1 , 0 , 0, 1, 1, 0 , 1 , 0 ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_STREAM_OUTPUT_BUFFER , 1 , 0 , 0, 1, 1, 0 , 1 , 0 ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_TILE_POOL , 1 , 0 , 0, 1, 1, 0 , 1 , 0 ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_SHADER_RESOURCE_LLC_BYPASS , 1 , 0 , 0, 1, 0, 0 , 1 , 0 ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_MOCS_62 , 0 , 0 , 1, 0, 1, 0 , 0 , 0 ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_L3_EVICTION , 0 , 0 , 1, 0, 1, 0 , 0 , 0 ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_L3_EVICTION_SPECIAL , 0 , 0 , 1, 0, 1, 0 , 0 , 0 ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_PROCEDURAL_TEXTURE , 1 , 0 , 0, 1, 1, 0 , 1 , 0 ); // Tiled Resource // // USAGE TYPE , L3, L3_SCC, GO, UcLookup, L1CC, L2CC, L4CC, Coherency ) DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_TILED_DEPTH_BUFFER , 1 , 0 , 0, 1, 1, 0 , 1 , 0 ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_TILED_HIZ , 1 , 0 , 0, 1, 1, 0 , 1 , 0 ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_TILED_MCS , 1 , 0 , 0, 1, 1, 0 , 1 , 0 ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_TILED_CCS , 1 , 0 , 0, 1, 1, 0 , 1 , 0 ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_TILED_RENDER_TARGET , 1 , 0 , 0, 1, 1, 0 , 1 , 0 ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_TILED_RENDER_TARGET_AND_SHADER_RESOURCE , 1 , 0 , 0, 1, 0, 0 , 1 , 0 ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_TILED_SHADER_RESOURCE , 1 , 0 , 0, 1, 0, 0 , 1 , 0 ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_TILED_UAV , 1 , 0 , 0, 1, 1, 0 , 1 , 0 ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_UAV , 1 , 0 , 0, 1, 1, 0 , 1 , 0 ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_VERTEX_BUFFER , 1 , 0 , 0, 1, 1, 0 , 1 , 0 ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_VERTEX_BUFFER_L3_COHERENT_UC , 0 , 0 , 0, 1, 1, 0 , 1 , 0 ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_VERTEX_BUFFER_L3_CACHED , 1 , 0 , 0, 1, 1, 0 , 1 , 0 ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_OGL_WSTN_VERTEX_BUFFER , 1 , 0 , 0, 1, 1, 0 , 1 , 0 ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_POSH_VERTEX_BUFFER , 1 , 0 , 0, 1, 1, 0 , 1 , 0 ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_RENDER_TARGET_AND_SHADER_RESOURCE , 1 , 0 , 0, 1, 0, 0 , 1 , 0 ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_WDDM_HISTORY_BUFFER , 1 , 0 , 0, 1, 1, 0 , 1 , 0 ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_CONTEXT_SAVE_RESTORE , 1 , 0 , 0, 1, 1, 0 , 1 , 0 ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_PTBR_PAGE_POOL , 1 , 0 , 0, 1, 1, 0 , 1 , 0 ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_PTBR_BATCH_BUFFER , 1 , 0 , 0, 1, 1, 0 , 1 , 0 ); // // CM USAGES // // USAGE TYPE , L3, L3_SCC, GO, UcLookup, L1CC, L2CC, L4CC, Coherency ) DEFINE_CACHE_ELEMENT(CM_RESOURCE_USAGE_SurfaceState, 1 , 0 , 0, 1, 1, 0 , 1 , 0 ); DEFINE_CACHE_ELEMENT(CM_RESOURCE_USAGE_L1_Enabled_SurfaceState, 1 , 0 , 0, 1, 2, 0 , 1 , 0 ); DEFINE_CACHE_ELEMENT(CM_RESOURCE_USAGE_StateHeap, 1 , 0 , 0, 1, 1, 0 , 1 , 0 ); DEFINE_CACHE_ELEMENT(CM_RESOURCE_USAGE_NO_L3_SurfaceState, 0 , 0 , 0, 1, 1, 0 , 1 , 0 ); DEFINE_CACHE_ELEMENT(CM_RESOURCE_USAGE_NO_CACHE_SurfaceState, 0 , 0 , 1, 0, 1, 0 , 0 , 0 ); // // MP USAGES // // USAGE TYPE , L3, L3_SCC, GO, UcLookup, L1CC, L2CC, L4CC, Coherency ) DEFINE_CACHE_ELEMENT(MP_RESOURCE_USAGE_BEGIN, 0 , 0 , 1, 0, 1, 0 , 0 , 0 ); DEFINE_CACHE_ELEMENT(MP_RESOURCE_USAGE_DEFAULT, 0 , 0 , 1, 0, 1, 0 , 0 , 0 ); DEFINE_CACHE_ELEMENT(MP_RESOURCE_USAGE_DEFAULT_FF, 0 , 0 , 1, 0, 1, 0 , 0 , 0 ); DEFINE_CACHE_ELEMENT(MP_RESOURCE_USAGE_DEFAULT_RCS, 0 , 0 , 0, 1, 1, 0 , 0 , 0 ); DEFINE_CACHE_ELEMENT(MP_RESOURCE_USAGE_SurfaceState, 1 , 0 , 0, 1, 1, 0 , 1 , 0 ); DEFINE_CACHE_ELEMENT(MP_RESOURCE_USAGE_SurfaceState_FF, 0 , 0 , 1, 0, 1, 0 , 0 , 0 ); DEFINE_CACHE_ELEMENT(MP_RESOURCE_USAGE_SurfaceState_RCS, 1 , 0 , 0, 1, 1, 0 , 1 , 0 ); DEFINE_CACHE_ELEMENT(MP_RESOURCE_USAGE_END, 0 , 0 , 1, 0, 1, 0 , 0 , 0 ); // MHW - SFC // USAGE TYPE , L3, L3_SCC, GO, UcLookup, L1CC, L2CC, L4CC, Coherency ) DEFINE_CACHE_ELEMENT(MHW_RESOURCE_USAGE_Sfc_CurrentOutputSurface, 0 , 0 , 1, 0, 1, 0 , 0 , 0 ); DEFINE_CACHE_ELEMENT(MHW_RESOURCE_USAGE_Sfc_AvsLineBufferSurface, 0 , 0 , 1, 0, 1, 0 , 0 , 0 ); DEFINE_CACHE_ELEMENT(MHW_RESOURCE_USAGE_Sfc_IefLineBufferSurface, 0 , 0 , 1, 0, 1, 0 , 0 , 0 ); /**********************************************************************************/ // // OCL Usages // // USAGE TYPE , L3, L3_SCC, GO, UcLookup, L1CC, L2CC, L4CC, Coherency ) DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_OCL_BUFFER , 1 , 0 , 0, 1, 1, 0 , 1 , 0 ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_OCL_BUFFER_CONST , 1 , 0 , 0, 1, 0, 0 , 1 , 0 ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_OCL_BUFFER_CSR_UC , 0 , 0 , 1, 1, 1, 0 , 0 , 0 ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_OCL_BUFFER_CACHELINE_MISALIGNED , 0 , 0 , 1, 1, 1, 0 , 1 , 0 ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_OCL_IMAGE , 1 , 0 , 0, 1, 1, 0 , 1 , 0 ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_OCL_INLINE_CONST , 1 , 0 , 0, 1, 1, 0 , 1 , 0 ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_OCL_INLINE_CONST_HDC , 1 , 0 , 0, 1, 0, 0 , 1 , 0 ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_OCL_SCRATCH , 1 , 0 , 0, 1, 1, 0 , 1 , 0 ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_OCL_PRIVATE_MEM , 1 , 0 , 0, 1, 1, 0 , 1 , 0 ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_OCL_PRINTF_BUFFER , 1 , 0 , 0, 1, 1, 0 , 1 , 0 ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_OCL_STATE_HEAP_BUFFER , 1 , 0 , 0, 1, 1, 0 , 1 , 0 ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_OCL_SYSTEM_MEMORY_BUFFER , 1 , 0 , 0, 1, 1, 0 , 1 , 0 ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_OCL_SYSTEM_MEMORY_BUFFER_CACHELINE_MISALIGNED , 0 , 0 , 1, 1, 1, 0 , 1 , 0 ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_OCL_ISH_HEAP_BUFFER , 1 , 0 , 0, 1, 1, 0 , 1 , 0 ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_OCL_TAG_MEMORY_BUFFER , 1 , 0 , 0, 1, 1, 0 , 1 , 0 ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_OCL_TEXTURE_BUFFER , 1 , 0 , 0, 1, 1, 0 , 1 , 0 ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_OCL_SELF_SNOOP_BUFFER , 1 , 0 , 0, 1, 1, 0 , 1 , 0 ); /**********************************************************************************/ // Cross Adapter // USAGE TYPE , L3, L3_SCC, GO, UcLookup, L1CC, L2CC, L4CC, Coherency ) DEFINE_CACHE_ELEMENT( GMM_RESOURCE_USAGE_XADAPTER_SHARED_RESOURCE , 0 , 0 , 0, 1, 1, 0 , 0 , 0 ); /**********************************************************************************/ // BCS // USAGE TYPE , L3, L3_SCC, GO, UcLookup, L1CC, L2CC, L4CC, Coherency ) DEFINE_CACHE_ELEMENT( GMM_RESOURCE_USAGE_BLT_SOURCE , 0 , 0 , 1, 0, 1, 0 , 0 , 0 ); DEFINE_CACHE_ELEMENT( GMM_RESOURCE_USAGE_BLT_DESTINATION , 0 , 0 , 1, 0, 1, 0 , 0 , 0 ); /**********************************************************************************/ // // MEDIA USAGES // USAGE TYPE , L3, L3_SCC, GO, UcLookup, L1CC, L2CC, L4CC, Coherency ) DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_MEDIA_BATCH_BUFFERS , 0 , 0 , 1, 0, 1, 0, 0, 0 ); // DECODE DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_DECODE_INPUT_BITSTREAM , 0 , 0 , 1, 0, 1, 0, 0, 0 ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_DECODE_INPUT_REFERENCE , 0 , 0 , 1, 0, 1, 1, 1, 0 ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_DECODE_INTERNAL_READ , 0 , 0 , 1, 0, 1, 0, 0, 0 ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_DECODE_INTERNAL_WRITE , 0 , 0 , 1, 0, 1, 0, 0, 0 ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_DECODE_INTERNAL_READ_WRITE_CACHE , 0 , 0 , 1, 0, 1, 0, 0, 0 ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_DECODE_INTERNAL_READ_WRITE_NOCACHE , 0 , 0 , 1, 0, 1, 0, 0, 0 ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_DECODE_OUTPUT_PICTURE , 0 , 0 , 0, 1, 1, 0, 0, 0 ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_DECODE_OUTPUT_STATISTICS_WRITE , 0 , 0 , 1, 0, 1, 0, 0, _SN ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_DECODE_OUTPUT_STATISTICS_READ_WRITE , 0 , 0 , 1, 0, 1, 0, 0, 0 ); // ENCODE DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_ENCODE_INPUT_RAW , 0 , 0 , 1, 0, 1, 0, 1, 0 ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_ENCODE_INPUT_RECON , 0 , 0 , 1, 0, 1, 1, 1, 0 ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_ENCODE_INTERNAL_READ , 0 , 0 , 1, 0, 1, 0, 1, 0 ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_ENCODE_INTERNAL_WRITE , 0 , 0 , 1, 0, 1, 0, 0, 0 ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_ENCODE_INTERNAL_READ_WRITE_CACHE , 0 , 0 , 1, 0, 1, 0, 1, 0 ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_ENCODE_INTERNAL_READ_WRITE_NOCACHE , 0 , 0 , 1, 0, 1, 0, 0, 0 ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_ENCODE_EXTERNAL_READ , 0 , 0 , 1, 0, 1, 0, 0, 0 ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_ENCODE_OUTPUT_PICTURE , 0 , 0 , 1, 0, 1, 0, 1, 0 ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_ENCODE_OUTPUT_BITSTREAM , 0 , 0 , 1, 0, 1, 0, 1, _SN ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_ENCODE_OUTPUT_STATISTICS_WRITE , 0 , 0 , 1, 0, 1, 0, 0, _SN ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_ENCODE_OUTPUT_STATISTICS_READ_WRITE , 0 , 0 , 1, 0, 1, 0, 0, 0 ); // VP DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_VP_INPUT_PICTURE_FF , 0 , 0 , 1, 0, 1, 0, 1, 0 ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_VP_INPUT_REFERENCE_FF , 0 , 0 , 1, 0, 1, 0, 1, 0 ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_VP_INTERNAL_READ_FF , 0 , 0 , 1, 0, 1, 0, 1, 0 ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_VP_INTERNAL_WRITE_FF , 0 , 0 , 1, 0, 1, 0, 1, 0 ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_VP_INTERNAL_READ_WRITE_FF , 0 , 0 , 1, 0, 1, 0, 1, 0 ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_VP_OUTPUT_PICTURE_FF , 1 , 0 , 0, 1, 1, 0, _WT, 0 ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_VP_INPUT_PICTURE_RENDER , 1 , 0 , 0, 1, 1, 0, 1, 0 ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_VP_INPUT_REFERENCE_RENDER , 0 , 0 , 1, 0, 1, 0, 1, 0 ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_VP_INTERNAL_READ_RENDER , 0 , 0 , 1, 0, 1, 0, 1, 0 ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_VP_INTERNAL_WRITE_RENDER , 1 , 0 , 0, 1, 1, 0, 1, 0 ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_VP_INTERNAL_READ_WRITE_RENDER , 1 , 0 , 0, 1, 1, 0, 1, 0 ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_VP_OUTPUT_PICTURE_RENDER , 1 , 0 , 0, 1, 1, 0, _WT, 0 ); // CP DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_CP_EXTERNAL_READ , 0 , 0 , 1, 0, 1, 0, 0, 0 ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_CP_INTERNAL_WRITE , 0 , 0 , 1, 0, 1, 0, 0, 0 ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_GSC_KMD_RESOURCE , 0 , 0 , 0, 1, 1, 0, 0, 0 ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_KMD_NULL_CONTEXT_BB , 0 , 0 , 0, 1, 1, 0 , 0, 0 ); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_COMMAND_STREAMER , 0 , 0 , 1, 1, 1, 0 , 0, 0 ); // USAGE TYPE , L3, L3_SCC, GO, UcLookup, L1CC, L2CC, L4CC, Coherency) // Uncacheable copies DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_COPY_SOURCE , 0 , 0 , 1 , 0 , 1 , 0, 0, 0); DEFINE_CACHE_ELEMENT(GMM_RESOURCE_USAGE_COPY_DEST , 0 , 0 , 1 , 0 , 1 , 0, 0, 0); #include "GmmCachePolicyUndefineConditionals.h" gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/GlobalInfo/000077500000000000000000000000001466655022700220675ustar00rootroot00000000000000gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/GlobalInfo/GmmClientContext.cpp000066400000000000000000001260041466655022700260220ustar00rootroot00000000000000/*============================================================================== Copyright(c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ============================================================================*/ #include "Internal/Common/GmmLibInc.h" #include "External/Common/GmmClientContext.h" #if !__GMM_KMD__ && LHDM #include "..\..\inc\common\gfxEscape.h" #include "..\..\..\miniport\LHDM\inc\gmmEscape.h" #include "Internal\Windows\GmmResourceInfoWinInt.h" #include "../TranslationTable/GmmUmdTranslationTable.h" #endif extern GMM_MA_LIB_CONTEXT *pGmmMALibContext; ///////////////////////////////////////////////////////////////////////////////////// /// Overloaded Constructor to zero initialize the GmmLib::GmmClientContext object /// This Construtor takes pointer to GmmLibCOntext as input argumnet and initiaizes /// ClientContext's GmmLibContext with this value ///////////////////////////////////////////////////////////////////////////////////// GmmLib::GmmClientContext::GmmClientContext(GMM_CLIENT ClientType, Context *pLibContext) : ClientType(), pUmdAdapter(), pGmmUmdContext(), DeviceCB(), IsDeviceCbReceived(0) { this->ClientType = ClientType; this->pGmmLibContext = pLibContext; } ///////////////////////////////////////////////////////////////////////////////////// /// Destructor to free GmmLib::GmmClientContext object memory ///////////////////////////////////////////////////////////////////////////////////// GmmLib::GmmClientContext::~GmmClientContext() { pGmmLibContext = NULL; } ///////////////////////////////////////////////////////////////////////////////////// /// Member function of ClientContext class for returning /// MEMORY_OBJECT_CONTROL_STATE for a given Resource Usage Type /// /// @param[in] GMM_RESOURCE_INFO : Pointer to ResInfo object /// @param[in] GMM_RESOURCE_USAGE_TYPE : Resource Usage Type /// @return MEMORY_OBJECT_CONTROL_STATE for the resource of "Usage" type. ///////////////////////////////////////////////////////////////////////////////////// MEMORY_OBJECT_CONTROL_STATE GMM_STDCALL GmmLib::GmmClientContext::CachePolicyGetMemoryObject(GMM_RESOURCE_INFO *pResInfo, GMM_RESOURCE_USAGE_TYPE Usage) { return pGmmLibContext->GetCachePolicyObj()->CachePolicyGetMemoryObject(pResInfo, Usage); } ///////////////////////////////////////////////////////////////////////////////////// /// Member function of ClientContext class for returning /// GMM_PTE_CACHE_CONTROL_BITS for a given Resource Usage Type /// /// @param[in] GMM_RESOURCE_USAGE_TYPE : Resource Usage Type /// @return GMM_PTE_CACHE_CONTROL_BITS for the resource of "Usage" type. ///////////////////////////////////////////////////////////////////////////////////// GMM_PTE_CACHE_CONTROL_BITS GMM_STDCALL GmmLib::GmmClientContext::CachePolicyGetPteType(GMM_RESOURCE_USAGE_TYPE Usage) { return pGmmLibContext->GetCachePolicyObj()->CachePolicyGetPteType(Usage); } ///////////////////////////////////////////////////////////////////////////////////// /// Member function of ClientContext class for returning /// MEMORY_OBJECT_CONTROL_STATE for a given ResInfo Object /// /// @param[in] GMM_RESOURCE_INFO : Pointer to ResInfo object /// @return MEMORY_OBJECT_CONTROL_STATE for the ResInfo object ///////////////////////////////////////////////////////////////////////////////////// MEMORY_OBJECT_CONTROL_STATE GMM_STDCALL GmmLib::GmmClientContext::CachePolicyGetOriginalMemoryObject(GMM_RESOURCE_INFO *pResInfo) { return pGmmLibContext->GetCachePolicyObj()->CachePolicyGetOriginalMemoryObject(pResInfo); } ///////////////////////////////////////////////////////////////////////////////////// /// Member function of ClientContext class for returning /// PAT Index for a given Resource Usage Type /// /// @param[in] GMM_RESOURCE_INFO : Pointer to ResInfo object /// @param[in] GMM_RESOURCE_USAGE_TYPE : Resource Usage Type /// @return PAT index for the resource of "Usage" type. ///////////////////////////////////////////////////////////////////////////////////// uint32_t GMM_STDCALL GmmLib::GmmClientContext::CachePolicyGetPATIndex(GMM_RESOURCE_INFO *pResInfo, GMM_RESOURCE_USAGE_TYPE Usage, bool *pCompressionEnable, bool IsCpuCacheable) { return pGmmLibContext->GetCachePolicyObj()->CachePolicyGetPATIndex(pResInfo, Usage, pCompressionEnable, IsCpuCacheable); } ///////////////////////////////////////////////////////////////////////////////////// /// Member function of ClientContext class for checking if PTE is cached for a /// given resource usage type /// /// @param[in] GMM_RESOURCE_USAGE_TYPE : Resource Usage Type /// @return True if PTE cached, else false ///////////////////////////////////////////////////////////////////////////////////// uint8_t GMM_STDCALL GmmLib::GmmClientContext::CachePolicyIsUsagePTECached(GMM_RESOURCE_USAGE_TYPE Usage) { return pGmmLibContext->GetCachePolicyObj()->CachePolicyIsUsagePTECached(Usage); } ///////////////////////////////////////////////////////////////////////////////////// /// Member function of ClientContext class to return L1 Cache Control on DG2 for a /// given resource usage type /// /// @param[in] GMM_RESOURCE_USAGE_TYPE : Resource Usage Type /// @return Value of L1 Cache control ///////////////////////////////////////////////////////////////////////////////////// uint8_t GMM_STDCALL GmmLib::GmmClientContext::GetSurfaceStateL1CachePolicy(GMM_RESOURCE_USAGE_TYPE Usage) { return pGmmLibContext->GetCachePolicyObj()->GetSurfaceStateL1CachePolicy(Usage); } ///////////////////////////////////////////////////////////////////////////////////// /// Member function of ClientContext class to return Swizzle Descriptor /// given Swizzle name , ResType and bpe /// /// @param[in] EXTERNAL_SWIZZLE_NAME /// @param[in] EXTERNAL_RES_TYPE /// @param[in] bpe /// @return SWIZZLE_DESCRIPTOR* ///////////////////////////////////////////////////////////////////////////////////// const SWIZZLE_DESCRIPTOR *GMM_STDCALL GmmLib::GmmClientContext::GetSwizzleDesc(EXTERNAL_SWIZZLE_NAME ExternalSwizzleName, EXTERNAL_RES_TYPE ResType, uint8_t bpe, bool isStdSwizzle) { const SWIZZLE_DESCRIPTOR *pSwizzleDesc; pSwizzleDesc = NULL; /*#define SWITCH_SWIZZLE(Layout, res, bpe) \ pSwizzleDesc = &Layout##_##res##bpe;*/ #define CASE_BPP(Layout, Tile, msaa, xD, bpe) \ case bpe: \ pSwizzleDesc = &Layout##_##Tile##msaa##bpe; \ break; #define SWITCH_SWIZZLE(Layout, Tile, msaa, bpe) \ switch (bpe) \ { \ CASE_BPP(Layout, Tile, msaa, xD, 8); \ CASE_BPP(Layout, Tile, msaa, xD, 16); \ CASE_BPP(Layout, Tile, msaa, xD, 32); \ CASE_BPP(Layout, Tile, msaa, xD, 64); \ CASE_BPP(Layout, Tile, msaa, xD, 128); \ } #define SWIZZLE_DESC(pGmmLibContext, ExternalSwizzleName, ResType, bpe, pSwizzleDesc) \ switch (ExternalSwizzleName) \ { \ case TILEX: \ pSwizzleDesc = &INTEL_TILE_X; \ break; \ case TILEY: \ if (GmmGetSkuTable(pGmmLibContext)->FtrTileY) \ pSwizzleDesc = &INTEL_TILE_Y; \ else \ pSwizzleDesc = &INTEL_TILE_4; \ break; \ case TILEYS: \ if (GmmGetSkuTable(pGmmLibContext)->FtrTileY || isStdSwizzle) \ { \ switch (ResType) \ { \ case 0: \ SWITCH_SWIZZLE(INTEL_TILE_YS, , , bpe); \ break; \ case 1: \ SWITCH_SWIZZLE(INTEL_TILE_YS, 3D_, , bpe); \ break; \ case 2: \ SWITCH_SWIZZLE(INTEL_TILE_YS, , MSAA2_, bpe); \ break; \ case 3: \ SWITCH_SWIZZLE(INTEL_TILE_YS, , MSAA4_, bpe); \ break; \ case 4: \ SWITCH_SWIZZLE(INTEL_TILE_YS, , MSAA8_, bpe); \ break; \ case 5: \ SWITCH_SWIZZLE(INTEL_TILE_YS, , MSAA16_, bpe); \ break; \ } \ } \ else if (GmmGetSkuTable(pGmmLibContext)->FtrXe2PlusTiling) \ { \ switch (ResType) \ { \ case 0: \ SWITCH_SWIZZLE(INTEL_TILE_64, , , bpe); \ break; \ case 1: \ SWITCH_SWIZZLE(INTEL_TILE_64_V2, 3D_, , bpe); \ break; \ case 2: \ SWITCH_SWIZZLE(INTEL_TILE_64_V2, , MSAA2_, bpe); \ break; \ case 3: \ SWITCH_SWIZZLE(INTEL_TILE_64_V2, , MSAA4_, bpe); \ break; \ case 4: \ SWITCH_SWIZZLE(INTEL_TILE_64_V2, , MSAA8_, bpe); \ break; \ case 5: \ SWITCH_SWIZZLE(INTEL_TILE_64_V2, , MSAA16_, bpe); \ break; \ } \ } \ else \ { \ switch (ResType) \ { \ case 0: \ SWITCH_SWIZZLE(INTEL_TILE_64, , , bpe); \ break; \ case 1: \ SWITCH_SWIZZLE(INTEL_TILE_64, 3D_, , bpe); \ break; \ case 2: \ SWITCH_SWIZZLE(INTEL_TILE_64, , MSAA2_, bpe); \ break; \ case 3: \ case 4: \ case 5: \ SWITCH_SWIZZLE(INTEL_TILE_64, , MSAA_, bpe); \ break; \ } \ } \ case TILEW: \ case TILEYF: \ default: break; \ } \ SWIZZLE_DESC(pGmmLibContext, ExternalSwizzleName, ResType, bpe, pSwizzleDesc); return pSwizzleDesc; } ///////////////////////////////////////////////////////////////////////////////////// /// Member function of ClientContext class for returning Max MOCS index used /// on a platform /// /// @return Max MOCS Index ///////////////////////////////////////////////////////////////////////////////////// uint32_t GMM_STDCALL GmmLib::GmmClientContext::CachePolicyGetMaxMocsIndex() { GMM_CACHE_POLICY * pCachePolicy = pGmmLibContext->GetCachePolicyObj(); GmmLib::GmmGen9CachePolicy *ptr = static_cast(pCachePolicy); return ptr->CurrentMaxMocsIndex; } ///////////////////////////////////////////////////////////////////////////////////// /// Member function of ClientContext class for returning Max L1 HDC MOCS index used /// on a platform /// /// @return Max L1 HDC MOCS Index ///////////////////////////////////////////////////////////////////////////////////// uint32_t GMM_STDCALL GmmLib::GmmClientContext::CachePolicyGetMaxL1HdcMocsIndex() { GMM_CACHE_POLICY * pCachePolicy = pGmmLibContext->GetCachePolicyObj(); GmmLib::GmmGen9CachePolicy *ptr = static_cast(pCachePolicy); return ptr->CurrentMaxL1HdcMocsIndex; } ///////////////////////////////////////////////////////////////////////////////////// /// Returns count of current Special MOCS values for MOCS Table programming at GMM boot /// /// @param[in] none: /// @return uint32_t max special mocs index needed to program ///////////////////////////////////////////////////////////////////////////////////// uint32_t GMM_STDCALL GmmLib::GmmClientContext::CachePolicyGetMaxSpecialMocsIndex(void) { GMM_CACHE_POLICY *pCachePolicy = pGmmLibContext->GetCachePolicyObj(); return pCachePolicy->GetMaxSpecialMocsIndex(); } ///////////////////////////////////////////////////////////////////////////////////// /// Member function of ClientContext class for returning GMM_CACHE_POLICY_ELEMENT /// Table defiend for a platform /// /// @return Const GMM_CACHE_POLICY_ELEMENT Table ///////////////////////////////////////////////////////////////////////////////////// GMM_CACHE_POLICY_ELEMENT *GMM_STDCALL GmmLib::GmmClientContext::GetCachePolicyUsage() { return (pGmmLibContext->GetCachePolicyUsage()); } ///////////////////////////////////////////////////////////////////////////////////// /// Member function of ClientContext class for populating GMM_CACHE_SIZES /// available on a platform /// /// @return In/Out GMM_CACHE_SIZES Populated Caches sizes ///////////////////////////////////////////////////////////////////////////////////// void GMM_STDCALL GmmLib::GmmClientContext::GetCacheSizes(GMM_CACHE_SIZES *pCacheSizes) { return GmmGetCacheSizes(pGmmLibContext, pCacheSizes); } ///////////////////////////////////////////////////////////////////////////////////// /// Member function of ClientContext class for returning GMM_CACHE_POLICY_ELEMENT /// for a given Resource Usage Type /// /// @return GMM_CACHE_POLICY_ELEMENT ///////////////////////////////////////////////////////////////////////////////////// GMM_CACHE_POLICY_ELEMENT GMM_STDCALL GmmLib::GmmClientContext::GetCachePolicyElement(GMM_RESOURCE_USAGE_TYPE Usage) { return pGmmLibContext->GetCachePolicyElement(Usage); } ///////////////////////////////////////////////////////////////////////////////////// /// Member function of ClientContext class for returning GMM_CACHE_POLICY_TBL_ELEMENT /// for a given Mocs Index /// /// @return GMM_CACHE_POLICY_TBL_ELEMENT ///////////////////////////////////////////////////////////////////////////////////// GMM_CACHE_POLICY_TBL_ELEMENT GMM_STDCALL GmmLib::GmmClientContext::GetCachePolicyTlbElement(uint32_t MocsIdx) { return pGmmLibContext->GetCachePolicyTlbElement()[MocsIdx]; } ///////////////////////////////////////////////////////////////////////////////////// /// Member function of ClientContext class for returning GMM_PLATFORM_INFO data /// /// @return GMM_PLATFORM_INFO& ///////////////////////////////////////////////////////////////////////////////////// GMM_PLATFORM_INFO &GMM_STDCALL GmmLib::GmmClientContext::GetPlatformInfo() { return pGmmLibContext->GetPlatformInfo(); } ///////////////////////////////////////////////////////////////////////////////////// /// Member function of ClientContext class for getting Alignment info /// /// @return void ////////////////////////////////////////////////////////////////////////////////// void GMM_STDCALL GmmLib::GmmClientContext::GetExtendedTextureAlign(uint32_t Mode, ALIGNMENT &UnitAlign) { ALIGNMENT AlignInfo; pGmmLibContext->GetPlatformInfoObj()->ApplyExtendedTexAlign(Mode, AlignInfo); UnitAlign = AlignInfo; } ///////////////////////////////////////////////////////////////////////////////////// /// Member function of ClientContext class for returning SKU_FEATURE_TABLE data /// /// @return SKU_FEATURE_TABLE& ///////////////////////////////////////////////////////////////////////////////////// const SKU_FEATURE_TABLE &GMM_STDCALL GmmLib::GmmClientContext::GetSkuTable() { return pGmmLibContext->GetSkuTable(); } ///////////////////////////////////////////////////////////////////////////////////// /// Member function of ClientContext class for returning whether the given Resource /// format is Planar /// /// @return True if the Given format is planar ///////////////////////////////////////////////////////////////////////////////////// uint8_t GMM_STDCALL GmmLib::GmmClientContext::IsPlanar(GMM_RESOURCE_FORMAT Format) { return GmmIsPlanar(Format); } ///////////////////////////////////////////////////////////////////////////////////// /// Member function of ClientContext class for returning whether the given Resource /// format is P0xx /// /// @return True if the Given format is P0xx ///////////////////////////////////////////////////////////////////////////////////// uint8_t GMM_STDCALL GmmLib::GmmClientContext::IsP0xx(GMM_RESOURCE_FORMAT Format) { return GmmIsP0xx(Format); } ///////////////////////////////////////////////////////////////////////////////////// /// Member function of ClientContext class for returning whether the given Resource /// format is UV Packed plane /// /// @return True if the Given format is UV packed ///////////////////////////////////////////////////////////////////////////////////// uint8_t GMM_STDCALL GmmLib::GmmClientContext::IsUVPacked(GMM_RESOURCE_FORMAT Format) { return GmmIsUVPacked(Format); } ///////////////////////////////////////////////////////////////////////////////////// /// Member function of ClientContext class for returning whether the given Resource /// format is Compressed /// /// @return True if the Given format is Compressed ///////////////////////////////////////////////////////////////////////////////////// uint8_t GMM_STDCALL GmmLib::GmmClientContext::IsCompressed(GMM_RESOURCE_FORMAT Format) { return (Format > GMM_FORMAT_INVALID) && (Format < GMM_RESOURCE_FORMATS) && pGmmLibContext->GetPlatformInfo().FormatTable[Format].Compressed; } ///////////////////////////////////////////////////////////////////////////////////// /// Member function of ClientContext class for returning whether the given Resource /// format is YUV Packed plane /// /// @return True if the Given format is YUV packed ///////////////////////////////////////////////////////////////////////////////////// uint8_t GMM_STDCALL GmmLib::GmmClientContext::IsYUVPacked(GMM_RESOURCE_FORMAT Format) { return GmmIsYUVPacked(Format); } ///////////////////////////////////////////////////////////////////////////////////// /// Member function of ClientContext class for returning its GMM_SURFACESTATE_FORMAT /// for the given equivalent GMM_RESOURCE_FORMAT type /// /// @return GMM_SURFACESTATE_FORMAT for the given format type ///////////////////////////////////////////////////////////////////////////////////// GMM_SURFACESTATE_FORMAT GMM_STDCALL GmmLib::GmmClientContext::GetSurfaceStateFormat(GMM_RESOURCE_FORMAT Format) { // ToDo: Remove the definition of GmmGetSurfaceStateFormat(Format) return ((Format > GMM_FORMAT_INVALID) && (Format < GMM_RESOURCE_FORMATS)) ? pGmmLibContext->GetPlatformInfo().FormatTable[Format].SurfaceStateFormat : GMM_SURFACESTATE_FORMAT_INVALID; } ///////////////////////////////////////////////////////////////////////////////////// /// Member function of ClientContext class for returning /// RENDER_SURFACE_STATE::CompressionFormat /// /// @return uint8_t ///////////////////////////////////////////////////////////////////////////////////// uint8_t GMM_STDCALL GmmLib::GmmClientContext::GetSurfaceStateCompressionFormat(GMM_RESOURCE_FORMAT Format) { __GMM_ASSERT((Format > GMM_FORMAT_INVALID) && (Format < GMM_RESOURCE_FORMATS)); return pGmmLibContext->GetPlatformInfo().FormatTable[Format].CompressionFormat.AuxL1eFormat; } ///////////////////////////////////////////////////////////////////////////////////// /// Member function of ClientContext class for returning /// MEDIA_SURFACE_STATE::CompressionFormat /// /// @return uint8_t ///////////////////////////////////////////////////////////////////////////////////// uint8_t GMM_STDCALL GmmLib::GmmClientContext::GetMediaSurfaceStateCompressionFormat(GMM_RESOURCE_FORMAT Format) { __GMM_ASSERT((Format > GMM_FORMAT_INVALID) && (Format < GMM_RESOURCE_FORMATS)); return pGmmLibContext->GetPlatformInfoObj()->OverrideCompressionFormat(Format, (uint8_t)0x1); } ///////////////////////////////////////////////////////////////////////////////////// /// Member function of ClientContext class for returning E2E compression format /// /// @return GMM_E2ECOMP_FORMAT ///////////////////////////////////////////////////////////////////////////////////// GMM_E2ECOMP_FORMAT GMM_STDCALL GmmLib::GmmClientContext::GetLosslessCompressionType(GMM_RESOURCE_FORMAT Format) { // ToDo: Remove the definition of GmmGetLosslessCompressionType(Format) __GMM_ASSERT((Format > GMM_FORMAT_INVALID) && (Format < GMM_RESOURCE_FORMATS)); return pGmmLibContext->GetPlatformInfo().FormatTable[Format].CompressionFormat.AuxL1eFormat; } ///////////////////////////////////////////////////////////////////////////////////// /// Member function of ClientContext class to return InternalGpuVaMax value /// stored in pGmmLibContext /// /// @return GMM_SUCCESS ///////////////////////////////////////////////////////////////////////////////////// uint64_t GMM_STDCALL GmmLib::GmmClientContext::GetInternalGpuVaRangeLimit() { return pGmmLibContext->GetInternalGpuVaRangeLimit(); } ///////////////////////////////////////////////////////////////////////////////////// /// Member function of ClientContext class for creation of Custiom ResourceInfo Object . /// @see GmmLib::GmmResourceInfoCommon::Create() /// /// @param[in] pCreateParams: Flags which specify what sort of resource to create /// @return Pointer to GmmResourceInfo class. ///////////////////////////////////////////////////////////////////////////////////// GMM_RESOURCE_INFO *GMM_STDCALL GmmLib::GmmClientContext::CreateCustomResInfoObject(GMM_RESCREATE_CUSTOM_PARAMS *pCreateParams) { GMM_RESOURCE_INFO *pRes = NULL; GmmClientContext * pClientContextIn = NULL; pClientContextIn = this; if((pRes = new GMM_RESOURCE_INFO(pClientContextIn)) == NULL) { GMM_ASSERTDPF(0, "Allocation failed!"); goto ERROR_CASE; } if(pRes->CreateCustomRes(*pGmmLibContext, *pCreateParams) != GMM_SUCCESS) { goto ERROR_CASE; } return (pRes); ERROR_CASE: if(pRes) { DestroyResInfoObject(pRes); } return (NULL); } #ifndef __GMM_KMD__ ///////////////////////////////////////////////////////////////////////////////////// /// Member function of ClientContext class for creation of Custiom ResourceInfo Object . /// @see GmmLib::GmmResourceInfoCommon::CreateCustomResInfoObject_2() /// /// @param[in] pCreateParams: Flags which specify what sort of resource to create /// @return Pointer to GmmResourceInfo class. ///////////////////////////////////////////////////////////////////////////////////// GMM_RESOURCE_INFO *GMM_STDCALL GmmLib::GmmClientContext::CreateCustomResInfoObject_2(GMM_RESCREATE_CUSTOM_PARAMS_2 *pCreateParams) { GMM_RESOURCE_INFO *pRes = NULL; GmmClientContext * pClientContextIn = NULL; pClientContextIn = this; if((pRes = new GMM_RESOURCE_INFO(pClientContextIn)) == NULL) { GMM_ASSERTDPF(0, "Allocation failed!"); goto ERROR_CASE; } if(pRes->CreateCustomRes_2(*pGmmLibContext, *pCreateParams) != GMM_SUCCESS) { goto ERROR_CASE; } return (pRes); ERROR_CASE: if(pRes) { DestroyResInfoObject(pRes); } return (NULL); } #endif ///////////////////////////////////////////////////////////////////////////////////// /// Member function of ClientContext class for creation of ResourceInfo Object . /// @see GmmLib::GmmResourceInfoCommon::Create() /// /// @param[in] pCreateParams: Flags which specify what sort of resource to create /// @return Pointer to GmmResourceInfo class. ///////////////////////////////////////////////////////////////////////////////////// GMM_RESOURCE_INFO *GMM_STDCALL GmmLib::GmmClientContext::CreateResInfoObject(GMM_RESCREATE_PARAMS *pCreateParams) { GMM_RESOURCE_INFO *pRes = NULL; GmmClientContext * pClientContextIn = NULL; #if(!defined(GMM_UNIFIED_LIB)) pClientContextIn = pGmmLibContext->pGmmGlobalClientContext; #else pClientContextIn = this; #endif GMM_DPF_ENTER; // GMM_RESOURCE_INFO... if(pCreateParams->pPreallocatedResInfo) { pRes = new(pCreateParams->pPreallocatedResInfo) GmmLib::GmmResourceInfo(pClientContextIn); // Use preallocated memory as a class pCreateParams->Flags.Info.__PreallocatedResInfo = pRes->GetResFlags().Info.__PreallocatedResInfo = 1; // Set both in case we can die before copying over the flags. } else { if((pRes = new GMM_RESOURCE_INFO(pClientContextIn)) == NULL) { GMM_ASSERTDPF(0, "Allocation failed!"); goto ERROR_CASE; } } if(pRes->Create(*pGmmLibContext, *pCreateParams) != GMM_SUCCESS) { goto ERROR_CASE; } GMM_DPF_EXIT; return (pRes); ERROR_CASE: if(pRes) { DestroyResInfoObject(pRes); } return (NULL); } ///////////////////////////////////////////////////////////////////////////////////// /// Member function of ClientContext class for creation of ResourceInfo Object from /// already created Src ResInfo object /// @see GmmLib::GmmResourceInfoCommon::Create() /// /// @param[in] pSrcRes: Existing ResInfoObj /// @return Pointer to GmmResourceInfo class. ///////////////////////////////////////////////////////////////////////////////////// GMM_RESOURCE_INFO *GMM_STDCALL GmmLib::GmmClientContext::CopyResInfoObject(GMM_RESOURCE_INFO *pSrcRes) { GMM_RESOURCE_INFO *pResCopy = NULL; GmmClientContext * pClientContextIn = NULL; #if(!defined(GMM_UNIFIED_LIB)) pClientContextIn = pGmmLibContext->pGmmGlobalClientContext; #else pClientContextIn = this; #endif __GMM_ASSERTPTR(pSrcRes, NULL); pResCopy = new GMM_RESOURCE_INFO(pClientContextIn); if(!pResCopy) { GMM_ASSERTDPF(0, "Allocation failed."); return NULL; } // Set the GmmLibContext for newly created DestResInfo object pResCopy->SetGmmLibContext(pGmmLibContext); *pResCopy = *pSrcRes; // Set the client type to the client for which this resinfo is created pResCopy->SetClientType(GetClientType()); // We are allocating new class, flag must be false to avoid leak at DestroyResource pResCopy->GetResFlags().Info.__PreallocatedResInfo = 0; return (pResCopy); } ///////////////////////////////////////////////////////////////////////////////////// /// Member function of ClientContext class for copy of ResourceInfo Object from /// already created Src ResInfo object /// @see GmmLib::GmmResourceInfoCommon::Create() /// /// @param[in] pDst: Pointer to memory when pSrc will be copied /// @param[in] pSrc: Pointer to GmmResourceInfo class that needs to be copied ///////////////////////////////////////////////////////////////////////////////////// void GMM_STDCALL GmmLib::GmmClientContext::ResMemcpy(void *pDst, void *pSrc) { GmmClientContext *pClientContextIn = NULL; #if(!defined(GMM_UNIFIED_LIB)) pClientContextIn = pGmmLibContext->pGmmGlobalClientContext; #else pClientContextIn = this; #endif GMM_RESOURCE_INFO *pResSrc = reinterpret_cast(pSrc); // Init memory correctly, in case the pointer is a raw memory pointer GMM_RESOURCE_INFO *pResDst = new(pDst) GMM_RESOURCE_INFO(pClientContextIn); // Set the GmmLibContext for newly created DestResInfo object pResDst->SetGmmLibContext(pGmmLibContext); *pResDst = *pResSrc; // Set the client type to the client for which this resinfo is created pResDst->SetClientType(GetClientType()); } ///////////////////////////////////////////////////////////////////////////////////// /// Member function of ClientContext class for Destroying ResInfoObject /// /// @param[in] pResInfo: Pointer to ResInfoObject /// @return void. ///////////////////////////////////////////////////////////////////////////////////// void GMM_STDCALL GmmLib::GmmClientContext::DestroyResInfoObject(GMM_RESOURCE_INFO *pResInfo) { __GMM_ASSERTPTR(pResInfo, VOIDRETURN); if(pResInfo->GetResFlags().Info.__PreallocatedResInfo) { *pResInfo = GmmLib::GmmResourceInfo(); } else { delete pResInfo; pResInfo = NULL; } } ///////////////////////////////////////////////////////////////////////////////////// /// Member function of ClientContext class for creation of PAgeTableMgr Object . /// @see GmmLib::GMM_PAGETABLE_MGR::GMM_PAGETABLE_MGR /// /// @param[in] TTFags /// @return Pointer to GMM_PAGETABLE_MGR class. ///////////////////////////////////////////////////////////////////////////////////// GMM_PAGETABLE_MGR* GMM_STDCALL GmmLib::GmmClientContext::CreatePageTblMgrObject(uint32_t TTFlags) { if (!IsDeviceCbReceived) { GMM_ASSERTDPF(0, "Device_callbacks not set"); return NULL; } return CreatePageTblMgrObject(&DeviceCB, TTFlags); } ///////////////////////////////////////////////////////////////////////////////////// /// Member function of ClientContext class for creation of PAgeTableMgr Object . /// @see GmmLib::GMM_PAGETABLE_MGR::GMM_PAGETABLE_MGR /// /// @param[in] pDevCb: Pointer to GMM_DEVICE_CALLBACKS_INT /// @param[in] TTFags /// @return Pointer to GMM_PAGETABLE_MGR class. // move the code to new overloaded the API and remove this API once all clients are moved to new API. ///////////////////////////////////////////////////////////////////////////////////// GMM_PAGETABLE_MGR* GMM_STDCALL GmmLib::GmmClientContext::CreatePageTblMgrObject(GMM_DEVICE_CALLBACKS_INT* pDevCb, uint32_t TTFlags) { GMM_PAGETABLE_MGR* pPageTableMgr = NULL; pPageTableMgr = new GMM_PAGETABLE_MGR(pDevCb, TTFlags, this); return pPageTableMgr; } ///////////////////////////////////////////////////////////////////////////////////// /// Member function of ClientContext class for destroy of PageTableMgr Object . /// /// @param[in] pPageTableMgr: Pointer to GMM_PAGETABLE_MGR /// @return void. ///////////////////////////////////////////////////////////////////////////////////// void GMM_STDCALL GmmLib::GmmClientContext::DestroyPageTblMgrObject(GMM_PAGETABLE_MGR* pPageTableMgr) { if (pPageTableMgr) { delete pPageTableMgr; } } #ifdef GMM_LIB_DLL ///////////////////////////////////////////////////////////////////////////////////// /// Member function of ClientContext class for creation of ResourceInfo Object . /// @see GmmLib::GmmResourceInfoCommon::Create() /// /// @param[in] pCreateParams: Flags which specify what sort of resource to create /// @return Pointer to GmmResourceInfo class. ///////////////////////////////////////////////////////////////////////////////////// GMM_RESOURCE_INFO *GMM_STDCALL GmmLib::GmmClientContext::CreateResInfoObject(GMM_RESCREATE_PARAMS * pCreateParams, GmmClientAllocationCallbacks *pAllocCbs) { if(!pAllocCbs || !pAllocCbs->pfnAllocation) { return CreateResInfoObject(pCreateParams); } else { GMM_RESOURCE_INFO *pRes = NULL; void * pConst = NULL; // GMM_RESOURCE_INFO... if(pCreateParams->pPreallocatedResInfo) { pRes = new(pCreateParams->pPreallocatedResInfo) GmmLib::GmmResourceInfo(this); // Use preallocated memory as a class pCreateParams->Flags.Info.__PreallocatedResInfo = pRes->GetResFlags().Info.__PreallocatedResInfo = 1; // Set both in case we can die before copying over the flags. } else { pConst = pAllocCbs->pfnAllocation(pAllocCbs->pUserData, sizeof(GMM_RESOURCE_INFO), alignof(GMM_RESOURCE_INFO)); if(pConst == NULL) { GMM_ASSERTDPF(0, "Allocation failed!"); goto ERROR_CASE; } else { pRes = new(pConst) GMM_RESOURCE_INFO(this); } } if(pRes->Create(*pGmmLibContext, *pCreateParams) != GMM_SUCCESS) { goto ERROR_CASE; } return (pRes); ERROR_CASE: if(pRes) { if(pAllocCbs->pfnFree) { #ifdef _WIN32 pRes->~GmmResourceInfoWin(); #else pRes->~GmmResourceInfoLin(); #endif pAllocCbs->pfnFree(pAllocCbs->pUserData, (void *)pRes); } } return (NULL); } } ///////////////////////////////////////////////////////////////////////////////////// /// Member function of ClientContext class for Destroying ResInfoObject /// /// @param[in] pResInfo: Pointer to ResInfoObject /// @return void. ///////////////////////////////////////////////////////////////////////////////////// void GMM_STDCALL GmmLib::GmmClientContext::DestroyResInfoObject(GMM_RESOURCE_INFO * pResInfo, GmmClientAllocationCallbacks *pAllocCbs) { __GMM_ASSERTPTR(pResInfo, VOIDRETURN); if(!pAllocCbs || !pAllocCbs->pfnFree) { return DestroyResInfoObject(pResInfo); } else { if(pResInfo->GetResFlags().Info.__PreallocatedResInfo) { *pResInfo = GmmLib::GmmResourceInfo(); } else { #ifdef _WIN32 pResInfo->~GmmResourceInfoWin(); #else pResInfo->~GmmResourceInfoLin(); #endif pAllocCbs->pfnFree(pAllocCbs->pUserData, (void *)pResInfo); pResInfo = NULL; } } } #endif ///////////////////////////////////////////////////////////////////////////////////// /// Member function of ClientContext class for creation of PAgeTableMgr Object . /// @see GmmLib::GMM_PAGETABLE_MGR::GMM_PAGETABLE_MGR /// /// @param[in] TTFags /// @return Pointer to GMM_PAGETABLE_MGR class. ///////////////////////////////////////////////////////////////////////////////////// GMM_PAGETABLE_MGR* GMM_STDCALL GmmLib::GmmClientContext::CreatePageTblMgrObject(uint32_t TTFlags, GmmClientAllocationCallbacks* pAllocCbs) { if (!IsDeviceCbReceived) { GMM_ASSERTDPF(0, "Device_callbacks not set"); return NULL; } return CreatePageTblMgrObject( &DeviceCB, TTFlags, pAllocCbs); } ///////////////////////////////////////////////////////////////////////////////////// /// Member function of ClientContext class for creation of PAgeTableMgr Object . /// @see GmmLib::GMM_PAGETABLE_MGR::GMM_PAGETABLE_MGR /// /// @param[in] pDevCb: Pointer to GMM_DEVICE_CALLBACKS_INT /// @param[in] TTFags /// @return Pointer to GMM_PAGETABLE_MGR class. /// move the code to new overloaded the API and remove this API once all clients are moved to new API. ///////////////////////////////////////////////////////////////////////////////////// GMM_PAGETABLE_MGR* GMM_STDCALL GmmLib::GmmClientContext::CreatePageTblMgrObject( GMM_DEVICE_CALLBACKS_INT* pDevCb, uint32_t TTFlags, GmmClientAllocationCallbacks* pAllocCbs) { if (!pAllocCbs || !pAllocCbs->pfnAllocation) { return CreatePageTblMgrObject( pDevCb, TTFlags); } else { GMM_PAGETABLE_MGR* pPageTableMgr = NULL; return pPageTableMgr; } } ///////////////////////////////////////////////////////////////////////////////////// /// Member function of ClientContext class for destroy of PageTableMgr Object . /// /// @param[in] pPageTableMgr: Pointer to GMM_PAGETABLE_MGR /// @return void. ///////////////////////////////////////////////////////////////////////////////////// void GMM_STDCALL GmmLib::GmmClientContext::DestroyPageTblMgrObject(GMM_PAGETABLE_MGR* pPageTableMgr, GmmClientAllocationCallbacks* pAllocCbs) { if (!pAllocCbs || !pAllocCbs->pfnFree) { return DestroyPageTblMgrObject(pPageTableMgr); } } //////////////////////////////////////////////////////////////////////////////////// /// Member function of ClientContext class for doing device specific operations. /// Clients must call it before any Gfx resource (incl. svm) /// is mapped, must happen before any use of GfxPartition, or PageTableMgr init. /// @param[in] DeviceInfo : Pointer to info related to Device Operations. /// @return GMM_STATUS. ////////////////////////////////////////////////////////////////////////////////////////// GMM_STATUS GMM_STDCALL GmmLib::GmmClientContext::GmmSetDeviceInfo(GMM_DEVICE_INFO* DeviceInfo) { GMM_STATUS Status = GMM_SUCCESS; if (DeviceInfo == NULL || DeviceInfo->pDeviceCb == NULL) { return GMM_INVALIDPARAM; } DeviceCB = *(DeviceInfo->pDeviceCb); IsDeviceCbReceived = 1; return Status; } ///////////////////////////////////////////////////////////////////////////////////// /// Gmm lib DLL C wrapper for creating GmmLib::GmmClientContext object /// This C wrapper is used for Multi-Adapter scenarios to take in Adapter's BDF as /// additional input argument to derive its correspodning GmmLibContext /// /// @see Class GmmLib::GmmClientContext /// /// @param[in] ClientType : describles the UMD clients such as OCL, DX, OGL, Vulkan etc /// @param[in] sBDF: Adapter's BDF info /// /// @return Pointer to GmmClientContext, if Context is created ///////////////////////////////////////////////////////////////////////////////////// extern "C" GMM_CLIENT_CONTEXT *GMM_STDCALL GmmCreateClientContextForAdapter(GMM_CLIENT ClientType, ADAPTER_BDF sBdf) { GMM_CLIENT_CONTEXT *pGmmClientContext = nullptr; GMM_LIB_CONTEXT * pLibContext = pGmmMALibContext->GetAdapterLibContext(sBdf); if (pLibContext) { pGmmClientContext = new GMM_CLIENT_CONTEXT(ClientType, pLibContext); } return pGmmClientContext; } ///////////////////////////////////////////////////////////////////////////////////// /// Gmm lib DLL exported C wrapper for deleting GmmLib::GmmClientContext object /// @see Class GmmLib::GmmClientContext /// /// @param[in] GMM_CLIENT_CONTEXT * : Pointer to ClientContext object /// @return Void ///////////////////////////////////////////////////////////////////////////////////// extern "C" void GMM_STDCALL GmmDeleteClientContext(GMM_CLIENT_CONTEXT *pGmmClientContext) { if(pGmmClientContext) { delete pGmmClientContext; pGmmClientContext = NULL; } } gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/GlobalInfo/GmmInfo.cpp000066400000000000000000001335001466655022700241310ustar00rootroot00000000000000/*============================================================================== Copyright(c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ============================================================================*/ #include "Internal/Common/GmmLibInc.h" #if(!defined(__GMM_KMD__) && !GMM_LIB_DLL_MA) int32_t GmmLib::Context::RefCount = 0; #endif #ifdef GMM_LIB_DLL // Create Mutex Object used for syncronization of ProcessSingleton Context #if !GMM_LIB_DLL_MA #ifdef _WIN32 GMM_MUTEX_HANDLE GmmLib::Context::SingletonContextSyncMutex = ::CreateMutex(NULL, false, NULL); #else //_WIN32 GMM_MUTEX_HANDLE GmmLib::Context::SingletonContextSyncMutex = PTHREAD_MUTEX_INITIALIZER; #endif // _WIN32 #endif //!GMM_LIB_DLL_MA ///////////////////////////////////////////////////////////////////////////////////// /// GMM lib DLL Multi Adapter Functions /// 1. This is the main holder of the Gmmlib Context /// 2. There is only one Multi-Adpater Context object created per process. /// 3. Gmmlib dll is loaded only once per process, This done by the first UMD client /// requesting Libcontext on a first Adpater to be registered with Gmmlib. /// 4. Gmmlib dll is Unloaded only once per process, this is done by the last client /// destroying the LibContext on the only last registered Adapter with Gmmlib. /// 5. The LibContext for an Adapter is same across all the N clients and is always /// equal. /// 6. The ClientContext for all the N clients on particaluar Adapter is unique and /// never equal. /// 7 Ex: N UMD clients querying GmmLib for an GPU Adapter's Properties will have the /// Same/Single LibContext and Unique N ClientContexts for that same adpater, on /// same process. /// 8. GmmLib is dynamically scalable for any number of GPU Adapters and any number /// of Clients per Adapter. /// 9. In Multiprocessing, for a process, the Gmmlib Multi-Adpater Context /// object is protected/syncronized using the Lock/UnLockMAContextSyncMutex /// 9. In Multiprocessing, for a process with Gmmlib Multi-Adpater Context the /// LibContetxt is protected/syncronized using Lock/unLockSingletonContextSyncMutex ///////////////////////////////////////////////////////////////////////////////////// GMM_MA_LIB_CONTEXT *pGmmMALibContext = NULL; ///////////////////////////////////////////////////////////////////////////////////// /// Function to create GmmMultiAdapterContext Object /// Called only during dll load time. /// Since Linux doesnt have DLL Main equivalent, adding __attribute__((constructor)) /// for this GmmCreateMultiAdapterContext() ///////////////////////////////////////////////////////////////////////////////////// extern "C" GMM_LIB_API_CONSTRUCTOR void GmmCreateMultiAdapterContext() { if(!pGmmMALibContext) { // This is called only during dll load // Initializes the MA context. pGmmMALibContext = new GMM_MA_LIB_CONTEXT(); } } ///////////////////////////////////////////////////////////////////////////////////// /// Function to Destroy GmmMultiAdapterContext Object /// Called Only during Dll Unload. /// Since Linux doesnt have DLL Main equivalent, adding __attribute__((destructor)) /// for this GmmDestroyMultiAdapterContext() ///////////////////////////////////////////////////////////////////////////////////// extern "C" GMM_LIB_API_DESTRUCTOR void GmmDestroyMultiAdapterContext() { if(pGmmMALibContext) { // Before destroying GmmMultiAdapterContext, check if all the Adapters have // their GmmLibContext destroyed. // At this point the linked list is empty and pHeadNode = NULL & NumAdapter=0. if(!pGmmMALibContext->GetNumAdapters()) { delete pGmmMALibContext; pGmmMALibContext = NULL; } } } ///////////////////////////////////////////////////////////////////////////////////// /// GMM lib DLL function for creating Singleton Context (GmmLib::Context) /// object which shall be process singleton across all UMD clients within a process /// This function creates an object in the global MultiAdapter Context.. /// @see Class GmmLib::Context /// /// @param[in] Platform: platform variable. Includes product family (Haswell, Cherryview, /// Broxton) with related render and display core revision (GEN3, // ..., GEN10) /// @param[in] pSkuTable: Pointer to the sku feature table. Set of capabilities to /// allow code paths to be feature based and GEN agnostic. /// @param[in] pWaTable: Pointer to the work around table. A set of anti-features, /// often in early/prototype silicon that require work-arounds /// until they are resolved to allow code paths to be GEN agnostic. /// @param[in] pGtSysInfo: Pointer to the GT system info. Contains various GT System /// Information such as EU counts, Thread Counts, Cache Sizes etc. /// @param[in] sBDF: Adapter's BDF info for which SingletonContext has to be created /// @return GMM_SUCCESS if Context is created, GMM_ERROR otherwise ///////////////////////////////////////////////////////////////////////////////////// #ifdef _WIN32 extern "C" GMM_STATUS GMM_STDCALL GmmCreateLibContext(const PLATFORM Platform, const SKU_FEATURE_TABLE *pSkuTable, const WA_TABLE * pWaTable, const GT_SYSTEM_INFO * pGtSysInfo, ADAPTER_BDF sBdf) #else extern "C" GMM_STATUS GMM_STDCALL GmmCreateLibContext(const PLATFORM Platform, const void * pSkuTable, const void * pWaTable, const void * pGtSysInfo, ADAPTER_BDF sBdf, const GMM_CLIENT ClientType) #endif { __GMM_ASSERTPTR(pSkuTable, GMM_ERROR); __GMM_ASSERTPTR(pWaTable, GMM_ERROR); __GMM_ASSERTPTR(pGtSysInfo, GMM_ERROR); // If pGmmMALibContext object is NULL, return error as DLL load would have failed if(!pGmmMALibContext) { return GMM_ERROR; } #if LHDM return pGmmMALibContext->AddContext(Platform, pSkuTable, pWaTable, pGtSysInfo, sBdf, DeviceRegistryPath); #else return pGmmMALibContext->AddContext(Platform, pSkuTable, pWaTable, pGtSysInfo, sBdf, ClientType); #endif } ///////////////////////////////////////////////////////////////////////////////////// /// GMM lib DLL function for deleting the Singleton Context. /// Reference Count will be decremented and once the reference count reaches 0, /// Singleton Context will be freed in memory. This removes a singleton context from /// the global MultiAdapter Context /// /// @param[in] sbdf: Adapter's BDF info that needs its SingletonContext to be freed ///////////////////////////////////////////////////////////////////////////////////// extern "C" void GMM_STDCALL GmmLibContextFree(ADAPTER_BDF sBdf) { if (pGmmMALibContext) { pGmmMALibContext->RemoveContext(sBdf); } } ///////////////////////////////////////////////////////////////////////////////////// /// Constructor to zero initialize the GmmLib::GmmMultiAdapterContext object and create /// GmmMultiAdapterContext class object ///////////////////////////////////////////////////////////////////////////////////// GmmLib::GmmMultiAdapterContext::GmmMultiAdapterContext() { this->NumAdapters = 0; pCpuReserveBase = NULL; CpuReserveSize = 0; // The Multi-Adapter Initialization is done dynamiclly using a Single Linked list Vector // pHeadNode points to the root node of the linked list and registers the first // adapter received from UMD. // Initializing to NULL at DLL load. this->pHeadNode = NULL; // Initializes the GmmLib::GmmMultiAdapterContext sync Mutex // This is required whenever any update has to be done Multiadapter context // This includes Addition, deletion and search operations of the GMM_ADAPTER_INFO linked list MAContextSyncMutex = PTHREAD_MUTEX_INITIALIZER; } ///////////////////////////////////////////////////////////////////////////////////// /// Destructor to free GmmLib::GmmMultiAdapterContext object memory ///////////////////////////////////////////////////////////////////////////////////// GmmLib::GmmMultiAdapterContext::~GmmMultiAdapterContext() { uint32_t i = 0; // Un-initializes the GmmLib::GmmMultiAdapterContext sync Mutex pthread_mutex_destroy(&MAContextSyncMutex); } ///////////////////////////////////////////////////////////////////////////////////// /// Multi Adapter member function for creating Singleton Context (GmmLib::Context) /// object which shall be process singleton across all UMD clients within a process. /// This function is thread safe for the MultiAdapterContext object. /// @see Class GmmLib::Context /// /// @param[in] Platform: platform variable. Includes product family (Haswell, Cherryview, /// Broxton) with related render and display core revision (GEN3, // ..., GEN10) /// @param[in] pSkuTable: Pointer to the sku feature table. Set of capabilities to /// allow code paths to be feature based and GEN agnostic. /// @param[in] pWaTable: Pointer to the work around table. A set of anti-features, /// often in early/prototype silicon that require work-arounds /// until they are resolved to allow code paths to be GEN agnostic. /// @param[in] pGtSysInfo: Pointer to the GT system info. Contains various GT System /// Information such as EU counts, Thread Counts, Cache Sizes etc. /// @param[in] sBDF: Adapter's BDF info for which SingletonContext i.e Adapter Node /// has to be created. /// @return GMM_SUCCESS if Context is created, GMM_ERROR otherwise ///////////////////////////////////////////////////////////////////////////////////// #if LHDM GMM_STATUS GMM_STDCALL GmmLib::GmmMultiAdapterContext::AddContext(const PLATFORM Platform, const SKU_FEATURE_TABLE *_pSkuTable, const WA_TABLE *_pWaTable, const GT_SYSTEM_INFO *_pGtSysInfo, ADAPTER_BDF sBdf, const char *DeviceRegistryPath, uint32_t PhysicalAdapterIndex) #else GMM_STATUS GMM_STDCALL GmmLib::GmmMultiAdapterContext::AddContext(const PLATFORM Platform, const void *_pSkuTable, const void *_pWaTable, const void *_pGtSysInfo, ADAPTER_BDF sBdf, const GMM_CLIENT ClientType) #endif { __GMM_ASSERTPTR(_pSkuTable, GMM_ERROR); __GMM_ASSERTPTR(_pWaTable, GMM_ERROR); __GMM_ASSERTPTR(_pGtSysInfo, GMM_ERROR); GMM_STATUS Status = GMM_SUCCESS; SKU_FEATURE_TABLE *pSkuTable; WA_TABLE *pWaTable; GT_SYSTEM_INFO *pSysInfo; GMM_LIB_CONTEXT *pGmmLibContext = NULL; GmmLib::GMM_ADAPTER_INFO *pNode = NULL; pSkuTable = (SKU_FEATURE_TABLE *)_pSkuTable; pWaTable = (WA_TABLE *)_pWaTable; pSysInfo = (GT_SYSTEM_INFO *)_pGtSysInfo; GMM_STATUS SyncLockStatus = LockMAContextSyncMutex(); if (SyncLockStatus != GMM_SUCCESS) { return SyncLockStatus; } // see if a context with the given BDF already exists pNode = GetAdapterNodeUnlocked(sBdf); if (pNode) { // The requested adapter context already exists. increment the reference count. // No further initialization needed. pNode->pGmmLibContext->IncrementRefCount(); UnLockMAContextSyncMutex(); return GMM_SUCCESS; } // No context exists for this bdf. Add a new node to store the context. pNode = AddAdapterNode(); if (pNode == NULL) { UnLockMAContextSyncMutex(); return GMM_ERROR; } // No context for this adapter yet, Lets create a new LibContext pGmmLibContext = new GMM_LIB_CONTEXT(); if (pGmmLibContext == NULL) { RemoveAdapterNode(pNode); pNode = NULL; UnLockMAContextSyncMutex(); return GMM_ERROR; } pGmmLibContext->IncrementRefCount(); Status = (pGmmLibContext->InitContext(Platform, pSkuTable, pWaTable, pSysInfo, ClientType)); if (Status != GMM_SUCCESS) { //clean everything and return error pGmmLibContext->DecrementRefCount(); pGmmLibContext->DestroyContext(); // Delete/free the LibContext object delete pGmmLibContext; RemoveAdapterNode(pNode); UnLockMAContextSyncMutex(); return GMM_ERROR; } #if LHDM // Initialize SingletonContext Data. // TBD: ProcessHeap creation requires size and GfxAddress parameters. These parameters are constants // and are given by GMM lib internally by PageTableMgr. Hence pHeapObj should be created here at the // time of SingletonContext creation. But untill all UMD clients have moved to GMM DLL, then we will // create this here. pGmmLibContext->pHeapObj = NULL; pGmmLibContext->ProcessHeapCounter = 0; // TBD: ProcessVA Gfx partition should be created here using VirtualAlloc at the time of SingletonContext // creation. But untill all UMD clients have moved to GMM DLL, then we will // create this here. pGmmLibContext->ProcessVA = {0}; pGmmLibContext->ProcessVACounter = 0; pGmmLibContext->IsSVMReserved = 0; pGmmLibContext->NullCCSTileAddress = 0; #endif pGmmLibContext->sBdf = sBdf; pNode->pGmmLibContext = pGmmLibContext; UnLockMAContextSyncMutex(); return GMM_SUCCESS; } ///////////////////////////////////////////////////////////////////////////////////// /// GMM lib DLL function for deleting the Singleton Context. /// Reference Count will be decremented and once the reference count reaches 0, /// Singleton Context will be freed in memory /// This function is thread safe for the MultiAdapterContext object. /// /// @param[in] sbdf: Adapter's BDF info that needs its SingletonContext to be freed ///////////////////////////////////////////////////////////////////////////////////// GMM_STATUS GMM_STDCALL GmmLib::GmmMultiAdapterContext::RemoveContext(ADAPTER_BDF sBdf) { GMM_STATUS SyncLockStatus = LockMAContextSyncMutex(); if (SyncLockStatus != GMM_SUCCESS) { return SyncLockStatus; } GmmLib::GMM_ADAPTER_INFO *pNode = GetAdapterNodeUnlocked(sBdf); GMM_LIB_ASSERT(pNode); if (!pNode) { UnLockMAContextSyncMutex(); return GMM_ERROR; } if (pNode->pGmmLibContext) { int32_t ContextRefCount = pNode->pGmmLibContext->DecrementRefCount(); // Refount = 0, It means that it the last client on this adapter // Lets free the LibContext and the Adapter Node if (!ContextRefCount) { pNode->pGmmLibContext->DestroyContext(); // Delete/free the LibContext object delete pNode->pGmmLibContext; // Delete/free the AdapterNode from the Linked List RemoveAdapterNode(pNode); pNode = NULL; } } else { // No context exists for this node. Just remove it. RemoveAdapterNode(pNode); pNode = NULL; } UnLockMAContextSyncMutex(); return GMM_SUCCESS; } ///////////////////////////////////////////////////////////////////////////////////// /// Member function of GmmMultiAdapterContext class for returning the AdapterIdx /// /// @param[in] sBdf : Adpater Bus, Device and Fucntion details /// @return Adpater Idx corresponding the given BDF. ///////////////////////////////////////////////////////////////////////////////////// uint32_t GMM_STDCALL GmmLib::GmmMultiAdapterContext::GetAdapterIndex(ADAPTER_BDF sBdf) { return 0; } ///////////////////////////////////////////////////////////////////////////////////// /// Member function of GmmMultiAdapterContext class to add adapter info for a given BDF /// Adds a new node with the given BDF if it is not yet tracked, otherwise returns the /// existing node with a matching BDF /// This function is not thread safe for the MultiAdapterContext object and calls to /// it must be protected with LockMAContextSyncMutex() /// /// @param[in] sBdf : Adpater Bus, Device and Function details /// @return GmmLib::GMM_ADAPTER_INFO pointer for the BDF ///////////////////////////////////////////////////////////////////////////////////// GmmLib::GMM_ADAPTER_INFO *GmmLib::GmmMultiAdapterContext::AddAdapterNode() { GMM_ADAPTER_INFO *pNode = NULL, *pPrev = NULL; pNode = this->pHeadNode; // walk to the end of the list while (pNode) { pPrev = pNode; pNode = pNode->pNext; } // create a new node pNode = (GMM_ADAPTER_INFO *)malloc(sizeof(GMM_ADAPTER_INFO)); if (!pNode) { // No memory for new node return NULL; } pNode->pGmmLibContext = NULL; pNode->pNext = NULL; if (this->pHeadNode) { // add it to the end of the list if the list already exists pPrev->pNext = pNode; } else { // nothing in the list, insert it as the head of the list this->pHeadNode = pNode; } this->NumAdapters++; return pNode; } ///////////////////////////////////////////////////////////////////////////////////// /// Member function of GmmMultiAdapterContext class to remove a given GMM_ADAPTER_INFO node /// This function is not thread safe for the MultiAdapterContext object and calls to /// it must be protected with LockMAContextSyncMutex() /// /// @param[in] pNode : The node to remove from the list /// @return Void : Removes and deletes the adapter Node from the list ///////////////////////////////////////////////////////////////////////////////////// void GmmLib::GmmMultiAdapterContext::RemoveAdapterNode(GMM_ADAPTER_INFO *pNode) { GMM_ADAPTER_INFO *pCur = NULL, *pPrev = NULL; // Find the node and remove the node from the list pCur = this->pHeadNode; while (pCur) { if (pCur == pNode) { if (pPrev) { // the node to be removed is in the middle of the list or the tail pPrev->pNext = pNode->pNext; } else if (pNode == this->pHeadNode) { // the node to be removed is the head of the list this->pHeadNode = pNode->pNext; } // Decrement the Adapter Node count tracker variable this->NumAdapters--; // Free the node that was removed from the list above. free(pNode); break; } pPrev = pCur; pCur = pCur->pNext; } GMM_ASSERTDPF(pCur != NULL, "CRITICAL ERROR: Node to be released does not exist in list"); } ///////////////////////////////////////////////////////////////////////////////////// /// Member function of GmmMultiAdapterContext class for returning the Adapter Node /// This function is thread safe for the MultiAdapterContext object /// /// @param[in] sBdf : Adpater Bus, Device and Fucntion details /// @return Adpater Node corresponding the given BDF or return NULL if not found ///////////////////////////////////////////////////////////////////////////////////// GmmLib::GMM_ADAPTER_INFO *GmmLib::GmmMultiAdapterContext::GetAdapterNode(ADAPTER_BDF sBdf) { GMM_ADAPTER_INFO *pNode = NULL; GMM_STATUS SyncLockStatus = LockMAContextSyncMutex(); if (SyncLockStatus != GMM_SUCCESS) { return NULL; } pNode = GetAdapterNodeUnlocked(sBdf); UnLockMAContextSyncMutex(); return pNode; } ///////////////////////////////////////////////////////////////////////////////////// /// Member function of GmmMultiAdapterContext class for returning the Adapter Node /// This function is not thread safe for the MultiAdapterContext object and calls to /// it must be protected with LockMAContextSyncMutex() /// /// @param[in] sBdf : Adpater Bus, Device and Fucntion details /// @return Adpater Node corresponding the given BDF or return NULL if not found ///////////////////////////////////////////////////////////////////////////////////// GmmLib::GMM_ADAPTER_INFO *GmmLib::GmmMultiAdapterContext::GetAdapterNodeUnlocked(ADAPTER_BDF sBdf) { GMM_ADAPTER_INFO *pNode = this->pHeadNode; // Search the entire linked list if the Adapter Node with sBdf is found or not while (pNode) { if ((sBdf.Bus == pNode->pGmmLibContext->sBdf.Bus) && (sBdf.Device == pNode->pGmmLibContext->sBdf.Device) && (sBdf.Function == pNode->pGmmLibContext->sBdf.Function)) { // Yes, Found!. This is the Adapter Node // pNode != NULL, will be valid pointer. return pNode; } else { // Not found, Search Next // pNode = NULL if traversed till the tail and not found pNode = pNode->pNext; } } return NULL; } /////////////////////////////////////////////////////////////////////////////////////// /// Member function of GmmMultiAdapterContext class for returning the GmmLibContext /// This function is thread safe for the MultiAdapterContext object // /// @param[in] sBdf : Adpater Bus, Device and Fucntion details /// @return GmmLibContext corresponding the given BDF. ////////////////////////////////////////////////////////////////////////////////////// GmmLib::Context *GMM_STDCALL GmmLib::GmmMultiAdapterContext::GetAdapterLibContext(ADAPTER_BDF sBdf) { GMM_ADAPTER_INFO *pNode = NULL; //Search the list and get the Adapter Node pNode = (GMM_ADAPTER_INFO *)GetAdapterNode(sBdf); if(pNode) { return pNode->pGmmLibContext; } else { return NULL; //return Null if not found } } ///////////////////////////////////////////////////////////////////////////////////// /// Member function of GmmMultiAdapterContext class for returning the NumAdapters /// that are initialized within a process /// This function is thread safe for the MultiAdapterContext object /// /// @return Number of Adpaters that are opened and initialized within a process. ///////////////////////////////////////////////////////////////////////////////////// uint32_t GMM_STDCALL GmmLib::GmmMultiAdapterContext::GetNumAdapters() { return this->NumAdapters; } #ifdef _WIN32 ///////////////////////////////////////////////////////////////////////////////////// /// Member function of GmmMultiAdapterContext class for Locking MultiAdapter Mutex /// SyncMutex to protect access of GmmMultiAdpaterContext object /// /// @return GMM_STATUS. ///////////////////////////////////////////////////////////////////////////////////// GMM_STATUS GMM_STDCALL GmmLib::GmmMultiAdapterContext::LockMAContextSyncMutex() { if(MAContextSyncMutex) { while(WAIT_OBJECT_0 != ::WaitForSingleObject(MAContextSyncMutex, INFINITE)) ; return GMM_SUCCESS; } else { return GMM_ERROR; } } ///////////////////////////////////////////////////////////////////////////////////// /// Member function of GmmMultiAdapterContext class for UnLocking MultiAdapter Mutex /// SyncMutex to protect access of GmmMultiAdpaterContext /// /// @return GMM_STATUS. ///////////////////////////////////////////////////////////////////////////////////// GMM_STATUS GMM_STDCALL GmmLib::GmmMultiAdapterContext::UnLockMAContextSyncMutex() { if(MAContextSyncMutex) { ::ReleaseMutex(MAContextSyncMutex); return GMM_SUCCESS; } else { return GMM_ERROR; } } #else // Non Win OS ///////////////////////////////////////////////////////////////////////////////////// /// Member function of GmmMultiAdapterContext class for Locking MultiAdapter Mutex /// /// @return GMM_STATUS. ///////////////////////////////////////////////////////////////////////////////////// GMM_STATUS GMM_STDCALL GmmLib::GmmMultiAdapterContext::LockMAContextSyncMutex() { pthread_mutex_lock(&MAContextSyncMutex); return GMM_SUCCESS; } ///////////////////////////////////////////////////////////////////////////////////// /// Member function of GmmMultiAdapterContext class for UnLocking MultiAdapter Mutex /// /// @return GMM_STATUS. ///////////////////////////////////////////////////////////////////////////////////// GMM_STATUS GMM_STDCALL GmmLib::GmmMultiAdapterContext::UnLockMAContextSyncMutex() { pthread_mutex_unlock(&MAContextSyncMutex); return GMM_SUCCESS; } #endif //#ifdef _WIN32 #ifdef _WIN32 ///////////////////////////////////////////////////////////////////////// /// Get ProcessHeapVA Singleton HeapObj ///////////////////////////////////////////////////////////////////////// GMM_HEAP *GmmLib::Context::GetSharedHeapObject() { GMM_HEAP *pHeapObjOut = NULL; // Obtain ProcessSingleton Lock #if GMM_LIB_DLL_MA LockSingletonContextSyncMutex(); #else GmmLib::Context::LockSingletonContextSyncMutex(); #endif //Check if the ProcessHeapCounter is 0 or not, if not 0 increment the counter and return the heapObj // that is stored in the DLL Singleton context if(ProcessHeapCounter) { ProcessHeapCounter++; pHeapObjOut = pHeapObj; } // Unlock ProcessSingleton Lock #if GMM_LIB_DLL_MA UnlockSingletonContextSyncMutex(); #else GmmLib::Context::UnlockSingletonContextSyncMutex(); #endif return pHeapObjOut; } ///////////////////////////////////////////////////////////////////////// /// Set ProcessHeapVA Singleton HeapObj ///////////////////////////////////////////////////////////////////////// uint32_t GmmLib::Context::SetSharedHeapObject(GMM_HEAP **pProcessHeapObj) { uint32_t DllClientsCount = 0; // Obtain ProcessSingleton Lock #if GMM_LIB_DLL_MA LockSingletonContextSyncMutex(); #else GmmLib::Context::LockSingletonContextSyncMutex(); #endif if(pProcessHeapObj) { if(!ProcessHeapCounter) { // Setting it for the first time ProcessHeapCounter++; pHeapObj = *pProcessHeapObj; } else { ProcessHeapCounter++; *pProcessHeapObj = pHeapObj; } } else // Destroy the HeapObj Handle Case { ProcessHeapCounter--; if(!ProcessHeapCounter) { // When all UMDs clients have called destroy pHeapObj = NULL; } } DllClientsCount = ProcessHeapCounter; // Unlock ProcessSingleton Lock #if GMM_LIB_DLL_MA UnlockSingletonContextSyncMutex(); #else GmmLib::Context::UnlockSingletonContextSyncMutex(); #endif return DllClientsCount; } ///////////////////////////////////////////////////////////////////////// /// Get ProcessGfxPartition ///////////////////////////////////////////////////////////////////////// void GmmLib::Context::GetProcessGfxPartition(GMM_GFX_PARTITIONING *pProcessVA) { // Obtain ProcessSingleton Lock #if GMM_LIB_DLL_MA LockSingletonContextSyncMutex(); #else GmmLib::Context::LockSingletonContextSyncMutex(); #endif //Check if the ProcessVACounter is 0 or not, if not 0 increment the counter and return the ProcessVA // that is stored in the DLL Singleton context if(ProcessVACounter) { ProcessVACounter++; if(pProcessVA) { *pProcessVA = ProcessVA; } } // Unlock ProcessSingleton Lock #if GMM_LIB_DLL_MA UnlockSingletonContextSyncMutex(); #else GmmLib::Context::UnlockSingletonContextSyncMutex(); #endif } ///////////////////////////////////////////////////////////////////////// /// Set ProcessGfxPartition ///////////////////////////////////////////////////////////////////////// void GmmLib::Context::SetProcessGfxPartition(GMM_GFX_PARTITIONING *pProcessVA) { // Obtain ProcessSingleton Lock #if GMM_LIB_DLL_MA LockSingletonContextSyncMutex(); #else GmmLib::Context::LockSingletonContextSyncMutex(); #endif if(pProcessVA) { if(!ProcessVACounter) { // Setting it for the first time ProcessVACounter++; ProcessVA = *pProcessVA; } else { ProcessVACounter++; //Add code to return the stored value of ProcessVA when Escapes are removed } } else // Reset the ProcessVA Case { ProcessVACounter--; if(!ProcessVACounter) { // When all UMDs clients have called destroy ProcessVA = {0}; } } // Unlock ProcessSingleton Lock #if GMM_LIB_DLL_MA UnlockSingletonContextSyncMutex(); #else GmmLib::Context::UnlockSingletonContextSyncMutex(); #endif } #endif // _WIN32 #endif // GMM_LIB_DLL ///////////////////////////////////////////////////////////////////////////////////// /// Constructor to zero initialize the GmmLib::Context object ///////////////////////////////////////////////////////////////////////////////////// GmmLib::Context::Context() : ClientType(), pPlatformInfo(), pTextureCalc(), SkuTable(), WaTable(), GtSysInfo(), pGmmKmdContext(), pGmmUmdContext(), pKmdHwDev(), pUmdAdapter(), pGmmCachePolicy() { memset(CachePolicy, 0, sizeof(CachePolicy)); memset(CachePolicyTbl, 0, sizeof(CachePolicyTbl)); //Default initialize 64KB Page padding percentage. AllowedPaddingFor64KbPagesPercentage = 10; InternalGpuVaMax = 0; AllowedPaddingFor64KBTileSurf = 10; #if(!defined(__GMM_KMD__) && !defined(GMM_UNIFIED_LIB)) pGmmGlobalClientContext = NULL; #endif #ifdef GMM_LIB_DLL //Protect this adapter context with a sync mutex. Initialize sync mutex #ifdef _WIN32 SyncMutex = ::CreateMutex(NULL, FALSE, NULL); #else // !_WIN32 SyncMutex = PTHREAD_MUTEX_INITIALIZER; #endif // _WIN32 #if GMM_LIB_DLL_MA RefCount = 0; #endif //GMM_LIB_DLL_MA #endif //GMM_LIB_DLL } ///////////////////////////////////////////////////////////////////////////////////// /// Destructor to release GmmLib::Context object memory ///////////////////////////////////////////////////////////////////////////////////// GmmLib::Context::~Context() { #ifdef GMM_LIB_DLL // Close the Mutex protecting this context pthread_mutex_destroy(&SyncMutex); #endif //GMM_LIB_DLL } #ifdef _WIN32 ///////////////////////////////////////////////////////////////////////////////////// /// Member function of Context class for Locking Singleton Context /// SyncMutex to protect access of GmmLibContext /// /// @return GMM_STATUS. ///////////////////////////////////////////////////////////////////////////////////// GMM_STATUS GMM_STDCALL GmmLib::Context::LockSingletonContextSyncMutex() { #ifdef GMM_LIB_DLL if(SyncMutex) { while(WAIT_OBJECT_0 != ::WaitForSingleObject(SyncMutex, INFINITE)) ; return GMM_SUCCESS; } #endif //GMM_LIB_DLL return GMM_ERROR; } ///////////////////////////////////////////////////////////////////////////////////// /// Member function of Context class for Unlocking Singleton Context /// SyncMutex to protect access of GmmLibContext /// /// @return GMM_STATUS. ///////////////////////////////////////////////////////////////////////////////////// GMM_STATUS GMM_STDCALL GmmLib::Context::UnlockSingletonContextSyncMutex() { #ifdef GMM_LIB_DLL if(SyncMutex) { ::ReleaseMutex(SyncMutex); return GMM_SUCCESS; } #endif //GMM_LIB_DLL return GMM_ERROR; } #else //_WIN32 ///////////////////////////////////////////////////////////////////////////////////// /// Member function of Context class for Locking Singleton Context /// /// @return GMM_STATUS. ///////////////////////////////////////////////////////////////////////////////////// GMM_STATUS GMM_STDCALL GmmLib::Context::LockSingletonContextSyncMutex() { pthread_mutex_lock(&SyncMutex); return GMM_SUCCESS; } ///////////////////////////////////////////////////////////////////////////////////// /// Member function of Context class for Unlocking Singleton Context /// /// @return GMM_STATUS. ///////////////////////////////////////////////////////////////////////////////////// GMM_STATUS GMM_STDCALL GmmLib::Context::UnlockSingletonContextSyncMutex() { pthread_mutex_unlock(&SyncMutex); return GMM_SUCCESS; } #endif //_WIN32 #if GMM_LIB_DLL_MA ///////////////////////////////////////////////////////////////////////////////////// /// Member function of Context class for Incrementing Adpater Ref /// Count /// RefCount indicates the number of UMD clients using a particaluar Adapter. /// RefCount is incremented when a client requests LibContext on already registered /// adapter. /// RefCount = 0, when no clients are using an adapter's LibContext /// RefCount > 0, when at least one client is using the adapter's LibContext /// /// @param1 sBdf Adpater's Bus, Device and Fucntion /// @return Current value of the ref count. ///////////////////////////////////////////////////////////////////////////////////// int32_t GmmLib::Context::IncrementRefCount() { int32_t *Ref = &RefCount; #if defined(__linux__) // returns 0 only when registering the first client return (__sync_fetch_and_add(Ref, 1)); #endif } ///////////////////////////////////////////////////////////////////////////////////// /// Member function of Context class for Decrementing Adpater's Ref /// Count /// RefCount indicates the number of UMD clients using a particaluar Adapter. /// RefCount is decremented when a clients requests LibContext destroy on already /// registered adapter. /// RefCount = 0, when no clients are using an adapter's LibContext /// RefCount > 0, when at least one client is using the adapter's LibContext /// /// @param1 sBdf Adpater's Bus, Device and Fucntion /// @return Current value of the ref count. ///////////////////////////////////////////////////////////////////////////////////// int32_t GmmLib::Context::DecrementRefCount() { int32_t *Ref = &RefCount; int CurrentValue = 0; int TargetValue = 0; do { CurrentValue = *Ref; if(CurrentValue > 0) { TargetValue = CurrentValue - 1; } else { break; } #if defined(__linux__) } while(!__sync_bool_compare_and_swap(Ref, CurrentValue, TargetValue)); #endif return TargetValue; } #endif //GMM_LIB_DLL_MA ///////////////////////////////////////////////////////////////////////////////////// /// Member function to initialize the GmmLib::Context object with cache policy, /// platform info, Texture calculator etc. /// @param[in] Platform: ref to platform /// @param[in] pSkuTable: ptr to sku table /// @param[in] pWaTable: ptr to workaround table /// @param[in] pGtSysInfo: ptr to gt system info /// @param[in] ClientType: client type such as dx, ogl, ocl etc /// @return GMM_SUCCESS if init is success, GMM_ERROR otherwise ///////////////////////////////////////////////////////////////////////////////////// GMM_STATUS GMM_STDCALL GmmLib::Context::InitContext( const PLATFORM & Platform, const SKU_FEATURE_TABLE *pSkuTable, const WA_TABLE * pWaTable, const GT_SYSTEM_INFO * pGtSysInfo, GMM_CLIENT ClientType) { this->ClientType = ClientType; // Save the SKU and WA this->SkuTable = *pSkuTable; this->WaTable = *pWaTable; this->GtSysInfo = *pGtSysInfo; this->pPlatformInfo = CreatePlatformInfo(Platform, false); if(this->pPlatformInfo == NULL) { return GMM_ERROR; } OverrideSkuWa(); this->pGmmCachePolicy = CreateCachePolicyCommon(); if(this->pGmmCachePolicy == NULL) { return GMM_ERROR; } this->pGmmCachePolicy->InitCachePolicy(); this->pTextureCalc = CreateTextureCalc(Platform, false); if(this->pTextureCalc == NULL) { return GMM_ERROR; } return GMM_SUCCESS; } ///////////////////////////////////////////////////////////////////////////////////// /// Member function to deallcoate the GmmLib::Context's cache policy, platform info, /// Texture calculator etc. ///////////////////////////////////////////////////////////////////////////////////// void GMM_STDCALL GmmLib::Context::DestroyContext() { if(this->pGmmCachePolicy) { delete this->pGmmCachePolicy; this->pGmmCachePolicy = NULL; } if(this->pTextureCalc) { delete this->pTextureCalc; this->pTextureCalc = NULL; } if(this->pPlatformInfo) { delete this->pPlatformInfo; this->pPlatformInfo = NULL; } } void GMM_STDCALL GmmLib::Context::OverrideSkuWa() { if((GFX_GET_CURRENT_PRODUCT(this->GetPlatformInfo().Platform) < IGFX_XE_HP_SDV)) { SkuTable.FtrTileY = true; } if(GFX_GET_CURRENT_PRODUCT(this->GetPlatformInfo().Platform) == IGFX_PVC) { SkuTable.Ftr57bGPUAddressing = true; } if (GFX_GET_CURRENT_PRODUCT(this->GetPlatformInfo().Platform) >= IGFX_BMG) { // FtrL3TransientDataFlush is always enabled for XE2 adding GMM Override if UMDs might have reset this. SkuTable.FtrL3TransientDataFlush = true; } } GMM_CACHE_POLICY *GMM_STDCALL GmmLib::Context::CreateCachePolicyCommon() { GMM_CACHE_POLICY * pGmmCachePolicy = NULL; GMM_CACHE_POLICY_ELEMENT *CachePolicy = NULL; CachePolicy = GetCachePolicyUsage(); PRODUCT_FAMILY ProductFamily = GFX_GET_CURRENT_PRODUCT(GetPlatformInfo().Platform); if(GetCachePolicyObj()) { return GetCachePolicyObj(); } if(ProductFamily >= IGFX_BMG) { pGmmCachePolicy = new GmmLib::GmmXe2_LPGCachePolicy(CachePolicy, this); } else if((ProductFamily == IGFX_METEORLAKE) || (ProductFamily == IGFX_ARROWLAKE)) { pGmmCachePolicy = new GmmLib::GmmXe_LPGCachePolicy(CachePolicy, this); } else { switch(GFX_GET_CURRENT_RENDERCORE(this->GetPlatformInfo().Platform)) { case IGFX_XE2_HPG_CORE: pGmmCachePolicy = new GmmLib::GmmXe2_LPGCachePolicy(CachePolicy, this); break; case IGFX_GEN12LP_CORE: case IGFX_GEN12_CORE: case IGFX_XE_HP_CORE: case IGFX_XE_HPG_CORE: case IGFX_XE_HPC_CORE: if(GetSkuTable().FtrLocalMemory) { pGmmCachePolicy = new GmmLib::GmmGen12dGPUCachePolicy(CachePolicy, this); } else { pGmmCachePolicy = new GmmLib::GmmGen12CachePolicy(CachePolicy, this); } break; case IGFX_GEN11_CORE: pGmmCachePolicy = new GmmLib::GmmGen11CachePolicy(CachePolicy, this); break; case IGFX_GEN10_CORE: pGmmCachePolicy = new GmmLib::GmmGen10CachePolicy(CachePolicy, this); break; case IGFX_GEN9_CORE: pGmmCachePolicy = new GmmLib::GmmGen9CachePolicy(CachePolicy, this); break; default: pGmmCachePolicy = new GmmLib::GmmGen8CachePolicy(CachePolicy, this); break; } } if(!pGmmCachePolicy) { GMM_DPF_CRITICAL("unable to allocate memory for CachePolicy Object"); } return pGmmCachePolicy; } GMM_TEXTURE_CALC *GMM_STDCALL GmmLib::Context::CreateTextureCalc(PLATFORM Platform, bool Override) { if(!Override) { if(GetTextureCalc()) { return GetTextureCalc(); } } if(GFX_GET_CURRENT_PRODUCT(GetPlatformInfo().Platform) >= IGFX_METEORLAKE) { return new GmmXe_LPGTextureCalc(this); } else { switch(GFX_GET_CURRENT_RENDERCORE(Platform)) { case IGFX_GEN7_CORE: case IGFX_GEN7_5_CORE: return new GmmGen7TextureCalc(this); break; case IGFX_GEN8_CORE: return new GmmGen8TextureCalc(this); break; case IGFX_GEN9_CORE: return new GmmGen9TextureCalc(this); break; case IGFX_GEN10_CORE: return new GmmGen10TextureCalc(this); break; case IGFX_GEN11_CORE: return new GmmGen11TextureCalc(this); break; case IGFX_GEN12LP_CORE: case IGFX_GEN12_CORE: case IGFX_XE_HP_CORE: case IGFX_XE_HPG_CORE: case IGFX_XE_HPC_CORE: return new GmmGen12TextureCalc(this); break; case IGFX_XE2_HPG_CORE: default: return new GmmXe_LPGTextureCalc(this); break; } } } GMM_PLATFORM_INFO_CLASS *GMM_STDCALL GmmLib::Context::CreatePlatformInfo(PLATFORM Platform, bool Override) { GMM_DPF_ENTER; PRODUCT_FAMILY ProductFamily = GFX_GET_CURRENT_PRODUCT(Platform); if(Override == false) { if(pPlatformInfo != NULL) { return pPlatformInfo; } } if (ProductFamily >= IGFX_LUNARLAKE) { return new GmmLib::PlatformInfoGen12(Platform, (GMM_LIB_CONTEXT *)this); } else { switch (GFX_GET_CURRENT_RENDERCORE(Platform)) { case IGFX_GEN12LP_CORE: case IGFX_GEN12_CORE: case IGFX_XE_HP_CORE: case IGFX_XE_HPG_CORE: case IGFX_XE_HPC_CORE: case IGFX_XE2_HPG_CORE: return new GmmLib::PlatformInfoGen12(Platform, (GMM_LIB_CONTEXT *)this); break; case IGFX_GEN11_CORE: return new GmmLib::PlatformInfoGen11(Platform, (GMM_LIB_CONTEXT *)this); break; case IGFX_GEN10_CORE: return new GmmLib::PlatformInfoGen10(Platform, (GMM_LIB_CONTEXT *)this); break; case IGFX_GEN9_CORE: return new GmmLib::PlatformInfoGen9(Platform, (GMM_LIB_CONTEXT *)this); break; default: return new GmmLib::PlatformInfoGen8(Platform, (GMM_LIB_CONTEXT *)this); break; } } } //C - Wrappers ///////////////////////////////////////////////////////////////////////// /// C-wrapper to get the PlatformInfo ptr /// @param[in] pGmmLibContext: ptr to GMM_GLOBAL_CONTEXT /// @return const PlatformInfo ptr ///////////////////////////////////////////////////////////////////////// const GMM_PLATFORM_INFO *GMM_STDCALL GmmGetPlatformInfo(GMM_LIB_CONTEXT *pGmmLibContext) { return (&pGmmLibContext->GetPlatformInfo()); } ///////////////////////////////////////////////////////////////////////// /// C-wrapper to get the cache policy element array ptr /// @param[in] pGmmLibContext: ptr to GMM_GLOBAL_CONTEXT /// @return const cache policy elment ptr ///////////////////////////////////////////////////////////////////////// const GMM_CACHE_POLICY_ELEMENT *GmmGetCachePolicyUsage(GMM_LIB_CONTEXT *pGmmLibContext) { return (pGmmLibContext->GetCachePolicyUsage()); } ///////////////////////////////////////////////////////////////////////// /// C-wrapper to get the texture calculation object ptr /// @param[in] pGmmLibContext: ptr to GMM_GLOBAL_CONTEXT /// @return TextureCalc ptr ///////////////////////////////////////////////////////////////////////// GMM_TEXTURE_CALC *GmmGetTextureCalc(GMM_LIB_CONTEXT *pGmmLibContext) { return (pGmmLibContext->GetTextureCalc()); } ///////////////////////////////////////////////////////////////////////// /// C-wrapper to get the sku table ptr /// @param[in] pGmmLibContext: ptr to GMM_GLOBAL_CONTEXT /// @return const SkuTable ptr ///////////////////////////////////////////////////////////////////////// const SKU_FEATURE_TABLE *GmmGetSkuTable(GMM_LIB_CONTEXT *pGmmLibContext) { return (&pGmmLibContext->GetSkuTable()); } ///////////////////////////////////////////////////////////////////////// /// C-wrapper to get the Wa table ptr /// @param[in] pGmmLibContext: ptr to GMM_GLOBAL_CONTEXT /// @return const WaTable ptr ///////////////////////////////////////////////////////////////////////// const WA_TABLE *GmmGetWaTable(GMM_LIB_CONTEXT *pGmmLibContext) { return (&pGmmLibContext->GetWaTable()); } ///////////////////////////////////////////////////////////////////////// /// C-wrapper to get the GT system info ptr /// @param[in] pGmmLibContext: ptr to GMM_GLOBAL_CONTEXT /// @return const GtSysInfo ptr ///////////////////////////////////////////////////////////////////////// const GT_SYSTEM_INFO *GmmGetGtSysInfo(GMM_LIB_CONTEXT *pGmmLibContext) { return (pGmmLibContext->GetGtSysInfoPtr()); } gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/GlobalInfo/GmmLibDllMain.cpp000077500000000000000000000062341466655022700252130ustar00rootroot00000000000000/*============================================================================== Copyright(c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ============================================================================*/ #include #ifdef _WIN32 #include #endif #include #include #ifdef GMM_LIB_DLL #include "Internal/Common/GmmLibInc.h" #include "External/Common/GmmClientContext.h" #include "External/Common/GmmLibDll.h" ///////////////////////////////////////////////////////////////////////////////////// // First Call to GMM Lib DLL/so to initialize singleton global context // and create client context ///////////////////////////////////////////////////////////////////////////////////// extern "C" GMM_LIB_API GMM_STATUS GMM_STDCALL InitializeGmm(GMM_INIT_IN_ARGS *pInArgs, GMM_INIT_OUT_ARGS *pOutArgs) { GMM_STATUS Status = GMM_ERROR; if(pInArgs && pOutArgs) { #if GMM_LIB_DLL_MA ADAPTER_BDF stAdapterBDF; #ifdef _WIN32 stAdapterBDF = pInArgs->stAdapterBDF; #else stAdapterBDF.Data = pInArgs->FileDescriptor; #endif Status = GmmCreateLibContext(pInArgs->Platform, pInArgs->pSkuTable, pInArgs->pWaTable, pInArgs->pGtSysInfo, stAdapterBDF, pInArgs->ClientType); if(Status == GMM_SUCCESS) { pOutArgs->pGmmClientContext = GmmCreateClientContextForAdapter(pInArgs->ClientType, stAdapterBDF); } #endif } return Status; } ///////////////////////////////////////////////////////////////////////////////////// /// Destroys singleton global context and client context /// ///////////////////////////////////////////////////////////////////////////////////// extern "C" GMM_LIB_API void GMM_STDCALL GmmAdapterDestroy(GMM_INIT_OUT_ARGS *pInArgs) { if(pInArgs && pInArgs->pGmmClientContext) { #if GMM_LIB_DLL_MA ADAPTER_BDF stAdapterBDF = pInArgs->pGmmClientContext->GetLibContext()->sBdf; GmmDeleteClientContext(pInArgs->pGmmClientContext); GmmLibContextFree(stAdapterBDF); #endif } } #endif // GMM_LIB_DLL gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/Linux.cmake000066400000000000000000000114341466655022700221570ustar00rootroot00000000000000# Copyright(c) 2017 Intel Corporation # Permission is hereby granted, free of charge, to any person obtaining a # copy of this software and associated documentation files(the "Software"), # to deal in the Software without restriction, including without limitation # the rights to use, copy, modify, merge, publish, distribute, sublicense, # and / or sell copies of the Software, and to permit persons to whom the # Software is furnished to do so, subject to the following conditions: # The above copyright notice and this permission notice shall be included # in all copies or substantial portions of the Software. # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS # OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL # THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR # OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, # ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR # OTHER DEALINGS IN THE SOFTWARE. #this file should contain only compiler and linker flags if (${CMAKE_SYSTEM_PROCESSOR} MATCHES "^aarch") SET (GMMLIB_COMPILER_FLAGS_COMMON #general warnings #-Wall -Winit-self -Winvalid-pch -Wpointer-arith -Wno-unused -Wno-unknown-pragmas -Wno-comments -Wno-narrowing -Wno-overflow -Wno-parentheses -Wno-missing-braces -Wno-sign-compare -Werror=address -Werror=format-security -Werror=return-type # General optimization options -march=${GMMLIB_MARCH} -finline-functions -fno-short-enums -Wa,--noexecstack -fno-strict-aliasing # Common defines -DUSE_NEON # Other common flags -fstack-protector -fdata-sections -ffunction-sections -fmessage-length=0 -fvisibility=hidden -fPIC -g ) else() SET (GMMLIB_COMPILER_FLAGS_COMMON #general warnings -Wall -Winit-self -Winvalid-pch -Wpointer-arith -Wno-unused -Wno-unknown-pragmas -Wno-comments -Wno-narrowing -Wno-overflow -Wno-parentheses -Wno-missing-braces -Wno-sign-compare -Wno-enum-compare -Werror=address -Werror=format-security -Werror=return-type # General optimization options -march=${GMMLIB_MARCH} -mpopcnt -msse -msse2 -msse3 -mssse3 -msse4 -msse4.1 -msse4.2 -mfpmath=sse -finline-functions -fno-short-enums -Wa,--noexecstack -fno-strict-aliasing # Common defines -DUSE_MMX -DUSE_SSE -DUSE_SSE2 -DUSE_SSE3 -DUSE_SSSE3 # Other common flags -fstack-protector -fdata-sections -ffunction-sections -fmessage-length=0 -fvisibility=hidden -fPIC -g # -m32 or -m64 -m${GMMLIB_ARCH} ) endif() if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") #Gcc only flags list (APPEND GMMLIB_COMPILER_FLAGS_COMMON -funswitch-loops -Wl,--no-undefined -Wl,--no-as-needed -Wl,--gc-sections ) endif() SET (GMMLIB_COMPILER_CXX_FLAGS_COMMON #cpp -Wno-reorder -Wsign-promo -Wnon-virtual-dtor -Wno-invalid-offsetof -fvisibility-inlines-hidden -fno-use-cxa-atexit -fno-rtti -fexceptions -fcheck-new -std=c++11 -pthread -Werror=non-virtual-dtor ) SET (GMMLIB_COMPILER_FLAGS_DEBUG -O0 -DINSTR_GTUNE_EXT ) SET (GMMLIB_COMPILER_FLAGS_RELEASE -O2 -fno-omit-frame-pointer #-flto #-Wl,-flto ) if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") list(APPEND GMMLIB_COMPILER_FLAGS_RELEASE -finline-limit=100 ) endif() #if("${CMAKE_BUILD_TYPE}" STREQUAL "Release") # For LTO support, use special wrappers around ar and ranlib commands: # ... and if using "nm", use gcc-nm # SET(CMAKE_AR "gcc-ar") # SET(CMAKE_RANLIB "gcc-ranlib") #endif() SET( GMMLIB_COMPILER_FLAGS_RELEASEINTERNAL ${GMMLIB_COMPILER_FLAGS_RELEASE}) #set predefined compiler flags set add_compile_options("${GMMLIB_COMPILER_FLAGS_COMMON}") add_compile_options("$<$:${GMMLIB_COMPILER_FLAGS_DEBUG}>") add_compile_options("$<$:${GMMLIB_COMPILER_FLAGS_RELEASE}>") add_compile_options("$<$:${GMMLIB_COMPILER_FLAGS_RELEASEINTERNAL}>") #cmake 3.3+, add_compile_options("$<$:${GMMLIB_COMPILER_CXX_FLAGS_COMMON}>") foreach (flag ${GMMLIB_COMPILER_CXX_FLAGS_COMMON}) SET (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${flag}") endforeach() if (${CMAKE_SYSTEM_PROCESSOR} MATCHES "^aarch") SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS}") SET(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS}") else() SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -m${GMMLIB_ARCH}") SET(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -m${GMMLIB_ARCH}") endif() gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/Platform/000077500000000000000000000000001466655022700216375ustar00rootroot00000000000000gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/Platform/GmmGen10Platform.cpp000066400000000000000000000731071466655022700253730ustar00rootroot00000000000000/*============================================================================== Copyright(c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ============================================================================*/ #include "Internal/Common/GmmLibInc.h" #include "Internal/Common/Platform/GmmGen10Platform.h" ///////////////////////////////////////////////////////////////////////////////////// /// Allocates This function will initialize the necessary info based on platform. /// - Buffer type restrictions (Eg: Z, Color, Display) /// - X/Y tile dimensions /// /// @param[in] Platform: Contains information about platform to initialize an object ///////////////////////////////////////////////////////////////////////////////////// GmmLib::PlatformInfoGen10::PlatformInfoGen10(PLATFORM &Platform, Context *pGmmLibContext) : PlatformInfo(Platform, pGmmLibContext) { __GMM_ASSERTPTR(pGmmLibContext, VOIDRETURN); // -------------------------- // Non Native Dispay Interface buffer restriction. Register Ref: DSPACNTR, DSPASTRIDE, DSPASURF // Clamping res based on 2 Nndi buffers and GMM_NNDI_SEGMENT_SIZE reserved gfx memory // -------------------------- Data.Nndi.Alignment = PAGE_SIZE; Data.Nndi.PitchAlignment = GMM_BYTES(1); Data.Nndi.RenderPitchAlignment = GMM_BYTES(1); Data.Nndi.LockPitchAlignment = GMM_BYTES(1); Data.Nndi.MinPitch = GMM_BYTES(640); Data.Nndi.MaxPitch = GMM_BYTES(8192); Data.Nndi.MinAllocationSize = PAGE_SIZE; Data.Nndi.MinHeight = GMM_SCANLINES(200); Data.Nndi.MinWidth = GMM_PIXELS(320); Data.Nndi.MinDepth = 0; Data.Nndi.MaxHeight = GMM_BYTES(1536); Data.Nndi.MaxWidth = GMM_BYTES(2048); Data.Nndi.MaxDepth = 1; Data.Nndi.MaxArraySize = 1; // -------------------------- // Depth Buffer Restriction. Inst Ref: 3DSTATE_DEPTH_BUFFER // -------------------------- Data.Depth.Alignment = PAGE_SIZE; Data.Depth.PitchAlignment = GMM_BYTES(64); Data.Depth.RenderPitchAlignment = GMM_BYTES(64); Data.Depth.LockPitchAlignment = GMM_BYTES(64); Data.Depth.MinPitch = GMM_BYTES(64); Data.Depth.MaxPitch = GMM_KBYTE(128); // 3DSTATE_DEPTH_BUFFER has conflicting info--but 128KB should be fine. Data.Depth.MinAllocationSize = PAGE_SIZE; Data.Depth.MinHeight = GMM_SCANLINES(1); Data.Depth.MinWidth = GMM_PIXELS(1); Data.Depth.MinDepth = 0; Data.Depth.MaxHeight = GMM_KBYTE(16); Data.Depth.MaxWidth = GMM_KBYTE(16); Data.Depth.MaxDepth = GMM_KBYTE(2); Data.Depth.MaxArraySize = GMM_KBYTE(2); // -------------------------- // Stencil Buffer Restriction. Inst Ref: 3DSTATE_STENCIL_BUFFER // -------------------------- Data.Stencil.Alignment = PAGE_SIZE; Data.Stencil.PitchAlignment = GMM_BYTES(128); Data.Stencil.RenderPitchAlignment = GMM_BYTES(128); Data.Stencil.LockPitchAlignment = GMM_BYTES(128); Data.Stencil.MinPitch = GMM_BYTES(128); Data.Stencil.MaxPitch = GMM_KBYTE(128); // 3DSTATE_STENCIL_BUFFER: 2*Pitch <= 128KB (GMM client allocs 2x-width, so GMM limits to that.) Data.Stencil.MinAllocationSize = PAGE_SIZE; Data.Stencil.MinHeight = GMM_SCANLINES(1); Data.Stencil.MinWidth = GMM_PIXELS(1); Data.Stencil.MinDepth = 0; Data.Stencil.MaxHeight = GMM_KBYTE(16); Data.Stencil.MaxWidth = GMM_KBYTE(16); Data.Stencil.MaxDepth = GMM_KBYTE(2); Data.Stencil.MaxArraySize = GMM_KBYTE(2); // -------------------------- // Hierarchical Depth Buffer Restriction. Inst Ref: 3DSTATE_HIER_DEPTH_BUFFER // -------------------------- Data.HiZ.Alignment = PAGE_SIZE; Data.HiZ.PitchAlignment = GMM_BYTES(128); Data.HiZ.RenderPitchAlignment = GMM_BYTES(128); Data.HiZ.LockPitchAlignment = GMM_BYTES(128); Data.HiZ.MinPitch = GMM_BYTES(128); Data.HiZ.MaxPitch = GMM_KBYTE(128); Data.HiZ.MinAllocationSize = PAGE_SIZE; Data.HiZ.MinHeight = GMM_SCANLINES(1); Data.HiZ.MinWidth = GMM_PIXELS(1); Data.HiZ.MinDepth = 0; Data.HiZ.MaxHeight = GMM_KBYTE(16); Data.HiZ.MaxWidth = GMM_KBYTE(16); Data.HiZ.MaxDepth = GMM_KBYTE(2); Data.HiZ.MaxArraySize = GMM_KBYTE(2); // -------------------------- // Vertex Restriction. Inst Ref: 3DSTATE_VERTEX_BUFFER, 3DSTATE_INSTANCE_STEP_RATE // Note: restrictions are expanded here for UMD flexibility. // -------------------------- Data.Vertex.Alignment = PAGE_SIZE; Data.Vertex.PitchAlignment = GMM_BYTES(1); Data.Vertex.LockPitchAlignment = GMM_BYTES(1); Data.Vertex.RenderPitchAlignment = GMM_BYTES(1); Data.Vertex.MinPitch = GMM_BYTES(1); Data.Vertex.MaxPitch = GMM_GBYTE(2); Data.Vertex.MinAllocationSize = PAGE_SIZE; Data.Vertex.MinHeight = GMM_SCANLINES(1); Data.Vertex.MinWidth = GMM_PIXELS(1); Data.Vertex.MinDepth = 0; Data.Vertex.MaxHeight = GMM_MBYTE(128); //TODO(Minor): How does Media fail when we change this to 1?! Data.Vertex.MaxWidth = GMM_GBYTE(2); Data.Vertex.MaxDepth = GMM_KBYTE(2); Data.Vertex.MaxArraySize = GMM_KBYTE(2); // -------------------------- // Index Buffer Restriction. Inst Ref: 3DSTATE_INDEX_BUFFER // -------------------------- Data.Index = Data.Vertex; // -------------------------- // Linear Buffer Restriction. General purpose. Flexible. // -------------------------- Data.Linear.Alignment = PAGE_SIZE; Data.Linear.PitchAlignment = GMM_BYTES(1); Data.Linear.LockPitchAlignment = GMM_BYTES(1); Data.Linear.RenderPitchAlignment = GMM_BYTES(1); Data.Linear.MinPitch = GMM_BYTES(1); Data.Linear.MaxPitch = GMM_GBYTE(256); Data.Linear.MinAllocationSize = PAGE_SIZE; Data.Linear.MinHeight = GMM_SCANLINES(1); Data.Linear.MinWidth = GMM_PIXELS(1); Data.Linear.MinDepth = 0; Data.Linear.MaxHeight = 1; Data.Linear.MaxWidth = GMM_GBYTE(256); Data.Linear.MaxDepth = 1; Data.Linear.MaxArraySize = 1; // -------------------------- // No Surface Restriction. General purpose. Flexible. // -------------------------- Data.NoRestriction.Alignment = PAGE_SIZE; Data.NoRestriction.PitchAlignment = GMM_BYTES(1); Data.NoRestriction.LockPitchAlignment = GMM_BYTES(1); Data.NoRestriction.RenderPitchAlignment = GMM_BYTES(1); Data.NoRestriction.MinPitch = GMM_BYTES(1); Data.NoRestriction.MaxPitch = GMM_TBYTE(128); Data.NoRestriction.MinAllocationSize = PAGE_SIZE; Data.NoRestriction.MinHeight = GMM_SCANLINES(1); Data.NoRestriction.MinWidth = GMM_PIXELS(1); Data.NoRestriction.MinDepth = 0; Data.NoRestriction.MaxHeight = GMM_GBYTE(256); Data.NoRestriction.MaxWidth = GMM_TBYTE(128); Data.NoRestriction.MaxDepth = GMM_KBYTE(2); Data.NoRestriction.MaxArraySize = GMM_KBYTE(2); // -------------------------- // Constant Buffer Restriction. // -------------------------- Data.Constant = Data.NoRestriction; // -------------------------- // Dx9 Constant Buffer pool Restriction. Inst Ref: 3DSTATE_DX9_CONSTANT_BUFFER_POOL_ALLOC // -------------------------- Data.StateDx9ConstantBuffer = Data.NoRestriction; Data.StateDx9ConstantBuffer.Alignment = GMM_KBYTE(8); // -------------------------- // MC Buffer Restriction // -------------------------- Data.MotionComp = Data.NoRestriction; Data.MotionComp.Alignment = PAGE_SIZE; Data.MotionComp.PitchAlignment = GMM_BYTES(32); Data.MotionComp.LockPitchAlignment = GMM_BYTES(32); Data.MotionComp.RenderPitchAlignment = GMM_BYTES(32); Data.MotionComp.MinPitch = GMM_BYTES(32); // -------------------------- // Stream Buffer Restriction // -------------------------- Data.Stream = Data.NoRestriction; // -------------------------- // Interlace Scan Buffer Restriction // -------------------------- Data.InterlacedScan = Data.NoRestriction; // -------------------------- // Text API Buffer Restriction // -------------------------- Data.TextApi = Data.NoRestriction; // -------------------------- // RT & Texture2DSurface restrictions. Inst Ref: SURFACE_STATE // Greatest common restriction source comes from 8bpp RT // -------------------------- Data.Texture2DSurface.Alignment = PAGE_SIZE; Data.Texture2DSurface.PitchAlignment = GMM_BYTES(32); Data.Texture2DSurface.LockPitchAlignment = GMM_BYTES(32); Data.Texture2DSurface.RenderPitchAlignment = GMM_BYTES(32); Data.Texture2DSurface.MinPitch = GMM_BYTES(32); Data.Texture2DSurface.MaxPitch = (pGmmLibContext->GetWaTable().WaRestrictPitch128KB) ? GMM_KBYTE(128) : GMM_KBYTE(256); Data.Texture2DSurface.MinAllocationSize = PAGE_SIZE; Data.Texture2DSurface.MinHeight = GMM_SCANLINES(1); Data.Texture2DSurface.MinWidth = GMM_PIXELS(1); Data.Texture2DSurface.MinDepth = 0; Data.Texture2DSurface.MaxHeight = GMM_KBYTE(16); Data.Texture2DSurface.MaxWidth = GMM_KBYTE(16); Data.Texture2DSurface.MaxDepth = GMM_FIELD_NA; Data.Texture2DSurface.MaxArraySize = GMM_KBYTE(2); { // Linear surfaces accessed with Media Block Read/Write commands // require 64-byte-aligned pitch. Such commands only operate on 2D // resources, so we'll handle the requirement here. Though requirement // applies to linear surfaces only, our up'ing the pitch alignment to // 64 bytes here won't affect tiled surfaces, since their pitch // alignment is never smaller than that. Data.Texture2DLinearSurface = Data.Texture2DSurface; Data.Texture2DLinearSurface.PitchAlignment = GFX_MAX(GMM_BYTES(64), Data.Texture2DSurface.PitchAlignment); Data.Texture2DLinearSurface.LockPitchAlignment = GFX_MAX(GMM_BYTES(64), Data.Texture2DSurface.LockPitchAlignment); Data.Texture2DLinearSurface.RenderPitchAlignment = GFX_MAX(GMM_BYTES(64), Data.Texture2DSurface.RenderPitchAlignment); } // -------------------------- // AsyncFlip Restriction. Register Ref: PRI_STRIDE, PRI_SURF, SRCSZ <-- TODO(Minor): SRCSZ correct reg for W/H req's? // -------------------------- Data.ASyncFlipSurface.Alignment = GMM_KBYTE(256); Data.ASyncFlipSurface.PitchAlignment = GMM_BYTES(64); Data.ASyncFlipSurface.RenderPitchAlignment = GMM_BYTES(64); Data.ASyncFlipSurface.LockPitchAlignment = GMM_BYTES(64); Data.ASyncFlipSurface.MinPitch = GMM_BYTES(64); Data.ASyncFlipSurface.MaxPitch = Data.Texture2DSurface.MaxPitch; Data.ASyncFlipSurface.MinAllocationSize = PAGE_SIZE; Data.ASyncFlipSurface.MinHeight = GMM_SCANLINES(1); Data.ASyncFlipSurface.MinWidth = GMM_PIXELS(1); Data.ASyncFlipSurface.MinDepth = 0; Data.ASyncFlipSurface.MaxHeight = Data.Texture2DSurface.MaxHeight; // Beyond DE requirements-Necessary for mosaic framebuffers Data.ASyncFlipSurface.MaxWidth = Data.Texture2DSurface.MaxWidth; // Okay since GMM isn't actual display requirement gatekeeper. Data.ASyncFlipSurface.MaxDepth = 1; Data.ASyncFlipSurface.MaxArraySize = GMM_KBYTE(2); // -------------------------- // Hardware MBM Restriction. // -------------------------- Data.HardwareMBM = Data.ASyncFlipSurface; // -------------------------- // Video Buffer Restriction // -------------------------- Data.Video = Data.Texture2DLinearSurface; // -------------------------- // Overlay Buffer Restriction. Overlay buffer restriction will be same as Async flip surface since CNL has universal planes. // -------------------------- Data.Overlay = Data.ASyncFlipSurface; // -------------------------- // RT & CubeSurface restrictions. Inst Ref: SURFACE_STATE // Greatest common restriction source comes from 8bpp RT // -------------------------- Data.CubeSurface.Alignment = PAGE_SIZE; Data.CubeSurface.PitchAlignment = GMM_BYTES(32); Data.CubeSurface.LockPitchAlignment = GMM_BYTES(32); Data.CubeSurface.RenderPitchAlignment = GMM_BYTES(32); Data.CubeSurface.MinPitch = GMM_BYTES(32); Data.CubeSurface.MaxPitch = (pGmmLibContext->GetWaTable().WaRestrictPitch128KB) ? GMM_KBYTE(128) : GMM_KBYTE(256); Data.CubeSurface.MinAllocationSize = PAGE_SIZE; Data.CubeSurface.MinHeight = GMM_SCANLINES(1); Data.CubeSurface.MinWidth = GMM_PIXELS(1); Data.CubeSurface.MinDepth = 0; Data.CubeSurface.MaxHeight = GMM_KBYTE(16); Data.CubeSurface.MaxWidth = GMM_KBYTE(16); Data.CubeSurface.MaxDepth = 1; Data.CubeSurface.MaxArraySize = GMM_KBYTE(2) / 6; // MaxElements / Cubefaces // -------------------------- // RT & 3D Surface restrictions. Inst Ref: SURFACE_STATE // Greatest common restriction source comes from 8bpp RT // -------------------------- Data.Texture3DSurface.Alignment = PAGE_SIZE; Data.Texture3DSurface.PitchAlignment = GMM_BYTES(32); Data.Texture3DSurface.LockPitchAlignment = GMM_BYTES(32); Data.Texture3DSurface.RenderPitchAlignment = GMM_BYTES(32); Data.Texture3DSurface.MinPitch = GMM_BYTES(32); Data.Texture3DSurface.MaxPitch = (pGmmLibContext->GetWaTable().WaRestrictPitch128KB) ? GMM_KBYTE(128) : GMM_KBYTE(256); Data.Texture3DSurface.MinAllocationSize = PAGE_SIZE; Data.Texture3DSurface.MinHeight = GMM_SCANLINES(1); Data.Texture3DSurface.MinWidth = GMM_PIXELS(1); Data.Texture3DSurface.MinDepth = 0; Data.Texture3DSurface.MaxHeight = GMM_KBYTE(16); Data.Texture3DSurface.MaxWidth = GMM_KBYTE(16); Data.Texture3DSurface.MaxDepth = GMM_KBYTE(2); Data.Texture3DSurface.MaxArraySize = GMM_FIELD_NA; // -------------------------- // RT & Buffer Type restrictions. Inst Ref: SURFACE_STATE // Greatest common restriction source comes from 8bpp RT // -------------------------- Data.BufferType.Alignment = PAGE_SIZE; Data.BufferType.PitchAlignment = GMM_BYTES(32); Data.BufferType.LockPitchAlignment = GMM_BYTES(32); Data.BufferType.RenderPitchAlignment = GMM_BYTES(32); Data.BufferType.MinPitch = GMM_BYTES(32); Data.BufferType.MaxPitch = GMM_GBYTE(256); Data.BufferType.MinAllocationSize = PAGE_SIZE; Data.BufferType.MinHeight = GMM_SCANLINES(0); Data.BufferType.MinWidth = GMM_PIXELS(1); Data.BufferType.MinDepth = 0; Data.BufferType.MaxHeight = GMM_SCANLINES(1); Data.BufferType.MaxWidth = GMM_GBYTE(256); Data.BufferType.MaxDepth = GMM_FIELD_NA; Data.BufferType.MaxArraySize = GMM_GBYTE(2); // -------------------------- // Cursor surface restricion. Register Ref: CURACNTR, CURABASE // -------------------------- Data.Cursor.Alignment = pGmmLibContext->GetWaTable().WaCursor16K ? GMM_KBYTE(16) : PAGE_SIZE; Data.Cursor.PitchAlignment = 1; Data.Cursor.LockPitchAlignment = 1; Data.Cursor.RenderPitchAlignment = 1; Data.Cursor.MinPitch = 1; Data.Cursor.MaxPitch = 0xffffffff; Data.Cursor.MinAllocationSize = 1; Data.Cursor.MinHeight = GMM_SCANLINES(1); Data.Cursor.MinWidth = 1; Data.Cursor.MinDepth = 0; Data.Cursor.MaxHeight = 0xffffffff; Data.Cursor.MaxWidth = 0xffffffff; Data.Cursor.MaxDepth = 0xffffffff; Data.Cursor.MaxArraySize = 1; // clang-format off /******************************************************************************************************/ /*************************************** Width, Height, Depth, MtsWidth, MtsHeight, MtsDepth */ /******************************************************************************************************/ // Legacy TILE_X/Y SET_TILE_MODE_INFO(LEGACY_TILE_X, 512, 8, 1, 0, 0, 0) SET_TILE_MODE_INFO(LEGACY_TILE_Y, 128, 32, 1, 0, 0, 0) // YS 1D SET_TILE_MODE_INFO(TILE_YS_1D_128bpe, 4096, 1, 1, 1024, 1, 1) SET_TILE_MODE_INFO(TILE_YS_1D_64bpe, 8192, 1, 1, 2048, 1, 1) SET_TILE_MODE_INFO(TILE_YS_1D_32bpe, 16384, 1, 1, 4096, 1, 1) SET_TILE_MODE_INFO(TILE_YS_1D_16bpe, 32768, 1, 1, 8192, 1, 1) SET_TILE_MODE_INFO(TILE_YS_1D_8bpe, 65536, 1, 1, 16384, 1, 1) // YS 2D SET_TILE_MODE_INFO(TILE_YS_2D_128bpe, 1024, 64, 1, 32, 64, 1) SET_TILE_MODE_INFO(TILE_YS_2D_64bpe, 1024, 64, 1, 64, 64, 1) SET_TILE_MODE_INFO(TILE_YS_2D_32bpe, 512, 128, 1, 64, 128, 1) SET_TILE_MODE_INFO(TILE_YS_2D_16bpe, 512, 128, 1, 128, 128, 1) SET_TILE_MODE_INFO(TILE_YS_2D_8bpe, 256, 256, 1, 128, 256, 1) // YS 2D 2X SET_TILE_MODE_INFO(TILE_YS_2D_2X_128bpe, 512, 64, 1, 32, 32, 1) SET_TILE_MODE_INFO(TILE_YS_2D_2X_64bpe, 512, 64, 1, 64, 32, 1) SET_TILE_MODE_INFO(TILE_YS_2D_2X_32bpe, 256, 128, 1, 64, 64, 1) SET_TILE_MODE_INFO(TILE_YS_2D_2X_16bpe, 256, 128, 1, 128, 64, 1) SET_TILE_MODE_INFO(TILE_YS_2D_2X_8bpe, 128, 256, 1, 128, 128, 1) // YS 2D 4X SET_TILE_MODE_INFO(TILE_YS_2D_4X_128bpe, 512, 32, 1, 16, 32, 1) SET_TILE_MODE_INFO(TILE_YS_2D_4X_64bpe, 512, 32, 1, 32, 32, 1) SET_TILE_MODE_INFO(TILE_YS_2D_4X_32bpe, 256, 64, 1, 32, 64, 1) SET_TILE_MODE_INFO(TILE_YS_2D_4X_16bpe, 256, 64, 1, 64, 64, 1) SET_TILE_MODE_INFO(TILE_YS_2D_4X_8bpe, 128, 128, 1, 64, 128, 1) // YS 2D 8X SET_TILE_MODE_INFO(TILE_YS_2D_8X_128bpe, 256, 32, 1, 16, 16, 1) SET_TILE_MODE_INFO(TILE_YS_2D_8X_64bpe, 256, 32, 1, 32, 16, 1) SET_TILE_MODE_INFO(TILE_YS_2D_8X_32bpe, 128, 64, 1, 32, 32, 1) SET_TILE_MODE_INFO(TILE_YS_2D_8X_16bpe, 128, 64, 1, 64, 32, 1) SET_TILE_MODE_INFO(TILE_YS_2D_8X_8bpe, 64, 128, 1, 64, 64, 1) // YS 2D 16X SET_TILE_MODE_INFO(TILE_YS_2D_16X_128bpe, 256, 16, 1, 8, 16, 1) SET_TILE_MODE_INFO(TILE_YS_2D_16X_64bpe, 256, 16, 1, 16, 16, 1) SET_TILE_MODE_INFO(TILE_YS_2D_16X_32bpe, 128, 32, 1, 16, 32, 1) SET_TILE_MODE_INFO(TILE_YS_2D_16X_16bpe, 128, 32, 1, 32, 32, 1) SET_TILE_MODE_INFO(TILE_YS_2D_16X_8bpe, 64, 64, 1, 32, 64, 1) // YS 3D SET_TILE_MODE_INFO(TILE_YS_3D_128bpe, 256, 16, 16, 8, 16, 16) SET_TILE_MODE_INFO(TILE_YS_3D_64bpe, 256, 16, 16, 16, 16, 16) SET_TILE_MODE_INFO(TILE_YS_3D_32bpe, 128, 32, 16, 16, 32, 16) SET_TILE_MODE_INFO(TILE_YS_3D_16bpe, 64, 32, 32, 16, 32, 32) SET_TILE_MODE_INFO(TILE_YS_3D_8bpe, 64, 32, 32, 32, 32, 32) // YF 1D SET_TILE_MODE_INFO(TILE_YF_1D_128bpe, 256, 1, 1, 64, 1, 1) SET_TILE_MODE_INFO(TILE_YF_1D_64bpe, 512, 1, 1, 128, 1, 1) SET_TILE_MODE_INFO(TILE_YF_1D_32bpe, 1024, 1, 1, 256, 1, 1) SET_TILE_MODE_INFO(TILE_YF_1D_16bpe, 2048, 1, 1, 512, 1, 1) SET_TILE_MODE_INFO(TILE_YF_1D_8bpe, 4096, 1, 1, 1024, 1, 1) // YF 2D SET_TILE_MODE_INFO(TILE_YF_2D_128bpe, 256, 16, 1, 8, 16, 1) SET_TILE_MODE_INFO(TILE_YF_2D_64bpe, 256, 16, 1, 16, 16, 1) SET_TILE_MODE_INFO(TILE_YF_2D_32bpe, 128, 32, 1, 16, 32, 1) SET_TILE_MODE_INFO(TILE_YF_2D_16bpe, 128, 32, 1, 32, 32, 1) SET_TILE_MODE_INFO(TILE_YF_2D_8bpe, 64, 64, 1, 32, 64, 1) // YF 2D 2X SET_TILE_MODE_INFO(TILE_YF_2D_2X_128bpe, 128, 16, 1, 4, 8, 1) SET_TILE_MODE_INFO(TILE_YF_2D_2X_64bpe, 128, 16, 1, 8, 8, 1) SET_TILE_MODE_INFO(TILE_YF_2D_2X_32bpe, 64, 32, 1, 8, 16, 1) SET_TILE_MODE_INFO(TILE_YF_2D_2X_16bpe, 64, 32, 1, 16, 16, 1) SET_TILE_MODE_INFO(TILE_YF_2D_2X_8bpe, 32, 64, 1, 16, 32, 1) // YF 2D 4X SET_TILE_MODE_INFO(TILE_YF_2D_4X_128bpe, 128, 8, 1, 4, 4, 1) SET_TILE_MODE_INFO(TILE_YF_2D_4X_64bpe, 128, 8, 1, 8, 4, 1) SET_TILE_MODE_INFO(TILE_YF_2D_4X_32bpe, 64, 16, 1, 8, 8, 1) SET_TILE_MODE_INFO(TILE_YF_2D_4X_16bpe, 64, 16, 1, 16, 8, 1) SET_TILE_MODE_INFO(TILE_YF_2D_4X_8bpe, 32, 32, 1, 16, 16, 1) // YF 2D 8X SET_TILE_MODE_INFO(TILE_YF_2D_8X_128bpe, 64, 8, 1, 4, 4, 1) SET_TILE_MODE_INFO(TILE_YF_2D_8X_64bpe, 64, 8, 1, 8, 4, 1) SET_TILE_MODE_INFO(TILE_YF_2D_8X_32bpe, 32, 16, 1, 8, 8, 1) SET_TILE_MODE_INFO(TILE_YF_2D_8X_16bpe, 32, 16, 1, 16, 8, 1) SET_TILE_MODE_INFO(TILE_YF_2D_8X_8bpe, 16, 32, 1, 16, 16, 1) // YF 2D 16X SET_TILE_MODE_INFO(TILE_YF_2D_16X_128bpe, 64, 4, 1, 1, 4, 1) SET_TILE_MODE_INFO(TILE_YF_2D_16X_64bpe, 64, 4, 1, 2, 4, 1) SET_TILE_MODE_INFO(TILE_YF_2D_16X_32bpe, 32, 8, 1, 4, 4, 1) SET_TILE_MODE_INFO(TILE_YF_2D_16X_16bpe, 32, 8, 1, 8, 4, 1) SET_TILE_MODE_INFO(TILE_YF_2D_16X_8bpe, 16, 16, 1, 8, 4, 1) // YF 3D SET_TILE_MODE_INFO(TILE_YF_3D_128bpe, 64, 8, 8, 4, 4, 8) SET_TILE_MODE_INFO(TILE_YF_3D_64bpe, 64, 8, 8, 8, 4, 8) SET_TILE_MODE_INFO(TILE_YF_3D_32bpe, 32, 16, 8, 8, 8, 8) SET_TILE_MODE_INFO(TILE_YF_3D_16bpe, 16, 16, 16, 8, 8, 16) SET_TILE_MODE_INFO(TILE_YF_3D_8bpe, 16, 16, 16, 16, 8, 16) // clang-format on //-------------------------- // Fence paramaters. Register Ref: FENCE //-------------------------- Data.NumberFenceRegisters = pGmmLibContext->GetWaTable().Wa16TileFencesOnly ? 16 : 32; Data.FenceLowBoundShift = 12; Data.FenceLowBoundMask = GFX_MASK(12, 31); Data.MinFenceSize = GMM_MBYTE(1); Data.PagingBufferPrivateDataSize = GMM_KBYTE(4); Data.MaxLod = 14; // [0,14] --> 15 Total Data.FBCRequiredStolenMemorySize = GMM_MBYTE(8); // -------------------------- // Surface Alignment Units // -------------------------- Data.TexAlign.CCS.Align.Width = 128; Data.TexAlign.CCS.Align.Height = 64; Data.TexAlign.CCS.MaxPitchinTiles = 512; Data.TexAlign.Compressed.Width = 4; // No reason for > HALIGN_4. Data.TexAlign.Compressed.Height = 4; // No reason for > VALIGN_4. Data.TexAlign.Compressed.Depth = 4; // No reason for > DALIGN_4. Data.TexAlign.Depth.Width = 4; // See usage for 16bpp HALIGN_8 special-casing. Data.TexAlign.Depth.Height = 4; Data.TexAlign.Depth_D16_UNORM_1x_4x_16x.Width = 8; Data.TexAlign.Depth_D16_UNORM_1x_4x_16x.Height = Data.TexAlign.Depth.Height; Data.TexAlign.Depth_D16_UNORM_2x_8x.Width = 8; Data.TexAlign.Depth_D16_UNORM_2x_8x.Height = Data.TexAlign.Depth.Height; Data.TexAlign.SeparateStencil.Width = 8; Data.TexAlign.SeparateStencil.Height = 8; Data.TexAlign.YUV422.Width = 4; Data.TexAlign.YUV422.Height = 4; Data.TexAlign.AllOther.Width = 16; // HALIGN_16 required for non-MSAA RT's for CCS Fast-Clear and...TBA Data.TexAlign.AllOther.Height = 4; // VALIGN_4 should be sufficent. Data.TexAlign.XAdapter.Height = D3DKMT_CROSS_ADAPTER_RESOURCE_HEIGHT_ALIGNMENT; Data.TexAlign.XAdapter.Width = 1; //minimum should be one. // ---------------------------------- // SURFACE_STATE YOffset Granularity // ---------------------------------- Data.SurfaceStateYOffsetGranularity = 4; Data.SamplerFetchGranularityHeight = 4; Data.SamplerFetchGranularityWidth = 4; // ---------------------------------- // Restrictions for Cross adapter resource // ---------------------------------- Data.XAdapter.Alignment = GMM_KBYTE(64); //64KB for DX12/StdSwizzle—-Not worth special-casing. Data.XAdapter.PitchAlignment = GMM_BYTES(D3DKMT_CROSS_ADAPTER_RESOURCE_PITCH_ALIGNMENT); Data.XAdapter.RenderPitchAlignment = GMM_BYTES(D3DKMT_CROSS_ADAPTER_RESOURCE_PITCH_ALIGNMENT); Data.XAdapter.LockPitchAlignment = GMM_BYTES(D3DKMT_CROSS_ADAPTER_RESOURCE_PITCH_ALIGNMENT); Data.XAdapter.MinPitch = GMM_BYTES(32); Data.XAdapter.MaxPitch = (pGmmLibContext->GetWaTable().WaRestrictPitch128KB) ? GMM_KBYTE(128) : GMM_KBYTE(256); Data.XAdapter.MinAllocationSize = PAGE_SIZE; Data.XAdapter.MinHeight = GMM_SCANLINES(1); Data.XAdapter.MinWidth = GMM_PIXELS(1); Data.XAdapter.MinDepth = 0; Data.XAdapter.MaxHeight = GMM_KBYTE(16); Data.XAdapter.MaxWidth = GMM_KBYTE(16); Data.XAdapter.MaxDepth = GMM_FIELD_NA; Data.XAdapter.MaxArraySize = GMM_KBYTE(2); //--------------------------------------------- //MaxSize for any surface type //--------------------------------------------- Data.SurfaceMaxSize = GMM_GBYTE(256); Data.MaxGpuVirtualAddressBitsPerResource = 38; Data.HiZPixelsPerByte = 2; Data.ReconMaxHeight = Data.Texture2DSurface.MaxHeight; // Reconstructed surfaces require more height and width for higher resolutions. Data.ReconMaxWidth = Data.Texture2DSurface.MaxWidth; Data.NoOfBitsSupported = 39; Data.HighestAcceptablePhysicalAddress = GFX_MASK_LARGE(0, 38); } gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/Platform/GmmGen11Platform.cpp000066400000000000000000000144701466655022700253720ustar00rootroot00000000000000/*============================================================================== Copyright(c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ============================================================================*/ #include "Internal/Common/GmmLibInc.h" #include "Internal/Common/Platform/GmmGen10Platform.h" #include "Internal/Common/Platform/GmmGen11Platform.h" GmmLib::PlatformInfoGen11::PlatformInfoGen11(PLATFORM &Platform, Context *pGmmLibContext) : PlatformInfoGen10(Platform, pGmmLibContext) { Data.SurfaceMaxSize = GMM_GBYTE(16384); Data.MaxGpuVirtualAddressBitsPerResource = 44; //Override the Height VP9 VdEnc requirement for Gen11 8k resolution. Data.ReconMaxHeight = GMM_KBYTE(32); //Override CCS MaxPitch requirement if(GFX_GET_CURRENT_PRODUCT(Data.Platform) == IGFX_ICELAKE) { Data.TexAlign.CCS.MaxPitchinTiles = 1024; } if(GFX_GET_CURRENT_PRODUCT(Data.Platform) == IGFX_LAKEFIELD) { Data.SurfaceMaxSize = GMM_GBYTE(64); Data.MaxGpuVirtualAddressBitsPerResource = 36; } } ///////////////////////////////////////////////////////////////////////////////////// /// Validates the MMC parameters passed in by clients to make sure they do not /// conflict or ask for unsupporting combinations/features. /// /// @param[in] GMM_TEXTURE_INFO which specify what sort of resource to create /// @return 1 is validation passed. 0 otherwise. ///////////////////////////////////////////////////////////////////////////////////// uint8_t GmmLib::PlatformInfoGen11::ValidateMMC(GMM_TEXTURE_INFO &Surf) { if(Surf.Flags.Gpu.MMC && //For Media Memory Compression -- ((!(GMM_IS_4KB_TILE(Surf.Flags) || GMM_IS_64KB_TILE(Surf.Flags))) || Surf.ArraySize > GMM_MAX_MMC_INDEX)) { return 0; } if(GFX_GET_CURRENT_PRODUCT(pGmmLibContext->GetPlatformInfo().Platform) == IGFX_LAKEFIELD) { if(Surf.Flags.Gpu.MMC && Surf.Flags.Gpu.UnifiedAuxSurface && !(Surf.Flags.Info.TiledY && (Surf.Format == GMM_FORMAT_NV12 || GmmIsP0xx(Surf.Format)))) { GMM_ASSERTDPF(0, "Invalid MMC usage for LKF!"); return 0; } } return 1; } ///////////////////////////////////////////////////////////////////////////////////// /// Validates the UnifiedAuxSurface parameters passed in by clients to make sure they do not /// conflict or ask for unsupporting combinations/features. /// /// @param[in] GMM_TEXTURE_INFO which specify what sort of resource to create /// @return 1 is validation passed. 0 otherwise. ///////////////////////////////////////////////////////////////////////////////////// uint8_t GmmLib::PlatformInfoGen11::ValidateUnifiedAuxSurface(GMM_TEXTURE_INFO &Surf) { if((Surf.Flags.Gpu.UnifiedAuxSurface) && !( //--- Legitimate UnifiedAuxSurface Case ------------------------------------------ Surf.Flags.Gpu.CCS && ((Surf.MSAA.NumSamples <= 1 && (Surf.Flags.Gpu.RenderTarget || Surf.Flags.Gpu.Texture))) || ((GFX_GET_CURRENT_PRODUCT(pGmmLibContext->GetPlatformInfo().Platform) == IGFX_LAKEFIELD) && Surf.Flags.Gpu.MMC && (Surf.MSAA.NumSamples <= 1)))) { GMM_ASSERTDPF(0, "Invalid UnifiedAuxSurface usage!"); return 0; } return 1; } //============================================================================= // // Function: CheckFmtDisplayDecompressible // // Desc: Returns true if display hw supports lossless render/media decompression // else returns false. // Umds can call it to decide if full resolve is required // // Parameters: // See function arguments. // // Returns: // uint8_t //----------------------------------------------------------------------------- uint8_t GmmLib::PlatformInfoGen11::CheckFmtDisplayDecompressible(GMM_TEXTURE_INFO &Surf, bool IsSupportedRGB64_16_16_16_16, bool IsSupportedRGB32_8_8_8_8, bool IsSupportedRGB32_2_10_10_10, bool IsSupportedMediaFormats) { bool IsRenderCompressed = false; bool IsMediaCompressed = false; GMM_UNREFERENCED_PARAMETER(IsSupportedMediaFormats); if(GFX_GET_CURRENT_PRODUCT(pGmmLibContext->GetPlatformInfo().Platform) == IGFX_LAKEFIELD) { if(Surf.Flags.Gpu.MMC && Surf.Flags.Info.TiledY && (Surf.Format == GMM_FORMAT_NV12 || Surf.Format == GMM_FORMAT_P010)) { IsMediaCompressed = true; } if(IsSupportedRGB64_16_16_16_16 || //RGB64 16:16 : 16 : 16 FP16 IsSupportedRGB32_8_8_8_8 || //RGB32 8 : 8 : 8 : 8 IsSupportedRGB32_2_10_10_10) //RGB32 2 : 10 : 10 : 10 { IsRenderCompressed = true; } } else { // Pre-LKF1 if(IsSupportedRGB32_8_8_8_8 || //RGB32 8 : 8 : 8 : 8 (GFX_GET_CURRENT_PRODUCT(pGmmLibContext->GetPlatformInfo().Platform) == IGFX_ICELAKE && IsSupportedRGB64_16_16_16_16)) //RGB64 16:16 : 16 : 16 FP16 { IsRenderCompressed = true; } } return IsRenderCompressed || IsMediaCompressed; } gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/Platform/GmmGen12Platform.cpp000066400000000000000000001050641466655022700253730ustar00rootroot00000000000000/*============================================================================== Copyright(c) 2019 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ============================================================================*/ #include "Internal/Common/GmmLibInc.h" #include "Internal/Common/Platform/GmmGen12Platform.h" /************************ RT->CCS Sizing definitions ************************ H/V/D Align and Downscale factor to obtain CCS from given RT dimensions Restrictions: CCS's RT (2D/3D YF) alignment to 4x1 (2D/3D YF) pages sharing 1x1 Aux$line (2D YS) 2x2 ( 2D YF) pages " (3D YS) 2x1x2 ( 3D YF) pages " ie Slices share Aux$line (Color MSAA'd YF) 4x1 (MSAA'dYF) pages " ie all samples share Aux$line (Samples are array'd ie YF 4KB = YF-MSAA x MSAA-Samples) (Color MSAA 2x/4x YS) 2x2x1 ( 2D YF) pages " ie Single sample per Aux$line (Color MSAA 8x YS) 1x2x2 ( 2D YF) pages " ie 2 samples share Aux$line (Color MSAA 16x YS) 1x1x4 ( 2D YF) pages " ie 4 samples share Aux$line (Depth MSAA YF) 4x1 ( 2D YF) pages " ie all samples share Aux$line (Depth MSAA 2x/4x YS) 2x2x1 ( 2D YF) pages " ie Single sample per Aux$line (Depth MSAA 8x YS) 1x2x2 ( 2D YF) pages " ie 2 samples share Aux$line (Depth MSAA 16x YS) 1x1x4 ( 2D YF) pages " ie 4 samples share Aux$line ie Depth/Color MSAA have common alignment, but due to different pixel packing (Depth MSS is interleaved, Color MSS is arrayed) SamplePerAux$line samples are X-major (for Depth), while Y-major (for Color) packed ie For Depth MSAA, Hdownscale *=SamplePerAux$line; for color MSAA, Vdownscale = Vdownscale; for both, MSAA-samples/SamplePerAux$line times sample shared CCS-size HAlign: Horizontal Align in pixels VAlign: Vertical Align in pixels DAlign: Depth Align in pixels HAlignxVAlignxDAlign [RT size] occupies one Aux$line SamplesPerAux$line: Samples sharing CCS; NSamples divisor on MSAA-samples giving multiple (on shared CCS) to cover all samples HDownscale: width divisor on CCSRTAlign`d width VDownscale: height divisor on CCSRTAlign`d height Convention: (+ve) HDownscale/VDownscale are downscale factors, and used as divisors (-ve) HDownscale/VDownscale are upscale factors, their absolute value used as multipliers ie if HDownscale etc is smaller than 1, its reciprocal is stored with -ve sign <---- CCSRTALIGN -----> <-- RT->CCS downscale--> ( TileMode, HAlign , VAlign, DAlign, HDownscale, VDownscale) or SamplesPerAux$line, eg: CCSRTALIGN(TILE_YF_2D_8bpe, 256, 64, 1, 16, 16 ) **********************************************************************************************************/ ///////////////////////////////////////////////////////////////////////////////////// /// Allocates This function will initialize the necessary info based on platform. /// - Buffer type restrictions (Eg: Z, Color, Display) /// - X/Y tile dimensions /// /// @param[in] Platform: Contains information about platform to initialize an object ///////////////////////////////////////////////////////////////////////////////////// GmmLib::PlatformInfoGen12::PlatformInfoGen12(PLATFORM &Platform, Context *pGmmLibContext) : PlatformInfoGen11(Platform, pGmmLibContext) { __GMM_ASSERTPTR(pGmmLibContext, VOIDRETURN); //Compression format update GMM_RESOURCE_FORMAT GmmFormat; #define GMM_FORMAT_SKU(FtrXxx) (pGmmLibContext->GetSkuTable().FtrXxx != 0) #define GMM_FORMAT(Name, bpe, _Width, _Height, _Depth, IsRT, IsASTC, RcsSurfaceFormat, SSCompressionFmt, Availability) \ \ { \ GmmFormat = GMM_FORMAT_##Name; \ Data.FormatTable[GmmFormat].CompressionFormat.CompressionFormat = static_cast(SSCompressionFmt); \ } #include "External/Common/GmmFormatTable.h" // -------------------------- // Surface Alignment Units // -------------------------- // 3DSTATE_DEPTH_BUFFER //====================================================================== // Surf Format | MSAA | HAlign | VAlign | //====================================================================== // D16_UNORM | 1x, 4x, 16x | 8 | 8 | // D16_UNORM | 2x, 8x | 16 | 4 | // Not D16_UNORM | 1x,2x,4x,8x,16x | 8 | 4 | //====================================================================== // 3DSTATE_STENCIL_BUFFER //====================================================================== // Surf Format | MSAA | HAlign | VAlign | //====================================================================== // N/A | N/A | 16 | 8 | //====================================================================== Data.SurfaceMaxSize = GMM_GBYTE(16384); Data.MaxGpuVirtualAddressBitsPerResource = 44; //Override the Height VP9 VdEnc requirement for Gen12 16k resolution. Data.ReconMaxHeight = GMM_KBYTE(48); Data.ReconMaxWidth = GMM_KBYTE(32); if((GFX_GET_CURRENT_PRODUCT(Data.Platform) >= IGFX_DG1)) { Data.HiZPixelsPerByte = 4; } Data.TexAlign.Depth.Width = 8; // Not D16_UNORM Data.TexAlign.Depth.Height = 4; Data.TexAlign.Depth_D16_UNORM_1x_4x_16x.Width = 8; Data.TexAlign.Depth_D16_UNORM_1x_4x_16x.Height = 8; Data.TexAlign.Depth_D16_UNORM_2x_8x.Width = 16; Data.TexAlign.Depth_D16_UNORM_2x_8x.Height = 4; Data.TexAlign.SeparateStencil.Width = 16; Data.TexAlign.SeparateStencil.Height = 8; //CCS unit size ie cacheline Data.TexAlign.CCS.Align.Width = 16; Data.TexAlign.CCS.Align.Height = 4; Data.TexAlign.CCS.Align.Depth = 1; Data.TexAlign.CCS.MaxPitchinTiles = 1024; // clang-format off SET_TILE_MODE_INFO(TILE4, 128, 32, 1, 0, 0, 0) // TILE__64 1D SET_TILE_MODE_INFO(TILE__64_1D_128bpe, 4096, 1, 1, 1024, 1, 1) SET_TILE_MODE_INFO(TILE__64_1D_64bpe, 8192, 1, 1, 2048, 1, 1) SET_TILE_MODE_INFO(TILE__64_1D_32bpe, 16384, 1, 1, 4096, 1, 1) SET_TILE_MODE_INFO(TILE__64_1D_16bpe, 32768, 1, 1, 8192, 1, 1) SET_TILE_MODE_INFO(TILE__64_1D_8bpe, 65536, 1, 1, 16384, 1, 1) // TILE__64 2D SET_TILE_MODE_INFO(TILE__64_2D_128bpe, 1024, 64, 1, 32, 64, 1) SET_TILE_MODE_INFO(TILE__64_2D_64bpe, 1024, 64, 1, 64, 64, 1) SET_TILE_MODE_INFO(TILE__64_2D_32bpe, 512, 128, 1, 64, 128, 1) SET_TILE_MODE_INFO(TILE__64_2D_16bpe, 512, 128, 1, 128, 128, 1) SET_TILE_MODE_INFO(TILE__64_2D_8bpe, 256, 256, 1, 128, 256, 1) // TILE__64 2D 2X if(pGmmLibContext->GetSkuTable().FtrXe2PlusTiling) { SET_TILE_MODE_INFO(TILE__64_2D_2X_128bpe, 1024, 32, 1, 32, 32, 1) } else { SET_TILE_MODE_INFO(TILE__64_2D_2X_128bpe, 512, 64, 1, 32, 32, 1) } SET_TILE_MODE_INFO(TILE__64_2D_2X_64bpe, 512, 64, 1, 64, 32, 1) SET_TILE_MODE_INFO(TILE__64_2D_2X_32bpe, 256, 128, 1, 64, 64, 1) SET_TILE_MODE_INFO(TILE__64_2D_2X_16bpe, 256, 128, 1, 128, 64, 1) SET_TILE_MODE_INFO(TILE__64_2D_2X_8bpe, 128, 256, 1, 128, 128, 1) // TILE__64 2D 4X SET_TILE_MODE_INFO(TILE__64_2D_4X_128bpe, 512, 32, 1, 16, 32, 1) SET_TILE_MODE_INFO(TILE__64_2D_4X_64bpe, 512, 32, 1, 32, 32, 1) SET_TILE_MODE_INFO(TILE__64_2D_4X_32bpe, 256, 64, 1, 32, 64, 1) SET_TILE_MODE_INFO(TILE__64_2D_4X_16bpe, 256, 64, 1, 64, 64, 1) SET_TILE_MODE_INFO(TILE__64_2D_4X_8bpe, 128, 128, 1, 64, 128, 1) // TILE__64 2D 8X SET_TILE_MODE_INFO(TILE__64_2D_8X_128bpe, 256, 32, 1, 8, 32, 1) SET_TILE_MODE_INFO(TILE__64_2D_8X_64bpe, 256, 32, 1, 16, 32, 1) SET_TILE_MODE_INFO(TILE__64_2D_8X_32bpe, 256, 32, 1, 16, 64, 1) SET_TILE_MODE_INFO(TILE__64_2D_8X_16bpe, 128, 64, 1, 32, 64, 1) SET_TILE_MODE_INFO(TILE__64_2D_8X_8bpe, 128, 64, 1, 32, 128, 1) // TILE__64 2D 16X SET_TILE_MODE_INFO(TILE__64_2D_16X_128bpe, 256, 16, 1, 8, 16, 1) SET_TILE_MODE_INFO(TILE__64_2D_16X_64bpe, 128, 32, 1, 16, 16, 1) SET_TILE_MODE_INFO(TILE__64_2D_16X_32bpe, 128, 32, 1, 16, 32, 1) SET_TILE_MODE_INFO(TILE__64_2D_16X_16bpe, 128, 32, 1, 32, 32, 1) SET_TILE_MODE_INFO(TILE__64_2D_16X_8bpe, 64, 64, 1, 32, 64, 1) // TILE__64 3D SET_TILE_MODE_INFO(TILE__64_3D_128bpe, 256, 16, 16, 8, 16, 16) SET_TILE_MODE_INFO(TILE__64_3D_64bpe, 256, 16, 16, 16, 16, 16) SET_TILE_MODE_INFO(TILE__64_3D_32bpe, 128, 32, 16, 16, 32, 16) SET_TILE_MODE_INFO(TILE__64_3D_16bpe, 64, 32, 32, 16, 32, 32) SET_TILE_MODE_INFO(TILE__64_3D_8bpe, 64, 32, 32, 32, 32, 32) // clang-format off //Extended CCS alignment for per bpp/Tiling CCS alignment #define CCSRTALIGN(TileMode, HAlign, VAlign, DAlign, HDownscale, VDownscale) \ { \ TexAlignEx.CCSEx[CCS_MODE(TileMode)].Align.Width = HAlign; \ TexAlignEx.CCSEx[CCS_MODE(TileMode)].Align.Height = VAlign; \ TexAlignEx.CCSEx[CCS_MODE(TileMode)].Align.Depth = DAlign; \ TexAlignEx.CCSEx[CCS_MODE(TileMode)].Downscale.Width = HDownscale; \ TexAlignEx.CCSEx[CCS_MODE(TileMode)].Downscale.Height = VDownscale; \ TexAlignEx.CCSEx[CCS_MODE(TileMode)].Downscale.Depth = DAlign; \ } // clang-format off //See "RT->CCS Sizing definitions" comments above for explanation on fields /********* TileMode HAlign, VAlign, DAlign, HDownscale, VDownscale ***/ CCSRTALIGN(TILE_YF_2D_8bpe, 256, 64, 1, 16, 16 ); CCSRTALIGN(TILE_YF_2D_16bpe, 256, 32, 1, 16, 8 ); CCSRTALIGN(TILE_YF_2D_32bpe, 128, 32, 1, 8, 8 ); CCSRTALIGN(TILE_YF_2D_64bpe, 128, 16, 1, 8, 4 ); CCSRTALIGN(TILE_YF_2D_128bpe, 64, 16, 1, 4, 4 ); CCSRTALIGN(TILE_YF_3D_8bpe, 64, 16, 16, 4, 4 ); CCSRTALIGN(TILE_YF_3D_16bpe, 32, 16, 16, 2, 4 ); CCSRTALIGN(TILE_YF_3D_32bpe, 32, 16, 8, 2, 4 ); CCSRTALIGN(TILE_YF_3D_64bpe, 32, 8, 8, 2, 2 ); CCSRTALIGN(TILE_YF_3D_128bpe, 16, 8, 8, 1, 2 ); CCSRTALIGN(TILE_YF_2D_2X_8bpe, 128, 64, 2, 8, 16 ); CCSRTALIGN(TILE_YF_2D_2X_16bpe, 128, 32, 2, 8, 8 ); CCSRTALIGN(TILE_YF_2D_2X_32bpe, 64, 32, 2, 4, 8 ); CCSRTALIGN(TILE_YF_2D_2X_64bpe, 64, 16, 2, 4, 4 ); CCSRTALIGN(TILE_YF_2D_2X_128bpe, 32, 16, 2, 2, 4 ); CCSRTALIGN(TILE_YF_2D_4X_8bpe, 128, 32, 4, 8, 8 ); CCSRTALIGN(TILE_YF_2D_4X_16bpe, 128, 16, 4, 8, 4 ); CCSRTALIGN(TILE_YF_2D_4X_32bpe, 64, 16, 4, 4, 4 ); CCSRTALIGN(TILE_YF_2D_4X_64bpe, 64, 8, 4, 4, 2 ); CCSRTALIGN(TILE_YF_2D_4X_128bpe, 32, 8, 4, 2, 2 ); CCSRTALIGN(TILE_YF_2D_8X_8bpe, 64, 32, 8, 4, 8 ); CCSRTALIGN(TILE_YF_2D_8X_16bpe, 64, 16, 8, 4, 4 ); CCSRTALIGN(TILE_YF_2D_8X_32bpe, 32, 16, 8, 2, 4 ); CCSRTALIGN(TILE_YF_2D_8X_64bpe, 32, 8, 8, 2, 2 ); CCSRTALIGN(TILE_YF_2D_8X_128bpe, 16, 8, 8, 1, 2 ); CCSRTALIGN(TILE_YF_2D_16X_8bpe, 64, 16, 16, 4, 4 ); CCSRTALIGN(TILE_YF_2D_16X_16bpe, 64, 8, 16, 4, 2 ); CCSRTALIGN(TILE_YF_2D_16X_32bpe, 32, 8, 16, 2, 2 ); CCSRTALIGN(TILE_YF_2D_16X_64bpe, 32, 4, 16, 2, 1 ); CCSRTALIGN(TILE_YF_2D_16X_128bpe, 16, 4, 16, 1, 1 ); CCSRTALIGN(TILE_YS_2D_8bpe, 128, 128, 1, 8, 32 ); CCSRTALIGN(TILE_YS_2D_16bpe, 128, 64, 1, 8, 16 ); CCSRTALIGN(TILE_YS_2D_32bpe, 64, 64, 1, 4, 16 ); CCSRTALIGN(TILE_YS_2D_64bpe, 64, 32, 1, 4, 8 ); CCSRTALIGN(TILE_YS_2D_128bpe, 32, 32, 1, 2, 8 ); CCSRTALIGN(TILE_YS_3D_8bpe, 32, 16, 32, 2, 4 ); CCSRTALIGN(TILE_YS_3D_16bpe, 16, 16, 32, 1, 4 ); CCSRTALIGN(TILE_YS_3D_32bpe, 16, 16, 16, 1, 4 ); CCSRTALIGN(TILE_YS_3D_64bpe, 16, 8, 16, 1, 2 ); CCSRTALIGN(TILE_YS_3D_128bpe, 8, 8, 16, -2, 2 ); CCSRTALIGN(TILE_YS_2D_2X_8bpe, 128, 128, 1, 8, 32 ); CCSRTALIGN(TILE_YS_2D_2X_16bpe, 128, 64, 1, 8, 16 ); CCSRTALIGN(TILE_YS_2D_2X_32bpe, 64, 64, 1, 4, 16 ); CCSRTALIGN(TILE_YS_2D_2X_64bpe, 64, 32, 1, 4, 8 ); CCSRTALIGN(TILE_YS_2D_2X_128bpe, 32, 32, 1, 2, 8 ); CCSRTALIGN(TILE_YS_2D_4X_8bpe, 128, 128, 1, 8, 32 ); CCSRTALIGN(TILE_YS_2D_4X_16bpe, 128, 64, 1, 8, 16 ); CCSRTALIGN(TILE_YS_2D_4X_32bpe, 64, 64, 1, 4, 16 ); CCSRTALIGN(TILE_YS_2D_4X_64bpe, 64, 32, 1, 4, 8 ); CCSRTALIGN(TILE_YS_2D_4X_128bpe, 32, 32, 1, 2, 8 ); CCSRTALIGN(TILE_YS_2D_8X_8bpe, 64, 128, 2, 4, 32 ); CCSRTALIGN(TILE_YS_2D_8X_16bpe, 64, 64, 2, 4, 16 ); CCSRTALIGN(TILE_YS_2D_8X_32bpe, 32, 64, 2, 2, 16 ); CCSRTALIGN(TILE_YS_2D_8X_64bpe, 32, 32, 2, 2, 8 ); CCSRTALIGN(TILE_YS_2D_8X_128bpe, 16, 32, 2, 1, 8 ); CCSRTALIGN(TILE_YS_2D_16X_8bpe, 64, 64, 4, 4, 16 ); CCSRTALIGN(TILE_YS_2D_16X_16bpe, 64, 32, 4, 4, 8 ); CCSRTALIGN(TILE_YS_2D_16X_32bpe, 32, 32, 4, 2, 8 ); CCSRTALIGN(TILE_YS_2D_16X_64bpe, 32, 16, 4, 2, 4 ); CCSRTALIGN(TILE_YS_2D_16X_128bpe, 16, 16, 4, 1, 4 ); #undef CCSRTALIGN // clang-format on #define FCRECTALIGN(TileMode, bpp, HAlign, VAlign, DAlign, HDownscale, VDownscale) \ { \ FCTileMode[FCMode(TileMode, bpp)].Align.Width = HAlign; \ FCTileMode[FCMode(TileMode, bpp)].Align.Height = VAlign; \ FCTileMode[FCMode(TileMode, bpp)].Align.Depth = DAlign; \ FCTileMode[FCMode(TileMode, bpp)].Downscale.Width = HDownscale; \ FCTileMode[FCMode(TileMode, bpp)].Downscale.Height = VDownscale; \ FCTileMode[FCMode(TileMode, bpp)].Downscale.Depth = 1; \ } // clang-format off FCRECTALIGN(LEGACY_TILE_Y , 8, 512, 32, 1, 256, 16); FCRECTALIGN(LEGACY_TILE_Y , 16, 256, 32, 1, 128, 16); FCRECTALIGN(LEGACY_TILE_Y , 32, 128, 32, 1, 64, 16); FCRECTALIGN(LEGACY_TILE_Y , 64, 64, 32, 1, 32, 16); FCRECTALIGN(LEGACY_TILE_Y , 128, 32, 32, 1, 16, 16); FCRECTALIGN(TILE_YF_2D_8bpe , 8, 256, 64, 1, 128, 32); FCRECTALIGN(TILE_YF_2D_16bpe , 16, 256, 32, 1, 128, 16); FCRECTALIGN(TILE_YF_2D_32bpe , 32, 128, 32, 1, 64, 16); FCRECTALIGN(TILE_YF_2D_64bpe , 64, 128, 16, 1, 64, 8); FCRECTALIGN(TILE_YF_2D_128bpe, 128, 64, 16, 1, 32, 8); FCRECTALIGN(TILE_YS_2D_8bpe , 8, 128, 128, 1, 64, 64); FCRECTALIGN(TILE_YS_2D_16bpe , 16, 128, 64, 1, 64, 32); FCRECTALIGN(TILE_YS_2D_32bpe , 32, 64, 64, 1, 32, 32); FCRECTALIGN(TILE_YS_2D_64bpe , 64, 64, 32, 1, 32, 16); FCRECTALIGN(TILE_YS_2D_128bpe, 128, 32, 32, 1, 16, 16); if(pGmmLibContext->GetSkuTable().FtrXe2Compression) { FCRECTALIGN(TILE4 , 8, 64, 4, 1, 64, 4); FCRECTALIGN(TILE4 , 16, 32, 4, 1, 32, 4); FCRECTALIGN(TILE4 , 32, 16, 4, 1, 16, 4); FCRECTALIGN(TILE4 , 64, 8, 4, 1, 8, 4); FCRECTALIGN(TILE4 , 128, 4, 4, 1, 4, 4); FCRECTALIGN(TILE__64_2D_8bpe , 8, 64, 4, 1, 64, 4); FCRECTALIGN(TILE__64_2D_16bpe , 16, 32, 4, 1, 32, 4); FCRECTALIGN(TILE__64_2D_32bpe , 32, 16, 4, 1, 16, 4); FCRECTALIGN(TILE__64_2D_64bpe , 64, 8, 4, 1, 8, 4); FCRECTALIGN(TILE__64_2D_128bpe, 128, 4, 4, 1, 4, 4); FCRECTALIGN(TILE__64_3D_8bpe , 8, 64, 32, 32, 4, 8); FCRECTALIGN(TILE__64_3D_16bpe , 16, 32, 32, 32, 8, 4); FCRECTALIGN(TILE__64_3D_32bpe , 32, 32, 32, 16, 4, 4); FCRECTALIGN(TILE__64_3D_64bpe , 64, 32, 16, 16, 4, 4); FCRECTALIGN(TILE__64_3D_128bpe, 128, 16, 16, 16, 4, 4); } else { FCRECTALIGN(TILE4 , 8, 1024, 16, 1, 1024, 16); FCRECTALIGN(TILE4 , 16, 512, 16, 1, 512, 16); FCRECTALIGN(TILE4 , 32, 256, 16, 1, 256, 16); FCRECTALIGN(TILE4 , 64, 128, 16, 1, 128, 16); FCRECTALIGN(TILE4 , 128, 64, 16, 1, 64, 16); FCRECTALIGN(TILE__64_2D_8bpe , 8, 128, 128, 1, 128, 128); FCRECTALIGN(TILE__64_2D_16bpe , 16, 128, 64, 1, 128, 64); FCRECTALIGN(TILE__64_2D_32bpe , 32, 64, 64, 1, 64, 64); FCRECTALIGN(TILE__64_2D_64bpe , 64, 64, 32, 1, 64, 32); FCRECTALIGN(TILE__64_2D_128bpe, 128, 32, 32, 1, 32, 32); FCRECTALIGN(TILE__64_3D_8bpe , 8, 1, 1, 1, 1, 1); FCRECTALIGN(TILE__64_3D_16bpe , 16, 1, 1, 1, 1, 1); FCRECTALIGN(TILE__64_3D_32bpe , 32, 1, 1, 1, 1, 1); FCRECTALIGN(TILE__64_3D_64bpe , 64, 1, 1, 1, 1, 1); FCRECTALIGN(TILE__64_3D_128bpe, 128, 1, 1, 1, 1, 1); } #undef FCRECTALIGN // clang-format on Data.NoOfBitsSupported = 39; Data.HighestAcceptablePhysicalAddress = GFX_MASK_LARGE(0, 38); if (GFX_GET_CURRENT_PRODUCT(Data.Platform) >= IGFX_BMG) { Data.NoOfBitsSupported = 52; Data.HighestAcceptablePhysicalAddress = GFX_MASK_LARGE(0, 51); } if(GFX_GET_CURRENT_PRODUCT(Data.Platform) == IGFX_PVC) { Data.NoOfBitsSupported = 52; Data.HighestAcceptablePhysicalAddress = GFX_MASK_LARGE(0, 51); } else if(GFX_GET_CURRENT_PRODUCT(Data.Platform) == IGFX_ALDERLAKE_S || (GFX_GET_CURRENT_PRODUCT(Data.Platform) == IGFX_ALDERLAKE_P) || (GFX_GET_CURRENT_PRODUCT(Data.Platform) == IGFX_ALDERLAKE_N) || (GFX_GET_CURRENT_PRODUCT(Data.Platform) >= IGFX_XE_HP_SDV)) { Data.NoOfBitsSupported = 46; Data.HighestAcceptablePhysicalAddress = GFX_MASK_LARGE(0, 45); } } void GmmLib::PlatformInfoGen12::ApplyExtendedTexAlign(uint32_t CCSMode, ALIGNMENT &UnitAlign) { if(CCSMode < CCS_MODES) { UnitAlign.Width = TexAlignEx.CCSEx[CCSMode].Align.Width; UnitAlign.Height = TexAlignEx.CCSEx[CCSMode].Align.Height; UnitAlign.Depth = TexAlignEx.CCSEx[CCSMode].Align.Depth; } } ///////////////////////////////////////////////////////////////////////////////////// /// Copies parameters or sets flags based on info sent by the client. /// /// @param[in] CreateParams: Flags which specify what sort of resource to create ///////////////////////////////////////////////////////////////////////////////////// void GmmLib::PlatformInfoGen12::SetCCSFlag(GMM_RESOURCE_FLAG &Flags) { if(Flags.Gpu.MMC) { Flags.Gpu.CCS = Flags.Gpu.MMC; } } ///////////////////////////////////////////////////////////////////////////////////// /// Validates the MMC parameters passed in by clients to make sure they do not /// conflict or ask for unsupporting combinations/features. /// /// @param[in] GMM_TEXTURE_INFO which specify what sort of resource to create /// @return 1 is validation passed. 0 otherwise. ///////////////////////////////////////////////////////////////////////////////////// uint8_t GmmLib::PlatformInfoGen12::ValidateMMC(GMM_TEXTURE_INFO &Surf) { if(Surf.Flags.Gpu.MMC && //For Media Memory Compression -- (!(GMM_IS_4KB_TILE(Surf.Flags) || GMM_IS_64KB_TILE(Surf.Flags)) && (!Surf.Flags.Gpu.__NonMsaaLinearCCS))) { return 0; } return 1; } ///////////////////////////////////////////////////////////////////////////////////// /// Validates the parameters passed in by clients to make sure they do not /// conflict or ask for unsupporting combinations/features. /// /// @param[in] GMM_TEXTURE_INFO which specify what sort of resource to create /// @return 1 is validation passed. 0 otherwise. ///////////////////////////////////////////////////////////////////////////////////// uint8_t GmmLib::PlatformInfoGen12::ValidateCCS(GMM_TEXTURE_INFO &Surf) { if (!( //--- Legitimate CCS Case ---------------------------------------- ((Surf.Flags.Gpu.ProceduralTexture || //procedural texture, or compressed surface (no more separate Aux-CCS) Surf.Flags.Info.RenderCompressed || Surf.Flags.Info.MediaCompressed) || pGmmLibContext->GetSkuTable().FtrXe2Compression && !Surf.Flags.Info.NotCompressed) && (((Surf.Type >= RESOURCE_2D && Surf.Type <= RESOURCE_CUBE) && //Not supported: 1D (until Flat CCS); Others Supported: Buffer, 2D, 3D, cube, Arrays, mip-maps, MSAA, Depth/Stencil (GMM_IS_4KB_TILE(Surf.Flags) || GMM_IS_64KB_TILE(Surf.Flags))) || //Only on 2D + Y/Ys or Lienar buffer (until Flat CCS) (Surf.Flags.Info.Linear && Surf.Type == RESOURCE_BUFFER) || ((pGmmLibContext->GetSkuTable().FtrFlatPhysCCS) && !Surf.Flags.Info.TiledX)))) { GMM_ASSERTDPF(0, "Invalid CCS usage!"); return 0; } if (!pGmmLibContext->GetSkuTable().FtrFlatPhysCCS && Surf.Flags.Info.Linear && Surf.Type == RESOURCE_BUFFER && !Surf.Flags.Info.RenderCompressed) { GMM_ASSERTDPF(0, "Invalid CCS usage - MLC only supported as RC!"); return 0; } //Compressed resource (main surf) must pre-define MC/RC type if(!(Surf.Flags.Gpu.__NonMsaaTileYCcs || Surf.Flags.Gpu.__NonMsaaLinearCCS) && !Surf.Flags.Gpu.ProceduralTexture && !(Surf.Flags.Info.RenderCompressed || Surf.Flags.Info.MediaCompressed || !Surf.Flags.Info.NotCompressed)) { GMM_ASSERTDPF(0, "Invalid CCS usage - RC/MC type unspecified!"); return 0; } if(Surf.Flags.Info.RenderCompressed && Surf.Flags.Info.MediaCompressed) { GMM_ASSERTDPF(0, "Invalid CCS usage - can't be both RC and MC!"); return 0; } if(!pGmmLibContext->GetSkuTable().FtrLinearCCS && (Surf.Type == RESOURCE_3D || Surf.MaxLod > 0 || Surf.MSAA.NumSamples > 1 || !(Surf.Flags.Info.TiledYf || GMM_IS_64KB_TILE(Surf.Flags)))) { GMM_ASSERTDPF(0, "CCS support for (volumetric, mip'd, MSAA'd, TileY) resources only enabled with Linear CCS!"); return 0; } GMM_ASSERTDPF((Surf.Flags.Wa.PreGen12FastClearOnly == 0), "FastClear Only unsupported on Gen12+!"); Surf.Flags.Wa.PreGen12FastClearOnly = 0; return 1; } ///////////////////////////////////////////////////////////////////////////////////// /// Validates the UnifiedAuxSurface parameters passed in by clients to make sure they do not /// conflict or ask for unsupporting combinations/features. /// /// @param[in] GMM_TEXTURE_INFO which specify what sort of resource to create /// @return 1 is validation passed. 0 otherwise. ///////////////////////////////////////////////////////////////////////////////////// uint8_t GmmLib::PlatformInfoGen12::ValidateUnifiedAuxSurface(GMM_TEXTURE_INFO &Surf) { if ((Surf.Flags.Gpu.UnifiedAuxSurface) && !( //--- Legitimate UnifiedAuxSurface Case ------------------------------------------ (Surf.Flags.Gpu.CCS && (Surf.MSAA.NumSamples <= 1 && (Surf.Flags.Gpu.RenderTarget || Surf.Flags.Gpu.Texture))) || (Surf.Flags.Gpu.Depth || Surf.Flags.Gpu.SeparateStencil || Surf.MSAA.NumSamples > 1))) { GMM_ASSERTDPF(0, "Invalid UnifiedAuxSurface usage!"); return 0; } return 1; } //============================================================================= // // Function: CheckFmtDisplayDecompressible // // Desc: Returns true if display hw supports lossless render/media decompression // else returns false. Restrictions are from // Umds can call it to decide if full resolve is required // // Parameters: // See function arguments. // // Returns: // uint8_t //----------------------------------------------------------------------------- uint8_t GmmLib::PlatformInfoGen12::CheckFmtDisplayDecompressible(GMM_TEXTURE_INFO &Surf, bool IsSupportedRGB64_16_16_16_16, bool IsSupportedRGB32_8_8_8_8, bool IsSupportedRGB32_2_10_10_10, bool IsSupportedMediaFormats) { //Check fmt is display decompressible if (((Surf.Flags.Info.RenderCompressed || Surf.Flags.Info.MediaCompressed || !Surf.Flags.Info.NotCompressed) && (IsSupportedRGB64_16_16_16_16 || //RGB64 16:16 : 16 : 16 FP16 IsSupportedRGB32_8_8_8_8 || //RGB32 8 : 8 : 8 : 8 IsSupportedRGB32_2_10_10_10)) || //RGB32 2 : 10 : 10 : 10) || (Surf.Flags.Info.MediaCompressed && IsSupportedMediaFormats)) //YUV444 - Y412, Y416 { //Display supports compression on TileY, but not Yf/Ys (deprecated for display support) if(GMM_IS_4KB_TILE(Surf.Flags) && !(Surf.Flags.Info.TiledYf || GMM_IS_64KB_TILE(Surf.Flags))) { return true; } } return false; } //============================================================================= // // Function: OverrideCompressionFormat // // Desc: SurfaceState compression format encoding differ for MC vs RC on few formats. This function // overrides default RC encoding for MC requests // // Parameters: // See function arguments. // // Returns: // uint8_t //----------------------------------------------------------------------------- uint8_t GmmLib::PlatformInfoGen12::OverrideCompressionFormat(GMM_RESOURCE_FORMAT Format, uint8_t IsMC) { uint8_t CompressionFormat = Data.FormatTable[Format].CompressionFormat.CompressionFormat; if (pGmmLibContext->GetSkuTable().FtrXe2Compression) { if ((CompressionFormat < GMM_XE2_UNIFIED_COMP_MIN_FORMAT) || (CompressionFormat > GMM_XE2_UNIFIED_COMP_MAX_FORMAT)) { CompressionFormat = GMM_XE2_UNIFIED_COMP_FORMAT_INVALID; } __GMM_ASSERT(CompressionFormat != GMM_XE2_UNIFIED_COMP_FORMAT_INVALID); } else if (pGmmLibContext->GetSkuTable().FtrFlatPhysCCS || pGmmLibContext->GetSkuTable().FtrUnified3DMediaCompressionFormats) { if(!IsMC && !pGmmLibContext->GetSkuTable().FtrUnified3DMediaCompressionFormats && (CompressionFormat < GMM_FLATCCS_MIN_RC_FORMAT || CompressionFormat > GMM_FLATCCS_MAX_RC_FORMAT)) { CompressionFormat = GMM_FLATCCS_FORMAT_INVALID; } if(!IsMC && pGmmLibContext->GetSkuTable().FtrUnified3DMediaCompressionFormats && (CompressionFormat < GMM_UNIFIED_COMP_MIN_RC_FORMAT || CompressionFormat > GMM_UNIFIED_COMP_MAX_RC_FORMAT)) { CompressionFormat = GMM_UNIFIED_COMP_FORMAT_INVALID; } else if(IsMC) { if(!pGmmLibContext->GetSkuTable().FtrUnified3DMediaCompressionFormats) { if(CompressionFormat >= GMM_FLATCCS_MIN_MC_FORMAT && CompressionFormat <= GMM_FLATCCS_MAX_MC_FORMAT) { //True MC format encodings, drop MC-identify bit (ie bit5) CompressionFormat -= (GMM_FLATCCS_MIN_MC_FORMAT - 1); } else { // RC format encoding, needs MC format encoding for MC usage switch(CompressionFormat) { case GMM_FLATCCS_FORMAT_RGB10A2: CompressionFormat = GMM_FLATCCS_FORMAT_RGB10b; break; case GMM_FLATCCS_FORMAT_RGBA16U: CompressionFormat = GMM_FLATCCS_FORMAT_RGBA16_MEDIA; break; case GMM_FLATCCS_FORMAT_RGBA8U: CompressionFormat = GMM_FLATCCS_FORMAT_ARGB8b; break; default: if(CompressionFormat < GMM_FLATCCS_MIN_MC_FORMAT || CompressionFormat > GMM_FLATCCS_MAX_MC_FORMAT) { CompressionFormat = GMM_FLATCCS_FORMAT_INVALID; } break; } if(CompressionFormat != GMM_FLATCCS_FORMAT_INVALID) { //drop MC-identify bit (ie bit 5) CompressionFormat -= (GMM_FLATCCS_MIN_MC_FORMAT - 1); } } } else { if(CompressionFormat >= GMM_UNIFIED_COMP_MIN_MC_FORMAT && CompressionFormat <= GMM_UNIFIED_COMP_MAX_MC_FORMAT) { //True MC format encodings, drop MC-identify bit (ie bit5) CompressionFormat -= (GMM_UNIFIED_COMP_MIN_MC_FORMAT - 1); } else { // RC format encoding, needs MC format encoding for MC usage switch(CompressionFormat) { case GMM_UNIFIED_COMP_FORMAT_RGB10A2: CompressionFormat = GMM_UNIFIED_COMP_FORMAT_RGB10b; break; case GMM_UNIFIED_COMP_FORMAT_RGBA16U: case GMM_UNIFIED_COMP_FORMAT_RGBA16F: CompressionFormat = GMM_UNIFIED_COMP_FORMAT_RGBA16_MEDIA; break; case GMM_UNIFIED_COMP_FORMAT_RGBA8U: case GMM_UNIFIED_COMP_FORMAT_RGBA8S: CompressionFormat = GMM_UNIFIED_COMP_FORMAT_ARGB8b; break; default: if(CompressionFormat < GMM_UNIFIED_COMP_MIN_MC_FORMAT || CompressionFormat > GMM_UNIFIED_COMP_MAX_MC_FORMAT) { CompressionFormat = GMM_UNIFIED_COMP_FORMAT_INVALID; } break; } if(CompressionFormat != GMM_UNIFIED_COMP_FORMAT_INVALID) { //drop MC-identify bit (ie bit 5) CompressionFormat -= (GMM_UNIFIED_COMP_MIN_MC_FORMAT - 1); } } } } //Assert if out of MC/RC encoding range -ie format-table must be corrected for Compression code __GMM_ASSERT(!pGmmLibContext->GetSkuTable().FtrUnified3DMediaCompressionFormats && CompressionFormat != GMM_FLATCCS_FORMAT_INVALID || pGmmLibContext->GetSkuTable().FtrUnified3DMediaCompressionFormats && CompressionFormat != GMM_UNIFIED_COMP_FORMAT_INVALID); } return CompressionFormat; } gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/Platform/GmmGen8Platform.cpp000066400000000000000000000540051466655022700253160ustar00rootroot00000000000000/*============================================================================== Copyright(c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ============================================================================*/ #include "Internal/Common/GmmLibInc.h" ///////////////////////////////////////////////////////////////////////////////////// /// Allocates This function will initialize the necessary info based on platform. /// - Buffer type restrictions (Eg: Z, Color, Display) /// - X/Y tile dimensions /// /// @param[in] Platform: Contains information about platform to initialize an object ///////////////////////////////////////////////////////////////////////////////////// GmmLib::PlatformInfoGen8::PlatformInfoGen8(PLATFORM &Platform, Context *pGmmLibContext) : PlatformInfo(Platform, pGmmLibContext) { __GMM_ASSERTPTR(pGmmLibContext, VOIDRETURN); // -------------------------- // Non Native Dispay Interface buffer restriction. Register Ref: DSPACNTR, DSPASTRIDE, DSPASURF // Clamping res based on 2 Nndi buffers and GMM_NNDI_SEGMENT_SIZE reserved gfx memory // -------------------------- Data.Nndi.Alignment = PAGE_SIZE; Data.Nndi.PitchAlignment = GMM_BYTES(1); Data.Nndi.RenderPitchAlignment = GMM_BYTES(1); Data.Nndi.LockPitchAlignment = GMM_BYTES(1); Data.Nndi.MinPitch = GMM_BYTES(640); Data.Nndi.MaxPitch = GMM_BYTES(8192); Data.Nndi.MinAllocationSize = PAGE_SIZE; Data.Nndi.MinHeight = GMM_SCANLINES(200); Data.Nndi.MinWidth = GMM_PIXELS(320); Data.Nndi.MinDepth = 0; Data.Nndi.MaxHeight = GMM_BYTES(1536); Data.Nndi.MaxWidth = GMM_BYTES(2048); Data.Nndi.MaxDepth = 1; Data.Nndi.MaxArraySize = 1; // -------------------------- // Depth Buffer Restriction. Inst Ref: 3DSTATE_DEPTH_BUFFER // -------------------------- Data.Depth.Alignment = PAGE_SIZE; Data.Depth.PitchAlignment = GMM_BYTES(64); Data.Depth.RenderPitchAlignment = GMM_BYTES(64); Data.Depth.LockPitchAlignment = GMM_BYTES(64); Data.Depth.MinPitch = GMM_BYTES(64); Data.Depth.MaxPitch = GMM_KBYTE(128); // 3DSTATE_DEPTH_BUFFER has conflicting info--but 128KB should be fine. Data.Depth.MinAllocationSize = PAGE_SIZE; Data.Depth.MinHeight = GMM_SCANLINES(1); Data.Depth.MinWidth = GMM_PIXELS(1); Data.Depth.MinDepth = 0; Data.Depth.MaxHeight = GMM_KBYTE(16); Data.Depth.MaxWidth = GMM_KBYTE(16); Data.Depth.MaxDepth = GMM_KBYTE(2); Data.Depth.MaxArraySize = GMM_KBYTE(2); // -------------------------- // Stencil Buffer Restriction. Inst Ref: 3DSTATE_STENCIL_BUFFER // -------------------------- Data.Stencil.Alignment = PAGE_SIZE; Data.Stencil.PitchAlignment = GMM_BYTES(128); Data.Stencil.RenderPitchAlignment = GMM_BYTES(128); Data.Stencil.LockPitchAlignment = GMM_BYTES(128); Data.Stencil.MinPitch = GMM_BYTES(128); Data.Stencil.MaxPitch = GMM_KBYTE(128); // 3DSTATE_STENCIL_BUFFER: 2*Pitch <= 128KB (GMM client allocs 2x-width, so GMM limits to that.) Data.Stencil.MinAllocationSize = PAGE_SIZE; Data.Stencil.MinHeight = GMM_SCANLINES(1); Data.Stencil.MinWidth = GMM_PIXELS(1); Data.Stencil.MinDepth = 0; Data.Stencil.MaxHeight = GMM_KBYTE(16); Data.Stencil.MaxWidth = GMM_KBYTE(16); Data.Stencil.MaxDepth = GMM_KBYTE(2); Data.Stencil.MaxArraySize = GMM_KBYTE(2); // -------------------------- // Hierarchical Depth Buffer Restriction. Inst Ref: 3DSTATE_HIER_DEPTH_BUFFER // -------------------------- Data.HiZ.Alignment = PAGE_SIZE; Data.HiZ.PitchAlignment = GMM_BYTES(128); Data.HiZ.RenderPitchAlignment = GMM_BYTES(128); Data.HiZ.LockPitchAlignment = GMM_BYTES(128); Data.HiZ.MinPitch = GMM_BYTES(128); Data.HiZ.MaxPitch = GMM_KBYTE(128); Data.HiZ.MinAllocationSize = PAGE_SIZE; Data.HiZ.MinHeight = GMM_SCANLINES(1); Data.HiZ.MinWidth = GMM_PIXELS(1); Data.HiZ.MinDepth = 0; Data.HiZ.MaxHeight = GMM_KBYTE(16); Data.HiZ.MaxWidth = GMM_KBYTE(16); Data.HiZ.MaxDepth = GMM_KBYTE(2); Data.HiZ.MaxArraySize = GMM_KBYTE(2); // -------------------------- // Vertex Restriction. Inst Ref: 3DSTATE_VERTEX_BUFFER, 3DSTATE_INSTANCE_STEP_RATE // Note: restrictions are expanded here for UMD flexibility. // -------------------------- Data.Vertex.Alignment = PAGE_SIZE; Data.Vertex.PitchAlignment = GMM_BYTES(1); Data.Vertex.LockPitchAlignment = GMM_BYTES(1); Data.Vertex.RenderPitchAlignment = GMM_BYTES(1); Data.Vertex.MinPitch = GMM_BYTES(1); Data.Vertex.MaxPitch = GMM_GBYTE(2); Data.Vertex.MinAllocationSize = PAGE_SIZE; Data.Vertex.MinHeight = GMM_SCANLINES(1); Data.Vertex.MinWidth = GMM_PIXELS(1); Data.Vertex.MinDepth = 0; Data.Vertex.MaxHeight = GMM_MBYTE(128); //TODO(Minor): How does Media fail when we change this to 1?! Data.Vertex.MaxWidth = GMM_GBYTE(2); Data.Vertex.MaxDepth = GMM_KBYTE(2); Data.Vertex.MaxArraySize = GMM_KBYTE(2); // -------------------------- // Index Buffer Restriction. Inst Ref: 3DSTATE_INDEX_BUFFER // -------------------------- Data.Index = Data.Vertex; // -------------------------- // Linear Buffer Restriction. General purpose. Flexible. // -------------------------- Data.Linear.Alignment = PAGE_SIZE; Data.Linear.PitchAlignment = GMM_BYTES(1); Data.Linear.LockPitchAlignment = GMM_BYTES(1); Data.Linear.RenderPitchAlignment = GMM_BYTES(1); Data.Linear.MinPitch = GMM_BYTES(1); Data.Linear.MaxPitch = GMM_GBYTE(2); Data.Linear.MinAllocationSize = PAGE_SIZE; Data.Linear.MinHeight = GMM_SCANLINES(1); Data.Linear.MinWidth = GMM_PIXELS(1); Data.Linear.MinDepth = 0; Data.Linear.MaxHeight = 1; Data.Linear.MaxWidth = GMM_GBYTE(2); Data.Linear.MaxDepth = 1; Data.Linear.MaxArraySize = 1; // -------------------------- // No Surface Restriction. General purpose. Flexible. // -------------------------- Data.NoRestriction.Alignment = PAGE_SIZE; Data.NoRestriction.PitchAlignment = GMM_BYTES(1); Data.NoRestriction.LockPitchAlignment = GMM_BYTES(1); Data.NoRestriction.RenderPitchAlignment = GMM_BYTES(1); Data.NoRestriction.MinPitch = GMM_BYTES(1); Data.NoRestriction.MinAllocationSize = PAGE_SIZE; Data.NoRestriction.MinHeight = GMM_SCANLINES(1); Data.NoRestriction.MinWidth = GMM_PIXELS(1); Data.NoRestriction.MinDepth = 0; Data.NoRestriction.MaxHeight = GMM_GBYTE(2); Data.NoRestriction.MaxWidth = GMM_GBYTE(256); Data.NoRestriction.MaxPitch = GMM_GBYTE(256); Data.NoRestriction.MaxDepth = GMM_KBYTE(2); Data.NoRestriction.MaxArraySize = GMM_KBYTE(2); // -------------------------- // Constant Buffer Restriction. // -------------------------- Data.Constant = Data.NoRestriction; // -------------------------- // Dx9 Constant Buffer pool Restriction. Inst Ref: 3DSTATE_DX9_CONSTANT_BUFFER_POOL_ALLOC // -------------------------- Data.StateDx9ConstantBuffer = Data.NoRestriction; Data.StateDx9ConstantBuffer.Alignment = GMM_KBYTE(8); // -------------------------- // MC Buffer Restriction // -------------------------- Data.MotionComp = Data.NoRestriction; Data.MotionComp.Alignment = PAGE_SIZE; Data.MotionComp.PitchAlignment = GMM_BYTES(32); Data.MotionComp.LockPitchAlignment = GMM_BYTES(32); Data.MotionComp.RenderPitchAlignment = GMM_BYTES(32); Data.MotionComp.MinPitch = GMM_BYTES(32); // -------------------------- // Stream Buffer Restriction // -------------------------- Data.Stream = Data.NoRestriction; // -------------------------- // Interlace Scan Buffer Restriction // -------------------------- Data.InterlacedScan = Data.NoRestriction; // -------------------------- // Text API Buffer Restriction // -------------------------- Data.TextApi = Data.NoRestriction; // -------------------------- // Overlay Buffer Restriction. Register Ref: OVADD, OSTRIDE // -------------------------- Data.Overlay.Alignment = PAGE_SIZE; Data.Overlay.PitchAlignment = GMM_BYTES(512); Data.Overlay.RenderPitchAlignment = GMM_BYTES(512); Data.Overlay.LockPitchAlignment = GMM_BYTES(512); Data.Overlay.MinPitch = GMM_BYTES(512); Data.Overlay.MaxPitch = GMM_KBYTE(16); Data.Overlay.MinAllocationSize = PAGE_SIZE; Data.Overlay.MinHeight = GMM_SCANLINES(1); Data.Overlay.MinWidth = GMM_PIXELS(1); Data.Overlay.MinDepth = 0; Data.Overlay.MaxHeight = GMM_SCANLINES(4096); Data.Overlay.MaxWidth = GMM_PIXELS(4096); Data.Overlay.MaxDepth = 1; Data.Overlay.MaxArraySize = 1; // -------------------------- // RT & Texture2DSurface restrictions. Inst Ref: SURFACE_STATE // Greatest common restriction source comes from 8bpp RT // -------------------------- Data.Texture2DSurface.Alignment = PAGE_SIZE; Data.Texture2DSurface.PitchAlignment = GMM_BYTES(32); Data.Texture2DSurface.LockPitchAlignment = GMM_BYTES(32); Data.Texture2DSurface.RenderPitchAlignment = GMM_BYTES(32); Data.Texture2DSurface.MinPitch = GMM_BYTES(32); Data.Texture2DSurface.MaxPitch = (pGmmLibContext->GetWaTable().WaRestrictPitch128KB) ? GMM_KBYTE(128) : GMM_KBYTE(256); Data.Texture2DSurface.MinAllocationSize = PAGE_SIZE; Data.Texture2DSurface.MinHeight = GMM_SCANLINES(1); Data.Texture2DSurface.MinWidth = GMM_PIXELS(1); Data.Texture2DSurface.MinDepth = 0; Data.Texture2DSurface.MaxHeight = GMM_KBYTE(16); Data.Texture2DSurface.MaxWidth = GMM_KBYTE(16); Data.Texture2DSurface.MaxDepth = GMM_FIELD_NA; Data.Texture2DSurface.MaxArraySize = GMM_KBYTE(2); { // Linear surfaces accessed with Media Block Read/Write commands // require 64-byte-aligned pitch. Such commands only operate on 2D // resources, so we'll handle the requirement here. Though requirement // applies to linear surfaces only, our up'ing the pitch alignment to // 64 bytes here won't affect tiled surfaces, since their pitch // alignment is never smaller than that. Data.Texture2DLinearSurface = Data.Texture2DSurface; Data.Texture2DLinearSurface.PitchAlignment = GFX_MAX(GMM_BYTES(64), Data.Texture2DSurface.PitchAlignment); Data.Texture2DLinearSurface.LockPitchAlignment = GFX_MAX(GMM_BYTES(64), Data.Texture2DSurface.LockPitchAlignment); Data.Texture2DLinearSurface.RenderPitchAlignment = GFX_MAX(GMM_BYTES(64), Data.Texture2DSurface.RenderPitchAlignment); } // -------------------------- // AsyncFlip Restriction. Register Ref: PRI_STRIDE, PRI_SURF, SRCSZ <-- TODO(Minor): SRCSZ correct reg for W/H req's? // -------------------------- Data.ASyncFlipSurface.Alignment = GMM_KBYTE(256); Data.ASyncFlipSurface.PitchAlignment = GMM_BYTES(64); Data.ASyncFlipSurface.RenderPitchAlignment = GMM_BYTES(64); Data.ASyncFlipSurface.LockPitchAlignment = GMM_BYTES(64); Data.ASyncFlipSurface.MinPitch = GMM_BYTES(64); Data.ASyncFlipSurface.MaxPitch = Data.Texture2DSurface.MaxPitch; Data.ASyncFlipSurface.MinAllocationSize = PAGE_SIZE; Data.ASyncFlipSurface.MinHeight = GMM_SCANLINES(1); Data.ASyncFlipSurface.MinWidth = GMM_PIXELS(1); Data.ASyncFlipSurface.MinDepth = 0; Data.ASyncFlipSurface.MaxHeight = Data.Texture2DSurface.MaxHeight; // Beyond DE requirements-Necessary for mosaic framebuffers Data.ASyncFlipSurface.MaxWidth = Data.Texture2DSurface.MaxWidth; // Okay since GMM isn't actual display requirement gatekeeper. Data.ASyncFlipSurface.MaxDepth = 1; Data.ASyncFlipSurface.MaxArraySize = GMM_KBYTE(2); // -------------------------- // Hardware MBM Restriction. // -------------------------- Data.HardwareMBM = Data.ASyncFlipSurface; // -------------------------- // Video Buffer Restriction // -------------------------- Data.Video = Data.Texture2DLinearSurface; // -------------------------- // RT & CubeSurface restrictions. Inst Ref: SURFACE_STATE // Greatest common restriction source comes from 8bpp RT // -------------------------- Data.CubeSurface.Alignment = PAGE_SIZE; Data.CubeSurface.PitchAlignment = GMM_BYTES(32); Data.CubeSurface.LockPitchAlignment = GMM_BYTES(32); Data.CubeSurface.RenderPitchAlignment = GMM_BYTES(32); Data.CubeSurface.MinPitch = GMM_BYTES(32); Data.CubeSurface.MaxPitch = (pGmmLibContext->GetWaTable().WaRestrictPitch128KB) ? GMM_KBYTE(128) : GMM_KBYTE(256); Data.CubeSurface.MinAllocationSize = PAGE_SIZE; Data.CubeSurface.MinHeight = GMM_SCANLINES(1); Data.CubeSurface.MinWidth = GMM_PIXELS(1); Data.CubeSurface.MinDepth = 0; Data.CubeSurface.MaxHeight = GMM_KBYTE(16); Data.CubeSurface.MaxWidth = GMM_KBYTE(16); Data.CubeSurface.MaxDepth = 1; Data.CubeSurface.MaxArraySize = GMM_KBYTE(2) / 6; // MaxElements / Cubefaces // -------------------------- // RT & 3D Surface restrictions. Inst Ref: SURFACE_STATE // Greatest common restriction source comes from 8bpp RT // -------------------------- Data.Texture3DSurface.Alignment = PAGE_SIZE; Data.Texture3DSurface.PitchAlignment = GMM_BYTES(32); Data.Texture3DSurface.LockPitchAlignment = GMM_BYTES(32); Data.Texture3DSurface.RenderPitchAlignment = GMM_BYTES(32); Data.Texture3DSurface.MinPitch = GMM_BYTES(32); Data.Texture3DSurface.MaxPitch = (pGmmLibContext->GetWaTable().WaRestrictPitch128KB) ? GMM_KBYTE(128) : GMM_KBYTE(256); Data.Texture3DSurface.MinAllocationSize = PAGE_SIZE; Data.Texture3DSurface.MinHeight = GMM_SCANLINES(1); Data.Texture3DSurface.MinWidth = GMM_PIXELS(1); Data.Texture3DSurface.MinDepth = 0; Data.Texture3DSurface.MaxHeight = GMM_KBYTE(2); Data.Texture3DSurface.MaxWidth = GMM_KBYTE(2); Data.Texture3DSurface.MaxDepth = GMM_KBYTE(2); Data.Texture3DSurface.MaxArraySize = GMM_FIELD_NA; // -------------------------- // RT & Buffer Type restrictions. Inst Ref: SURFACE_STATE // Greatest common restriction source comes from 8bpp RT // -------------------------- Data.BufferType.Alignment = PAGE_SIZE; Data.BufferType.PitchAlignment = GMM_BYTES(32); Data.BufferType.LockPitchAlignment = GMM_BYTES(32); Data.BufferType.RenderPitchAlignment = GMM_BYTES(32); Data.BufferType.MinPitch = GMM_BYTES(32); Data.BufferType.MaxPitch = GMM_GBYTE(2); Data.BufferType.MinAllocationSize = PAGE_SIZE; Data.BufferType.MinHeight = GMM_SCANLINES(0); Data.BufferType.MinWidth = GMM_PIXELS(1); Data.BufferType.MinDepth = 0; Data.BufferType.MaxHeight = GMM_SCANLINES(1); Data.BufferType.MaxWidth = GMM_GBYTE(2); Data.BufferType.MaxDepth = GMM_FIELD_NA; Data.BufferType.MaxArraySize = GMM_GBYTE(2); // -------------------------- // Cursor surface restricion. Register Ref: CURACNTR, CURABASE // -------------------------- Data.Cursor.Alignment = pGmmLibContext->GetWaTable().WaCursor16K ? GMM_KBYTE(16) : PAGE_SIZE; Data.Cursor.PitchAlignment = 1; Data.Cursor.LockPitchAlignment = 1; Data.Cursor.RenderPitchAlignment = 1; Data.Cursor.MinPitch = 1; Data.Cursor.MaxPitch = 0xffffffff; Data.Cursor.MinAllocationSize = 1; Data.Cursor.MinHeight = GMM_SCANLINES(1); Data.Cursor.MinWidth = 1; Data.Cursor.MinDepth = 0; Data.Cursor.MaxHeight = 0xffffffff; Data.Cursor.MaxWidth = 0xffffffff; Data.Cursor.MaxDepth = 0xffffffff; Data.Cursor.MaxArraySize = 1; //-------------------------- // Set TILE_X/Y Parameters //-------------------------- SET_TILE_MODE_INFO(LEGACY_TILE_X, 512, 8, 1, 0, 0, 0) SET_TILE_MODE_INFO(LEGACY_TILE_Y, 128, 32, 1, 0, 0, 0) //-------------------------- // Fence paramaters. Register Ref: FENCE //-------------------------- Data.NumberFenceRegisters = pGmmLibContext->GetWaTable().Wa16TileFencesOnly ? 16 : 32; Data.FenceLowBoundShift = 12; Data.FenceLowBoundMask = GFX_MASK(12, 31); Data.MinFenceSize = GMM_MBYTE(1); Data.PagingBufferPrivateDataSize = GMM_KBYTE(4); Data.MaxLod = 14; // [0,14] --> 15 Total Data.FBCRequiredStolenMemorySize = GMM_MBYTE(8); // -------------------------- // Surface Alignment Units // -------------------------- Data.TexAlign.CCS.Align.Width = 256; Data.TexAlign.CCS.Align.Height = 128; Data.TexAlign.CCS.MaxPitchinTiles = 512; Data.TexAlign.Compressed.Width = 1; Data.TexAlign.Compressed.Height = 1; Data.TexAlign.Compressed.Depth = 1; Data.TexAlign.Depth.Width = 4; // See usage for 16bpp HALIGN_8 special-casing. Data.TexAlign.Depth.Height = 4; Data.TexAlign.Depth_D16_UNORM_1x_4x_16x.Width = 8; Data.TexAlign.Depth_D16_UNORM_1x_4x_16x.Height = Data.TexAlign.Depth.Height; Data.TexAlign.Depth_D16_UNORM_2x_8x.Width = 8; Data.TexAlign.Depth_D16_UNORM_2x_8x.Height = Data.TexAlign.Depth.Height; Data.TexAlign.SeparateStencil.Width = 8; Data.TexAlign.SeparateStencil.Height = 8; Data.TexAlign.YUV422.Width = 4; Data.TexAlign.YUV422.Height = 4; Data.TexAlign.AllOther.Width = 16; // HALIGN_16 required for non-MSAA RT's for CCS Fast-Clear and...TBA Data.TexAlign.AllOther.Height = 4; // VALIGN_4 should be sufficent. Data.TexAlign.XAdapter.Height = D3DKMT_CROSS_ADAPTER_RESOURCE_HEIGHT_ALIGNMENT; Data.TexAlign.XAdapter.Width = 1; //minimum should be one. // ---------------------------------- // SURFACE_STATE YOffset Granularity // ---------------------------------- Data.SurfaceStateYOffsetGranularity = 4; Data.SamplerFetchGranularityHeight = 4; Data.SamplerFetchGranularityWidth = 4; // ---------------------------------- // Restrictions for Cross adapter resource // ---------------------------------- Data.XAdapter.Alignment = PAGE_SIZE; Data.XAdapter.PitchAlignment = GMM_BYTES(D3DKMT_CROSS_ADAPTER_RESOURCE_PITCH_ALIGNMENT); Data.XAdapter.RenderPitchAlignment = GMM_BYTES(D3DKMT_CROSS_ADAPTER_RESOURCE_PITCH_ALIGNMENT); Data.XAdapter.LockPitchAlignment = GMM_BYTES(D3DKMT_CROSS_ADAPTER_RESOURCE_PITCH_ALIGNMENT); Data.XAdapter.MinPitch = GMM_BYTES(32); Data.XAdapter.MaxPitch = (pGmmLibContext->GetWaTable().WaRestrictPitch128KB) ? GMM_KBYTE(128) : GMM_KBYTE(256); Data.XAdapter.MinAllocationSize = PAGE_SIZE; Data.XAdapter.MinHeight = GMM_SCANLINES(1); Data.XAdapter.MinWidth = GMM_PIXELS(1); Data.XAdapter.MinDepth = 0; Data.XAdapter.MaxHeight = GMM_KBYTE(16); Data.XAdapter.MaxWidth = GMM_KBYTE(16); Data.XAdapter.MaxDepth = GMM_FIELD_NA; Data.XAdapter.MaxArraySize = GMM_KBYTE(2); //--------------------------------------------- //MaxSize for any surface type //--------------------------------------------- Data.SurfaceMaxSize = GMM_GBYTE(2); Data.MaxGpuVirtualAddressBitsPerResource = 31; Data.MaxSLMSize = GMM_KBYTE(384); Data.HiZPixelsPerByte = 2; Data.ReconMaxHeight = Data.Texture2DSurface.MaxHeight; // Reconstructed surfaces require more height and width for higher resolutions. Data.ReconMaxWidth = Data.Texture2DSurface.MaxWidth; } gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/Platform/GmmGen9Platform.cpp000066400000000000000000000670471466655022700253310ustar00rootroot00000000000000/*============================================================================== Copyright(c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ============================================================================*/ #include "Internal/Common/GmmLibInc.h" ///////////////////////////////////////////////////////////////////////////////////// /// Allocates This function will initialize the necessary info based on platform. /// - Buffer type restrictions (Eg: Z, Color, Display) /// - X/Y tile dimensions /// /// @param[in] Platform: Contains information about platform to initialize an object ///////////////////////////////////////////////////////////////////////////////////// GmmLib::PlatformInfoGen9::PlatformInfoGen9(PLATFORM &Platform, Context *pGmmLibContext) : PlatformInfo(Platform, pGmmLibContext) { __GMM_ASSERTPTR(pGmmLibContext, VOIDRETURN); // -------------------------- // Non Native Dispay Interface buffer restriction. Register Ref: DSPACNTR, DSPASTRIDE, DSPASURF // Clamping res based on 2 Nndi buffers and GMM_NNDI_SEGMENT_SIZE reserved gfx memory // -------------------------- Data.Nndi.Alignment = PAGE_SIZE; Data.Nndi.PitchAlignment = GMM_BYTES(1); Data.Nndi.RenderPitchAlignment = GMM_BYTES(1); Data.Nndi.LockPitchAlignment = GMM_BYTES(1); Data.Nndi.MinPitch = GMM_BYTES(640); Data.Nndi.MaxPitch = GMM_BYTES(8192); Data.Nndi.MinAllocationSize = PAGE_SIZE; Data.Nndi.MinHeight = GMM_SCANLINES(200); Data.Nndi.MinWidth = GMM_PIXELS(320); Data.Nndi.MinDepth = 0; Data.Nndi.MaxHeight = GMM_BYTES(1536); Data.Nndi.MaxWidth = GMM_BYTES(2048); Data.Nndi.MaxDepth = 1; Data.Nndi.MaxArraySize = 1; // -------------------------- // Depth Buffer Restriction. Inst Ref: 3DSTATE_DEPTH_BUFFER // -------------------------- Data.Depth.Alignment = PAGE_SIZE; Data.Depth.PitchAlignment = GMM_BYTES(64); Data.Depth.RenderPitchAlignment = GMM_BYTES(64); Data.Depth.LockPitchAlignment = GMM_BYTES(64); Data.Depth.MinPitch = GMM_BYTES(64); Data.Depth.MaxPitch = GMM_KBYTE(128); // 3DSTATE_DEPTH_BUFFER has conflicting info--but 128KB should be fine. Data.Depth.MinAllocationSize = PAGE_SIZE; Data.Depth.MinHeight = GMM_SCANLINES(1); Data.Depth.MinWidth = GMM_PIXELS(1); Data.Depth.MinDepth = 0; Data.Depth.MaxHeight = GMM_KBYTE(16); Data.Depth.MaxWidth = GMM_KBYTE(16); Data.Depth.MaxDepth = GMM_KBYTE(2); Data.Depth.MaxArraySize = GMM_KBYTE(2); // -------------------------- // Stencil Buffer Restriction. Inst Ref: 3DSTATE_STENCIL_BUFFER // -------------------------- Data.Stencil.Alignment = PAGE_SIZE; Data.Stencil.PitchAlignment = GMM_BYTES(128); Data.Stencil.RenderPitchAlignment = GMM_BYTES(128); Data.Stencil.LockPitchAlignment = GMM_BYTES(128); Data.Stencil.MinPitch = GMM_BYTES(128); Data.Stencil.MaxPitch = GMM_KBYTE(128); // 3DSTATE_STENCIL_BUFFER: 2*Pitch <= 128KB (GMM client allocs 2x-width, so GMM limits to that.) Data.Stencil.MinAllocationSize = PAGE_SIZE; Data.Stencil.MinHeight = GMM_SCANLINES(1); Data.Stencil.MinWidth = GMM_PIXELS(1); Data.Stencil.MinDepth = 0; Data.Stencil.MaxHeight = GMM_KBYTE(16); Data.Stencil.MaxWidth = GMM_KBYTE(16); Data.Stencil.MaxDepth = GMM_KBYTE(2); Data.Stencil.MaxArraySize = GMM_KBYTE(2); // -------------------------- // Hierarchical Depth Buffer Restriction. Inst Ref: 3DSTATE_HIER_DEPTH_BUFFER // -------------------------- Data.HiZ.Alignment = PAGE_SIZE; Data.HiZ.PitchAlignment = GMM_BYTES(128); Data.HiZ.RenderPitchAlignment = GMM_BYTES(128); Data.HiZ.LockPitchAlignment = GMM_BYTES(128); Data.HiZ.MinPitch = GMM_BYTES(128); Data.HiZ.MaxPitch = GMM_KBYTE(128); Data.HiZ.MinAllocationSize = PAGE_SIZE; Data.HiZ.MinHeight = GMM_SCANLINES(1); Data.HiZ.MinWidth = GMM_PIXELS(1); Data.HiZ.MinDepth = 0; Data.HiZ.MaxHeight = GMM_KBYTE(16); Data.HiZ.MaxWidth = GMM_KBYTE(16); Data.HiZ.MaxDepth = GMM_KBYTE(2); Data.HiZ.MaxArraySize = GMM_KBYTE(2); // -------------------------- // Vertex Restriction. Inst Ref: 3DSTATE_VERTEX_BUFFER, 3DSTATE_INSTANCE_STEP_RATE // Note: restrictions are expanded here for UMD flexibility. // -------------------------- Data.Vertex.Alignment = PAGE_SIZE; Data.Vertex.PitchAlignment = GMM_BYTES(1); Data.Vertex.LockPitchAlignment = GMM_BYTES(1); Data.Vertex.RenderPitchAlignment = GMM_BYTES(1); Data.Vertex.MinPitch = GMM_BYTES(1); Data.Vertex.MaxPitch = GMM_GBYTE(2); Data.Vertex.MinAllocationSize = PAGE_SIZE; Data.Vertex.MinHeight = GMM_SCANLINES(1); Data.Vertex.MinWidth = GMM_PIXELS(1); Data.Vertex.MinDepth = 0; Data.Vertex.MaxHeight = GMM_MBYTE(128); //TODO(Minor): How does Media fail when we change this to 1?! Data.Vertex.MaxWidth = GMM_GBYTE(2); Data.Vertex.MaxDepth = GMM_KBYTE(2); Data.Vertex.MaxArraySize = GMM_KBYTE(2); // -------------------------- // Index Buffer Restriction. Inst Ref: 3DSTATE_INDEX_BUFFER // -------------------------- Data.Index = Data.Vertex; // -------------------------- // Linear Buffer Restriction. General purpose. Flexible. // -------------------------- Data.Linear.Alignment = PAGE_SIZE; Data.Linear.PitchAlignment = GMM_BYTES(1); Data.Linear.LockPitchAlignment = GMM_BYTES(1); Data.Linear.RenderPitchAlignment = GMM_BYTES(1); Data.Linear.MinPitch = GMM_BYTES(1); Data.Linear.MaxPitch = GMM_GBYTE(256); Data.Linear.MinAllocationSize = PAGE_SIZE; Data.Linear.MinHeight = GMM_SCANLINES(1); Data.Linear.MinWidth = GMM_PIXELS(1); Data.Linear.MinDepth = 0; Data.Linear.MaxHeight = 1; Data.Linear.MaxWidth = GMM_GBYTE(256); Data.Linear.MaxDepth = 1; Data.Linear.MaxArraySize = 1; // -------------------------- // No Surface Restriction. General purpose. Flexible. // -------------------------- Data.NoRestriction.Alignment = PAGE_SIZE; Data.NoRestriction.PitchAlignment = GMM_BYTES(1); Data.NoRestriction.LockPitchAlignment = GMM_BYTES(1); Data.NoRestriction.RenderPitchAlignment = GMM_BYTES(1); Data.NoRestriction.MinPitch = GMM_BYTES(1); Data.NoRestriction.MaxPitch = GMM_TBYTE(128); Data.NoRestriction.MinAllocationSize = PAGE_SIZE; Data.NoRestriction.MinHeight = GMM_SCANLINES(1); Data.NoRestriction.MinWidth = GMM_PIXELS(1); Data.NoRestriction.MinDepth = 0; Data.NoRestriction.MaxHeight = GMM_GBYTE(256); Data.NoRestriction.MaxWidth = GMM_TBYTE(128); Data.NoRestriction.MaxDepth = GMM_KBYTE(2); Data.NoRestriction.MaxArraySize = GMM_KBYTE(2); // -------------------------- // Constant Buffer Restriction. // -------------------------- Data.Constant = Data.NoRestriction; // -------------------------- // Dx9 Constant Buffer pool Restriction. Inst Ref: 3DSTATE_DX9_CONSTANT_BUFFER_POOL_ALLOC // -------------------------- Data.StateDx9ConstantBuffer = Data.NoRestriction; Data.StateDx9ConstantBuffer.Alignment = GMM_KBYTE(8); // -------------------------- // MC Buffer Restriction // -------------------------- Data.MotionComp = Data.NoRestriction; Data.MotionComp.Alignment = PAGE_SIZE; Data.MotionComp.PitchAlignment = GMM_BYTES(32); Data.MotionComp.LockPitchAlignment = GMM_BYTES(32); Data.MotionComp.RenderPitchAlignment = GMM_BYTES(32); Data.MotionComp.MinPitch = GMM_BYTES(32); // -------------------------- // Stream Buffer Restriction // -------------------------- Data.Stream = Data.NoRestriction; // -------------------------- // Interlace Scan Buffer Restriction // -------------------------- Data.InterlacedScan = Data.NoRestriction; // -------------------------- // Text API Buffer Restriction // -------------------------- Data.TextApi = Data.NoRestriction; // -------------------------- // RT & Texture2DSurface restrictions. Inst Ref: SURFACE_STATE // Greatest common restriction source comes from 8bpp RT // -------------------------- Data.Texture2DSurface.Alignment = PAGE_SIZE; Data.Texture2DSurface.PitchAlignment = GMM_BYTES(32); Data.Texture2DSurface.LockPitchAlignment = GMM_BYTES(32); Data.Texture2DSurface.RenderPitchAlignment = GMM_BYTES(32); Data.Texture2DSurface.MinPitch = GMM_BYTES(32); Data.Texture2DSurface.MaxPitch = (pGmmLibContext->GetWaTable().WaRestrictPitch128KB) ? GMM_KBYTE(128) : GMM_KBYTE(256); Data.Texture2DSurface.MinAllocationSize = PAGE_SIZE; Data.Texture2DSurface.MinHeight = GMM_SCANLINES(1); Data.Texture2DSurface.MinWidth = GMM_PIXELS(1); Data.Texture2DSurface.MinDepth = 0; Data.Texture2DSurface.MaxHeight = GMM_KBYTE(16); Data.Texture2DSurface.MaxWidth = GMM_KBYTE(16); Data.Texture2DSurface.MaxDepth = GMM_FIELD_NA; Data.Texture2DSurface.MaxArraySize = GMM_KBYTE(2); { // Linear surfaces accessed with Media Block Read/Write commands // require 64-byte-aligned pitch. Such commands only operate on 2D // resources, so we'll handle the requirement here. Though requirement // applies to linear surfaces only, our up'ing the pitch alignment to // 64 bytes here won't affect tiled surfaces, since their pitch // alignment is never smaller than that. Data.Texture2DLinearSurface = Data.Texture2DSurface; Data.Texture2DLinearSurface.PitchAlignment = GFX_MAX(GMM_BYTES(64), Data.Texture2DSurface.PitchAlignment); Data.Texture2DLinearSurface.LockPitchAlignment = GFX_MAX(GMM_BYTES(64), Data.Texture2DSurface.LockPitchAlignment); Data.Texture2DLinearSurface.RenderPitchAlignment = GFX_MAX(GMM_BYTES(64), Data.Texture2DSurface.RenderPitchAlignment); } // -------------------------- // AsyncFlip Restriction. Register Ref: PRI_STRIDE, PRI_SURF, SRCSZ <-- TODO(Minor): SRCSZ correct reg for W/H req's? // -------------------------- Data.ASyncFlipSurface.Alignment = GMM_KBYTE(256); Data.ASyncFlipSurface.PitchAlignment = GMM_BYTES(64); Data.ASyncFlipSurface.RenderPitchAlignment = GMM_BYTES(64); Data.ASyncFlipSurface.LockPitchAlignment = GMM_BYTES(64); Data.ASyncFlipSurface.MinPitch = GMM_BYTES(64); Data.ASyncFlipSurface.MaxPitch = Data.Texture2DSurface.MaxPitch; Data.ASyncFlipSurface.MinAllocationSize = PAGE_SIZE; Data.ASyncFlipSurface.MinHeight = GMM_SCANLINES(1); Data.ASyncFlipSurface.MinWidth = GMM_PIXELS(1); Data.ASyncFlipSurface.MinDepth = 0; Data.ASyncFlipSurface.MaxHeight = Data.Texture2DSurface.MaxHeight; // Beyond DE requirements-Necessary for mosaic framebuffers Data.ASyncFlipSurface.MaxWidth = Data.Texture2DSurface.MaxWidth; // Okay since GMM isn't actual display requirement gatekeeper. Data.ASyncFlipSurface.MaxDepth = 1; Data.ASyncFlipSurface.MaxArraySize = GMM_KBYTE(2); // -------------------------- // Hardware MBM Restriction. // -------------------------- Data.HardwareMBM = Data.ASyncFlipSurface; // -------------------------- // Video Buffer Restriction // -------------------------- Data.Video = Data.Texture2DLinearSurface; // -------------------------- // Overlay Buffer Restriction. Overlay buffer restriction will be same as Async flip surface since SKL has universal planes. // -------------------------- Data.Overlay = Data.ASyncFlipSurface; // -------------------------- // RT & CubeSurface restrictions. Inst Ref: SURFACE_STATE // Greatest common restriction source comes from 8bpp RT // -------------------------- Data.CubeSurface.Alignment = PAGE_SIZE; Data.CubeSurface.PitchAlignment = GMM_BYTES(32); Data.CubeSurface.LockPitchAlignment = GMM_BYTES(32); Data.CubeSurface.RenderPitchAlignment = GMM_BYTES(32); Data.CubeSurface.MinPitch = GMM_BYTES(32); Data.CubeSurface.MaxPitch = (pGmmLibContext->GetWaTable().WaRestrictPitch128KB) ? GMM_KBYTE(128) : GMM_KBYTE(256); Data.CubeSurface.MinAllocationSize = PAGE_SIZE; Data.CubeSurface.MinHeight = GMM_SCANLINES(1); Data.CubeSurface.MinWidth = GMM_PIXELS(1); Data.CubeSurface.MinDepth = 0; Data.CubeSurface.MaxHeight = GMM_KBYTE(16); Data.CubeSurface.MaxWidth = GMM_KBYTE(16); Data.CubeSurface.MaxDepth = 1; Data.CubeSurface.MaxArraySize = GMM_KBYTE(2) / 6; // MaxElements / Cubefaces // -------------------------- // RT & 3D Surface restrictions. Inst Ref: SURFACE_STATE // Greatest common restriction source comes from 8bpp RT // -------------------------- Data.Texture3DSurface.Alignment = PAGE_SIZE; Data.Texture3DSurface.PitchAlignment = GMM_BYTES(32); Data.Texture3DSurface.LockPitchAlignment = GMM_BYTES(32); Data.Texture3DSurface.RenderPitchAlignment = GMM_BYTES(32); Data.Texture3DSurface.MinPitch = GMM_BYTES(32); Data.Texture3DSurface.MaxPitch = (pGmmLibContext->GetWaTable().WaRestrictPitch128KB) ? GMM_KBYTE(128) : GMM_KBYTE(256); Data.Texture3DSurface.MinAllocationSize = PAGE_SIZE; Data.Texture3DSurface.MinHeight = GMM_SCANLINES(1); Data.Texture3DSurface.MinWidth = GMM_PIXELS(1); Data.Texture3DSurface.MinDepth = 0; Data.Texture3DSurface.MaxHeight = GMM_KBYTE(16); Data.Texture3DSurface.MaxWidth = GMM_KBYTE(16); Data.Texture3DSurface.MaxDepth = GMM_KBYTE(2); Data.Texture3DSurface.MaxArraySize = GMM_FIELD_NA; // -------------------------- // RT & Buffer Type restrictions. Inst Ref: SURFACE_STATE // Greatest common restriction source comes from 8bpp RT // -------------------------- Data.BufferType.Alignment = PAGE_SIZE; Data.BufferType.PitchAlignment = GMM_BYTES(32); Data.BufferType.LockPitchAlignment = GMM_BYTES(32); Data.BufferType.RenderPitchAlignment = GMM_BYTES(32); Data.BufferType.MinPitch = GMM_BYTES(32); Data.BufferType.MaxPitch = GMM_GBYTE(256); Data.BufferType.MinAllocationSize = PAGE_SIZE; Data.BufferType.MinHeight = GMM_SCANLINES(0); Data.BufferType.MinWidth = GMM_PIXELS(1); Data.BufferType.MinDepth = 0; Data.BufferType.MaxHeight = GMM_SCANLINES(1); Data.BufferType.MaxWidth = GMM_GBYTE(256); Data.BufferType.MaxDepth = GMM_FIELD_NA; Data.BufferType.MaxArraySize = GMM_GBYTE(2); // -------------------------- // Cursor surface restricion. Register Ref: CURACNTR, CURABASE // -------------------------- Data.Cursor.Alignment = pGmmLibContext->GetWaTable().WaCursor16K ? GMM_KBYTE(16) : PAGE_SIZE; Data.Cursor.PitchAlignment = 1; Data.Cursor.LockPitchAlignment = 1; Data.Cursor.RenderPitchAlignment = 1; Data.Cursor.MinPitch = 1; Data.Cursor.MaxPitch = 0xffffffff; Data.Cursor.MinAllocationSize = 1; Data.Cursor.MinHeight = GMM_SCANLINES(1); Data.Cursor.MinWidth = 1; Data.Cursor.MinDepth = 0; Data.Cursor.MaxHeight = 0xffffffff; Data.Cursor.MaxWidth = 0xffffffff; Data.Cursor.MaxDepth = 0xffffffff; Data.Cursor.MaxArraySize = 1; // clang-format off /******************************************************************************************************/ /*************************************** Width, Height, Depth, MtsWidth, MtsHeight, MtsDepth */ /******************************************************************************************************/ // Legacy TILE_X/Y SET_TILE_MODE_INFO(LEGACY_TILE_X, 512, 8, 1, 0, 0, 0) SET_TILE_MODE_INFO(LEGACY_TILE_Y, 128, 32, 1, 0, 0, 0) // YS 1D SET_TILE_MODE_INFO(TILE_YS_1D_128bpe, 4096, 1, 1, 2048, 1, 1) SET_TILE_MODE_INFO(TILE_YS_1D_64bpe, 8192, 1, 1, 4096, 1, 1) SET_TILE_MODE_INFO(TILE_YS_1D_32bpe, 16384, 1, 1, 8192, 1, 1) SET_TILE_MODE_INFO(TILE_YS_1D_16bpe, 32768, 1, 1, 16384, 1, 1) SET_TILE_MODE_INFO(TILE_YS_1D_8bpe, 65536, 1, 1, 32768, 1, 1) // YS 2D SET_TILE_MODE_INFO(TILE_YS_2D_128bpe, 1024, 64, 1, 32, 64, 1) SET_TILE_MODE_INFO(TILE_YS_2D_64bpe, 1024, 64, 1, 64, 64, 1) SET_TILE_MODE_INFO(TILE_YS_2D_32bpe, 512, 128, 1, 64, 128, 1) SET_TILE_MODE_INFO(TILE_YS_2D_16bpe, 512, 128, 1, 128, 128, 1) SET_TILE_MODE_INFO(TILE_YS_2D_8bpe, 256, 256, 1, 128, 256, 1) // YS 2D 2X SET_TILE_MODE_INFO(TILE_YS_2D_2X_128bpe, 512, 64, 1, 32, 32, 1) SET_TILE_MODE_INFO(TILE_YS_2D_2X_64bpe, 512, 64, 1, 64, 32, 1) SET_TILE_MODE_INFO(TILE_YS_2D_2X_32bpe, 256, 128, 1, 64, 64, 1) SET_TILE_MODE_INFO(TILE_YS_2D_2X_16bpe, 256, 128, 1, 128, 64, 1) SET_TILE_MODE_INFO(TILE_YS_2D_2X_8bpe, 128, 256, 1, 128, 128, 1) // YS 2D 4X SET_TILE_MODE_INFO(TILE_YS_2D_4X_128bpe, 512, 32, 1, 16, 32, 1) SET_TILE_MODE_INFO(TILE_YS_2D_4X_64bpe, 512, 32, 1, 32, 32, 1) SET_TILE_MODE_INFO(TILE_YS_2D_4X_32bpe, 256, 64, 1, 32, 64, 1) SET_TILE_MODE_INFO(TILE_YS_2D_4X_16bpe, 256, 64, 1, 64, 64, 1) SET_TILE_MODE_INFO(TILE_YS_2D_4X_8bpe, 128, 128, 1, 64, 128, 1) // YS 2D 8X SET_TILE_MODE_INFO(TILE_YS_2D_8X_128bpe, 256, 32, 1, 16, 16, 1) SET_TILE_MODE_INFO(TILE_YS_2D_8X_64bpe, 256, 32, 1, 32, 16, 1) SET_TILE_MODE_INFO(TILE_YS_2D_8X_32bpe, 128, 64, 1, 32, 32, 1) SET_TILE_MODE_INFO(TILE_YS_2D_8X_16bpe, 128, 64, 1, 64, 32, 1) SET_TILE_MODE_INFO(TILE_YS_2D_8X_8bpe, 64, 128, 1, 64, 64, 1) // YS 2D 16X SET_TILE_MODE_INFO(TILE_YS_2D_16X_128bpe, 256, 16, 1, 8, 16, 1) SET_TILE_MODE_INFO(TILE_YS_2D_16X_64bpe, 256, 16, 1, 16, 16, 1) SET_TILE_MODE_INFO(TILE_YS_2D_16X_32bpe, 128, 32, 1, 16, 32, 1) SET_TILE_MODE_INFO(TILE_YS_2D_16X_16bpe, 128, 32, 1, 32, 32, 1) SET_TILE_MODE_INFO(TILE_YS_2D_16X_8bpe, 64, 64, 1, 32, 64, 1) // YS 3D SET_TILE_MODE_INFO(TILE_YS_3D_128bpe, 256, 16, 16, 8, 16, 16) SET_TILE_MODE_INFO(TILE_YS_3D_64bpe, 256, 16, 16, 16, 16, 16) SET_TILE_MODE_INFO(TILE_YS_3D_32bpe, 128, 32, 16, 16, 32, 16) SET_TILE_MODE_INFO(TILE_YS_3D_16bpe, 64, 32, 32, 16, 32, 32) SET_TILE_MODE_INFO(TILE_YS_3D_8bpe, 64, 32, 32, 32, 32, 32) // YF 1D SET_TILE_MODE_INFO(TILE_YF_1D_128bpe, 256, 1, 1, 128, 1, 1) SET_TILE_MODE_INFO(TILE_YF_1D_64bpe, 512, 1, 1, 256, 1, 1) SET_TILE_MODE_INFO(TILE_YF_1D_32bpe, 1024, 1, 1, 512, 1, 1) SET_TILE_MODE_INFO(TILE_YF_1D_16bpe, 2048, 1, 1, 1024, 1, 1) SET_TILE_MODE_INFO(TILE_YF_1D_8bpe, 4096, 1, 1, 2048, 1, 1) // YF 2D SET_TILE_MODE_INFO(TILE_YF_2D_128bpe, 256, 16, 1, 8, 16, 1) SET_TILE_MODE_INFO(TILE_YF_2D_64bpe, 256, 16, 1, 16, 16, 1) SET_TILE_MODE_INFO(TILE_YF_2D_32bpe, 128, 32, 1, 16, 32, 1) SET_TILE_MODE_INFO(TILE_YF_2D_16bpe, 128, 32, 1, 32, 32, 1) SET_TILE_MODE_INFO(TILE_YF_2D_8bpe, 64, 64, 1, 32, 64, 1) // YF 3D SET_TILE_MODE_INFO(TILE_YF_3D_128bpe, 64, 8, 8, 4, 4, 8) SET_TILE_MODE_INFO(TILE_YF_3D_64bpe, 64, 8, 8, 8, 4, 8) SET_TILE_MODE_INFO(TILE_YF_3D_32bpe, 32, 16, 8, 8, 8, 8) SET_TILE_MODE_INFO(TILE_YF_3D_16bpe, 16, 16, 16, 8, 8, 16) SET_TILE_MODE_INFO(TILE_YF_3D_8bpe, 16, 16, 16, 16, 8, 16) // clang-format on //-------------------------- // Fence paramaters. Register Ref: FENCE //-------------------------- Data.NumberFenceRegisters = pGmmLibContext->GetWaTable().Wa16TileFencesOnly ? 16 : 32; Data.FenceLowBoundShift = 12; Data.FenceLowBoundMask = GFX_MASK(12, 31); Data.MinFenceSize = GMM_MBYTE(1); Data.PagingBufferPrivateDataSize = GMM_KBYTE(4); Data.MaxLod = 14; // [0,14] --> 15 Total Data.FBCRequiredStolenMemorySize = GMM_MBYTE(8); // -------------------------- // Surface Alignment Units // -------------------------- Data.TexAlign.CCS.Align.Width = 128; Data.TexAlign.CCS.Align.Height = 64; Data.TexAlign.CCS.MaxPitchinTiles = 512; Data.TexAlign.Compressed.Width = 4; // No reason for > HALIGN_4. Data.TexAlign.Compressed.Height = 4; // No reason for > VALIGN_4. Data.TexAlign.Compressed.Depth = 1; Data.TexAlign.Depth.Width = 4; // See usage for 16bpp HALIGN_8 special-casing. Data.TexAlign.Depth.Height = 4; Data.TexAlign.Depth_D16_UNORM_1x_4x_16x.Width = 8; Data.TexAlign.Depth_D16_UNORM_1x_4x_16x.Height = Data.TexAlign.Depth.Height; Data.TexAlign.Depth_D16_UNORM_2x_8x.Width = 8; Data.TexAlign.Depth_D16_UNORM_2x_8x.Height = Data.TexAlign.Depth.Height; Data.TexAlign.SeparateStencil.Width = 8; Data.TexAlign.SeparateStencil.Height = 8; Data.TexAlign.YUV422.Width = 4; Data.TexAlign.YUV422.Height = 4; Data.TexAlign.AllOther.Width = 16; // HALIGN_16 required for non-MSAA RT's for CCS Fast-Clear and...TBA Data.TexAlign.AllOther.Height = 4; // VALIGN_4 should be sufficent. Data.TexAlign.XAdapter.Height = D3DKMT_CROSS_ADAPTER_RESOURCE_HEIGHT_ALIGNMENT; Data.TexAlign.XAdapter.Width = 1; //minimum should be one. // ---------------------------------- // SURFACE_STATE YOffset Granularity // ---------------------------------- Data.SurfaceStateYOffsetGranularity = 4; Data.SamplerFetchGranularityHeight = 4; Data.SamplerFetchGranularityWidth = 4; // ---------------------------------- // Restrictions for Cross adapter resource // ---------------------------------- Data.XAdapter.Alignment = GMM_KBYTE(64); //64KB for DX12/StdSwizzle--Not worth special-casing. Data.XAdapter.PitchAlignment = GMM_BYTES(D3DKMT_CROSS_ADAPTER_RESOURCE_PITCH_ALIGNMENT); Data.XAdapter.RenderPitchAlignment = GMM_BYTES(D3DKMT_CROSS_ADAPTER_RESOURCE_PITCH_ALIGNMENT); Data.XAdapter.LockPitchAlignment = GMM_BYTES(D3DKMT_CROSS_ADAPTER_RESOURCE_PITCH_ALIGNMENT); Data.XAdapter.MinPitch = GMM_BYTES(32); Data.XAdapter.MaxPitch = (pGmmLibContext->GetWaTable().WaRestrictPitch128KB) ? GMM_KBYTE(128) : GMM_KBYTE(256); Data.XAdapter.MinAllocationSize = PAGE_SIZE; Data.XAdapter.MinHeight = GMM_SCANLINES(1); Data.XAdapter.MinWidth = GMM_PIXELS(1); Data.XAdapter.MinDepth = 0; Data.XAdapter.MaxHeight = GMM_KBYTE(16); Data.XAdapter.MaxWidth = GMM_KBYTE(16); Data.XAdapter.MaxDepth = GMM_FIELD_NA; Data.XAdapter.MaxArraySize = GMM_KBYTE(2); //--------------------------------------------- //MaxSize for any surface type //--------------------------------------------- Data.SurfaceMaxSize = GMM_GBYTE(256); Data.MaxGpuVirtualAddressBitsPerResource = 38; if(GFX_IS_PRODUCT(Data.Platform, IGFX_KABYLAKE) || GFX_IS_PRODUCT(Data.Platform, IGFX_COFFEELAKE)) { Data.MaxSLMSize = GMM_KBYTE(960); } else { Data.MaxSLMSize = GMM_KBYTE(576); } Data.HiZPixelsPerByte = 2; Data.ReconMaxHeight = Data.Texture2DSurface.MaxHeight; // Reconstructed surfaces require more height and width for higher resolutions. Data.ReconMaxWidth = Data.Texture2DSurface.MaxWidth; Data.NoOfBitsSupported = 39; Data.HighestAcceptablePhysicalAddress = GFX_MASK_LARGE(0, 38); } gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/Platform/GmmPlatform.cpp000066400000000000000000000244521466655022700245770ustar00rootroot00000000000000/*============================================================================== Copyright(c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ============================================================================*/ #include "Internal/Common/GmmLibInc.h" GmmLib::PlatformInfo::PlatformInfo(PLATFORM &Platform, Context *pGmmLibContext) { GMM_DPF_ENTER; memset(&Data, 0, sizeof(Data)); Data.Platform = Platform; this->pGmmLibContext = pGmmLibContext; GMM_RESOURCE_FORMAT GmmFormat; #define GMM_FORMAT_GEN(X) (GFX_GET_CURRENT_RENDERCORE(Data.Platform) >= IGFX_GEN##X##_CORE) #define GMM_FORMAT_SKU(FtrXxx) (pGmmLibContext->GetSkuTable().FtrXxx != 0) #define GMM_FORMAT_WA(WaXxx) (pGmmLibContext->GetWaTable().WaXxx != 0) #define GMM_FORMAT(Name, bpe, _Width, _Height, _Depth, IsRT, IsASTC, RcsSurfaceFormat, SSCompressionFmt, Availability) \ \ { \ GmmFormat = GMM_FORMAT_##Name; \ Data.FormatTable[GmmFormat].ASTC = (IsASTC); \ Data.FormatTable[GmmFormat].Element.BitsPer = (bpe); \ Data.FormatTable[GmmFormat].Element.Depth = (_Depth); \ Data.FormatTable[GmmFormat].Element.Height = (_Height); \ Data.FormatTable[GmmFormat].Element.Width = (_Width); \ Data.FormatTable[GmmFormat].RenderTarget = ((IsRT) != 0); \ Data.FormatTable[GmmFormat].SurfaceStateFormat = ((GMM_SURFACESTATE_FORMAT)(RcsSurfaceFormat)); \ Data.FormatTable[GmmFormat].CompressionFormat.CompressionFormat = (SSCompressionFmt); \ Data.FormatTable[GmmFormat].Supported = ((Availability) != 0); \ if(((_Depth) > 1) || ((_Height) > 1) || ((_Width) > 1)) \ { \ Data.FormatTable[GmmFormat].Compressed = 1; \ } \ } #include "External/Common/GmmFormatTable.h" } ///////////////////////////////////////////////////////////////////////////////////// /// Copies parameters or sets flags based on info sent by the client. /// /// @param[in] CreateParams: Flags which specify what sort of resource to create ///////////////////////////////////////////////////////////////////////////////////// void GmmLib::PlatformInfo::SetCCSFlag(GMM_RESOURCE_FLAG &Flags) { if(Flags.Gpu.MCS) { Flags.Gpu.CCS = Flags.Gpu.MCS; } Flags.Info.RenderCompressed = Flags.Info.MediaCompressed = 0; Flags.Info.NotCompressed = 1; } ///////////////////////////////////////////////////////////////////////////////////// /// Validates the MMC parameters passed in by clients to make sure they do not /// conflict or ask for unsupporting combinations/features. /// /// @param[in] GMM_TEXTURE_INFO which specify what sort of resource to create /// @return 1 is validation passed. 0 otherwise. ///////////////////////////////////////////////////////////////////////////////////// uint8_t GmmLib::PlatformInfo::ValidateMMC(GMM_TEXTURE_INFO &Surf) { if(Surf.Flags.Gpu.MMC && //For Media Memory Compression -- ((!(GMM_IS_4KB_TILE(Surf.Flags) || GMM_IS_64KB_TILE(Surf.Flags))) || Surf.ArraySize > GMM_MAX_MMC_INDEX)) { return 0; } return 1; } ///////////////////////////////////////////////////////////////////////////////////// /// Validates the parameters passed in by clients to make sure they do not /// conflict or ask for unsupporting combinations/features. /// /// @param[in] GMM_TEXTURE_INFO which specify what sort of resource to create /// @return 1 is validation passed. 0 otherwise. ///////////////////////////////////////////////////////////////////////////////////// uint8_t GmmLib::PlatformInfo::ValidateCCS(GMM_TEXTURE_INFO &Surf) { if(!( //--- Legitimate CCS Case ---------------------------------------- ((Surf.Type >= RESOURCE_2D && Surf.Type <= RESOURCE_BUFFER) && //Not supported: 1D; Supported: Buffer, 2D, 3D, cube, Arrays, mip-maps, MSAA, Depth/Stencil (Surf.Type <= RESOURCE_CUBE)) || (Surf.Type == RESOURCE_2D && Surf.MaxLod == 0))) { GMM_ASSERTDPF(0, "Invalid CCS usage!"); return 0; } if(Surf.Flags.Info.RenderCompressed && Surf.Flags.Info.MediaCompressed) { GMM_ASSERTDPF(0, "Invalid CCS usage - can't be both RC and MC!"); return 0; } return 1; } ///////////////////////////////////////////////////////////////////////////////////// /// Validates the UnifiedAuxSurface parameters passed in by clients to make sure they do not /// conflict or ask for unsupporting combinations/features. /// /// @param[in] GMM_TEXTURE_INFO which specify what sort of resource to create /// @return 1 is validation passed. 0 otherwise. ///////////////////////////////////////////////////////////////////////////////////// uint8_t GmmLib::PlatformInfo::ValidateUnifiedAuxSurface(GMM_TEXTURE_INFO &Surf) { if((Surf.Flags.Gpu.UnifiedAuxSurface) && !( //--- Legitimate UnifiedAuxSurface Case ------------------------------------------ Surf.Flags.Gpu.CCS && (Surf.MSAA.NumSamples <= 1 && (Surf.Flags.Gpu.RenderTarget || Surf.Flags.Gpu.Texture)))) { GMM_ASSERTDPF(0, "Invalid UnifiedAuxSurface usage!"); return 0; } return 1; } //============================================================================= // // Function: CheckFmtDisplayDecompressible // // Desc: Returns true if display hw supports lossless render/media decompression // else returns false. // Umds can call it to decide if full resolve is required // // Parameters: // See function arguments. // // Returns: // uint8_t //----------------------------------------------------------------------------- uint8_t GmmLib::PlatformInfo::CheckFmtDisplayDecompressible(GMM_TEXTURE_INFO &Surf, bool IsSupportedRGB64_16_16_16_16, bool IsSupportedRGB32_8_8_8_8, bool IsSupportedRGB32_2_10_10_10, bool IsSupportedMediaFormats) { bool IsRenderCompressed = false; GMM_UNREFERENCED_PARAMETER(IsSupportedMediaFormats); GMM_UNREFERENCED_PARAMETER(IsSupportedRGB64_16_16_16_16); GMM_UNREFERENCED_PARAMETER(Surf); if(IsSupportedRGB32_8_8_8_8 || //RGB32 8 : 8 : 8 : 8 (GFX_GET_CURRENT_DISPLAYCORE(pGmmLibContext->GetPlatformInfo().Platform) >= IGFX_GEN10_CORE && IsSupportedRGB32_2_10_10_10)) //RGB32 2 : 10 : 10 : 10)) { IsRenderCompressed = true; } return IsRenderCompressed; } ///////////////////////////////////////////////////////////////////////////////////// /// C wrapper to get platform info data pointer (non-override platform info) /// /// @return Pointer to platform info data ///////////////////////////////////////////////////////////////////////////////////// const GMM_PLATFORM_INFO *GMM_STDCALL __GmmGetPlatformInfo(void *pLibContext) { GMM_LIB_CONTEXT *pGmmLibContext = (GMM_LIB_CONTEXT *)pLibContext; __GMM_ASSERTPTR(pGmmLibContext, NULL) if(pGmmLibContext->GetPlatformInfoObj() != NULL) { return (const GMM_PLATFORM_INFO *)(&(pGmmLibContext->GetPlatformInfo())); } return NULL; } ///////////////////////////////////////////////////////////////////////////////////// /// @param[in] Number: Number of Fence Registers ///////////////////////////////////////////////////////////////////////////////////// void GMM_STDCALL __SetNumberFenceRegisters(void *pLibContext, uint32_t Number) { GMM_LIB_CONTEXT *pGmmLibContext = (GMM_LIB_CONTEXT *)pLibContext; __GMM_ASSERT(pGmmLibContext != NULL) if(pGmmLibContext != NULL && pGmmLibContext->GetPlatformInfoObj() != NULL) { pGmmLibContext->GetPlatformInfoObj()->SetDataNumberFenceRegisters(Number); } } uint32_t GMM_STDCALL GmmPlatformGetBppFromGmmResourceFormat(void *pLibContext, GMM_RESOURCE_FORMAT Format) { GMM_LIB_CONTEXT *pGmmLibContext = (GMM_LIB_CONTEXT *)pLibContext; __GMM_ASSERT((Format > GMM_FORMAT_INVALID) && (Format < GMM_RESOURCE_FORMATS)); __GMM_ASSERT(pGmmLibContext); __GMM_ASSERT(pGmmLibContext->GetPlatformInfo().FormatTable[Format].Element.BitsPer >> 3); return pGmmLibContext->GetPlatformInfo().FormatTable[Format].Element.BitsPer; } gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/Platform/GmmPlatforms.h000066400000000000000000000114571466655022700244300ustar00rootroot00000000000000/*============================================================================== Copyright(c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ============================================================================*/ #pragma once #ifdef __cplusplus #include "../inc/External/Common/GmmMemAllocator.hpp" #include "../inc/External/Common/GmmTextureExt.h" namespace GmmLib { class Context; class NON_PAGED_SECTION PlatformInfo : public GmmMemAllocator { public: static int32_t RefCount; static int32_t OverrideRefCount; protected: GMM_PLATFORM_INFO Data; Context * pGmmLibContext; public: PlatformInfo(PLATFORM &Platform, Context* pGmmLibContext); virtual ~PlatformInfo() { } const GMM_PLATFORM_INFO& GetData() { return Data; } virtual void ApplyExtendedTexAlign(uint32_t CCSMode, ALIGNMENT& UnitAlign) { GMM_UNREFERENCED_PARAMETER(CCSMode); GMM_UNREFERENCED_PARAMETER(UnitAlign); } virtual uint8_t OverrideCompressionFormat(GMM_RESOURCE_FORMAT Format, uint8_t IsMC) { GMM_UNREFERENCED_PARAMETER(Format); GMM_UNREFERENCED_PARAMETER(IsMC); return 0; } void SetDataSurfaceMaxSize(uint64_t Size) { Data.SurfaceMaxSize = Size; } void SetDataFBCRequiredStolenMemorySize(uint32_t Size) { Data.FBCRequiredStolenMemorySize = Size; } void SetDataNumberFenceRegisters(uint32_t Number) { Data.NumberFenceRegisters = Number; } virtual void SetCCSFlag(GMM_RESOURCE_FLAG &Flags); virtual uint8_t ValidateMMC(GMM_TEXTURE_INFO &Surf); virtual uint8_t ValidateCCS(GMM_TEXTURE_INFO &Surf); virtual uint8_t ValidateUnifiedAuxSurface(GMM_TEXTURE_INFO &Surf); virtual uint8_t CheckFmtDisplayDecompressible(GMM_TEXTURE_INFO &Surf, bool IsSupportedRGB64_16_16_16_16, bool IsSupportedRGB32_8_8_8_8, bool IsSupportedRGB32_2_10_10_10, bool IsSupportedMediaFormats); }; } #define GMM_PLATFORM_INFO_CLASS GmmLib::PlatformInfo #else typedef struct PlatformInfo PlatformInfo; #define GMM_PLATFORM_INFO_CLASS PlatformInfo #endif //*************************************************************************** // // GMM_PLATFORM_INFO Internl API // //*************************************************************************** #define SET_TILE_MODE_INFO(Mode, _Width, _Height, _Depth, _MtsWidth, _MtsHeight, _MtsDepth) \ { \ Data.TileInfo[Mode].LogicalTileWidth = GMM_BYTES(_Width); \ Data.TileInfo[Mode].LogicalTileHeight = GMM_SCANLINES(_Height); \ Data.TileInfo[Mode].LogicalTileDepth = (_Depth); \ Data.TileInfo[Mode].LogicalSize = (_Width) * (_Height) * (_Depth); \ Data.TileInfo[Mode].MaxPitch = GMM_KBYTE(256); \ Data.TileInfo[Mode].MaxMipTailStartWidth = (_MtsWidth); \ Data.TileInfo[Mode].MaxMipTailStartHeight = (_MtsHeight); \ Data.TileInfo[Mode].MaxMipTailStartDepth = (_MtsDepth); \ } #if __cplusplus extern "C" { #endif const GMM_PLATFORM_INFO *GMM_STDCALL __GmmGetPlatformInfo(void *pLibContext); void GMM_STDCALL __SetNumberFenceRegisters(void *pLibContext, uint32_t Number); #if __cplusplus } #endif gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/Resource/000077500000000000000000000000001466655022700216425ustar00rootroot00000000000000gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/Resource/GmmResourceInfo.cpp000066400000000000000000002260231466655022700254170ustar00rootroot00000000000000/*============================================================================== Copyright(c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ============================================================================*/ #include "Internal/Common/GmmLibInc.h" #include ///////////////////////////////////////////////////////////////////////////////////// /// C wrapper for GmmResourceInfoCommon::Create. /// @see GmmLib::GmmResourceInfoCommon::Create() /// /// @param[in] pCreateParams: Flags which specify what sort of resource to create /// @return Pointer to GmmResourceInfo class. ///////////////////////////////////////////////////////////////////////////////////// GMM_RESOURCE_INFO *GMM_STDCALL GmmResCreate(GMM_RESCREATE_PARAMS *pCreateParams, GMM_LIB_CONTEXT *pLibContext) { GMM_RESOURCE_INFO *pRes = NULL; #if(!defined(__GMM_KMD__) && !defined(GMM_UNIFIED_LIB)) pRes = GmmResCreateThroughClientCtxt(pCreateParams); return pRes; #else // GMM_RESOURCE_INFO... if(pCreateParams->pPreallocatedResInfo) { pRes = new(pCreateParams->pPreallocatedResInfo) GmmLib::GmmResourceInfo(); // Use preallocated memory as a class pCreateParams->Flags.Info.__PreallocatedResInfo = pRes->GetResFlags().Info.__PreallocatedResInfo = 1; // Set both in case we can die before copying over the flags. } else { if((pRes = new GMM_RESOURCE_INFO) == NULL) { GMM_ASSERTDPF(0, "Allocation failed!"); goto ERROR_CASE; } } if(pRes->Create(*pLibContext, *pCreateParams) != GMM_SUCCESS) { goto ERROR_CASE; } return (pRes); ERROR_CASE: if(pRes) { GmmResFree(pRes); } GMM_DPF_EXIT; return (NULL); #endif } ///////////////////////////////////////////////////////////////////////////////////// /// C wrapper for GmmResourceInfoCommon::opeartor=. Allocates a new class and /// returns a pointer to it. The new class must be free'd explicitly by the client. /// /// @see GmmLib::GmmResourceInfoCommon::operator=() /// /// @param[in] pRes: Pointer to the GmmResourceInfo class that needs to be copied /// @return Pointer to newly copied GmmResourceInfo class ///////////////////////////////////////////////////////////////////////////////////// GMM_RESOURCE_INFO *GMM_STDCALL GmmResCopy(GMM_RESOURCE_INFO *pRes) { GMM_RESOURCE_INFO *pResCopy = NULL; GMM_DPF_ENTER; __GMM_ASSERTPTR(pRes, NULL); #if(!defined(__GMM_KMD__) && !defined(GMM_UNIFIED_LIB)) pResCopy = GmmResCopyThroughClientCtxt(pRes); return pResCopy; #else pResCopy = new GMM_RESOURCE_INFO; if(!pResCopy) { GMM_ASSERTDPF(0, "Allocation failed."); return NULL; } *pResCopy = *pRes; // We are allocating new class, flag must be false to avoid leak at DestroyResource pResCopy->GetResFlags().Info.__PreallocatedResInfo = 0; GMM_DPF_EXIT; return (pResCopy); #endif } ///////////////////////////////////////////////////////////////////////////////////// /// Helps clients copy one GmmResourceInfo object to another /// /// @param[in] pDst: Pointer to memory when pSrc will be copied. /// @param[in] pSrc: Pointer to GmmResourceInfo class that needs to be copied ///////////////////////////////////////////////////////////////////////////////////// void GMM_STDCALL GmmResMemcpy(void *pDst, void *pSrc) { #if(!defined(__GMM_KMD__) && !defined(GMM_UNIFIED_LIB)) GmmResMemcpyThroughClientCtxt(pDst, pSrc); #else GMM_RESOURCE_INFO *pResSrc = reinterpret_cast(pSrc); // Init memory correctly, in case the pointer is a raw memory pointer GMM_RESOURCE_INFO *pResDst = new(pDst) GMM_RESOURCE_INFO(); *pResDst = *pResSrc; #endif } ///////////////////////////////////////////////////////////////////////////////////// /// C wrapper for ~GmmResourceInfoCommon. Frees the resource if it wasn't part of /// ::GMM_RESCREATE_PARAMS::pPreallocatedResInfo. /// @see GmmLib::GmmResourceInfoCommon::~GmmResourceInfoCommon() /// /// @param[in] pRes: Pointer to the GmmResourceInfo class that needs to be freed ///////////////////////////////////////////////////////////////////////////////////// void GMM_STDCALL GmmResFree(GMM_RESOURCE_INFO *pRes) { GMM_DPF_ENTER; __GMM_ASSERTPTR(pRes, VOIDRETURN); #if(!defined(__GMM_KMD__) && !defined(GMM_UNIFIED_LIB)) GmmResFreeThroughClientCtxt(pRes); #else if(pRes->GetResFlags().Info.__PreallocatedResInfo) { *pRes = GmmLib::GmmResourceInfo(); } else { delete pRes; pRes = NULL; } #endif } ///////////////////////////////////////////////////////////////////////////////////// /// C wrapper for GmmLib::GmmResourceInfoCommon::GetSystemMemPointer. /// @see GmmLib::GmmResourceInfoCommon::GetSystemMemPointer() /// /// @param[in] pRes: Pointer to the GmmResourceInfo class /// @param[in] IsD3DDdiAllocation: Specifies where allocation was made by a D3D client /// @return Pointer to system memory. NULL if not available. ///////////////////////////////////////////////////////////////////////////////////// void *GMM_STDCALL GmmResGetSystemMemPointer(GMM_RESOURCE_INFO *pRes, uint8_t IsD3DDdiAllocation) { GMM_DPF_ENTER; __GMM_ASSERTPTR(pRes, NULL); return pRes->GetSystemMemPointer(IsD3DDdiAllocation); } ///////////////////////////////////////////////////////////////////////////////////// /// C wrapper for GmmLib::GmmResourceInfoCommon::GetSystemMemSize. /// @see GmmLib::GmmResourceInfoCommon::GetSystemMemSize() /// /// @param[in] pRes: Pointer to the GmmResourceInfo class /// @return Size of memory. ///////////////////////////////////////////////////////////////////////////////////// GMM_GFX_SIZE_T GMM_STDCALL GmmResGetSystemMemSize(GMM_RESOURCE_INFO *pRes) { __GMM_ASSERTPTR(pRes, ((GMM_GFX_SIZE_T)0)); return pRes->GetSystemMemSize(); } ///////////////////////////////////////////////////////////////////////////////////// /// This function returns size of GMM_RESOURCE_INFO /// /// @return size of class ///////////////////////////////////////////////////////////////////////////////////// uint32_t GMM_STDCALL GmmResGetSizeOfStruct(void) { return (sizeof(GMM_RESOURCE_INFO)); } ///////////////////////////////////////////////////////////////////////////////////// /// This function returns resource flags /// /// @param[in] pGmmResource: Pointer to the GmmResourceInfo class /// @param[out] pFlags: Memory where resource flags will be copied ///////////////////////////////////////////////////////////////////////////////////// void GMM_STDCALL GmmResGetFlags(GMM_RESOURCE_INFO *pGmmResource, GMM_RESOURCE_FLAG *pFlags /*output*/) { GMM_DPF_ENTER; __GMM_ASSERTPTR(pGmmResource, VOIDRETURN); __GMM_ASSERTPTR(pFlags, VOIDRETURN); *pFlags = GmmResGetResourceFlags(pGmmResource); GMM_DPF_EXIT; } ///////////////////////////////////////////////////////////////////////////////////// /// C wrapper for GmmLib::GmmResourceInfoCommon::GetResourceType. /// @see GmmLib::GmmResourceInfoCommon::GetResourceType() /// /// @param[in] pGmmResource: Pointer to the GmmResourceInfo class /// @return Resource Type ///////////////////////////////////////////////////////////////////////////////////// GMM_RESOURCE_TYPE GMM_STDCALL GmmResGetResourceType(GMM_RESOURCE_INFO *pGmmResource) { __GMM_ASSERTPTR(pGmmResource, RESOURCE_INVALID); return pGmmResource->GetResourceType(); } ///////////////////////////////////////////////////////////////////////////////////// /// C wrapper for GmmLib::GmmResourceInfoCommon::GetResourceFormat. /// @see GmmLib::GmmResourceInfoCommon::GetResourceFormat() /// /// @param[in] pGmmResource: Pointer to the GmmResourceInfo class /// @return Resource Format ///////////////////////////////////////////////////////////////////////////////////// GMM_RESOURCE_FORMAT GMM_STDCALL GmmResGetResourceFormat(GMM_RESOURCE_INFO *pGmmResource) { __GMM_ASSERTPTR(pGmmResource, GMM_FORMAT_INVALID); return pGmmResource->GetResourceFormat(); } ///////////////////////////////////////////////////////////////////////////////////// /// C wrapper for GmmLib::GmmResourceInfoCommon::GetPaddedWidth. /// @see GmmLib::GmmResourceInfoCommon::GetPaddedWidth() /// /// @param[in] pGmmResource: Pointer to the GmmResourceInfo class /// @param[in] MipLevel: Requested mip level /// @return Padded Width ///////////////////////////////////////////////////////////////////////////////////// uint32_t GMM_STDCALL GmmResGetPaddedWidth(GMM_RESOURCE_INFO *pGmmResource, uint32_t MipLevel) { __GMM_ASSERTPTR(pGmmResource, 0); return pGmmResource->GetPaddedWidth(MipLevel); } ///////////////////////////////////////////////////////////////////////////////////// /// C wrapper for GmmLib::GmmResourceInfoCommon::GetPaddedHeight. /// @see GmmLib::GmmResourceInfoCommon::GetPaddedHeight() /// /// @param[in] pGmmResource: Pointer to the GmmResourceInfo class /// @param[in] MipLevel: Requested mip level /// @return Padded Height ///////////////////////////////////////////////////////////////////////////////////// uint32_t GMM_STDCALL GmmResGetPaddedHeight(GMM_RESOURCE_INFO *pGmmResource, uint32_t MipLevel) { __GMM_ASSERTPTR(pGmmResource, 0); return pGmmResource->GetPaddedHeight(MipLevel); } ///////////////////////////////////////////////////////////////////////////////////// /// C wrapper for GmmLib::GmmResourceInfoCommon::GetPaddedPitch. /// @see GmmLib::GmmResourceInfoCommon::GetPaddedPitch() /// /// @param[in] pGmmResource: Pointer to the GmmResourceInfo class /// @param[in] MipLevel: Requested mip level /// @return Padded Pitch ///////////////////////////////////////////////////////////////////////////////////// uint32_t GMM_STDCALL GmmResGetPaddedPitch(GMM_RESOURCE_INFO *pGmmResource, uint32_t MipLevel) { __GMM_ASSERTPTR(pGmmResource, 0); return pGmmResource->GetPaddedPitch(MipLevel); } ///////////////////////////////////////////////////////////////////////////////////// /// C wrapper for GmmLib::GmmResourceInfoCommon::GetBaseWidth. Truncates width to /// 32-bit. /// @see GmmLib::GmmResourceInfoCommon::GetBaseWidth() /// /// @param[in] pGmmResource: Pointer to the GmmResourceInfo class /// @return Width ///////////////////////////////////////////////////////////////////////////////////// uint32_t GMM_STDCALL GmmResGetBaseWidth(GMM_RESOURCE_INFO *pGmmResource) { __GMM_ASSERTPTR(pGmmResource, 0); return GFX_ULONG_CAST(pGmmResource->GetBaseWidth()); } ///////////////////////////////////////////////////////////////////////////////////// /// C wrapper for GmmLib::GmmResourceInfoCommon::GetBaseWidth. /// @see GmmLib::GmmResourceInfoCommon::GetBaseWidth() /// /// @param[in] pGmmResource: Pointer to the GmmResourceInfo class /// @return Width ///////////////////////////////////////////////////////////////////////////////////// GMM_GFX_SIZE_T GMM_STDCALL GmmResGetBaseWidth64(GMM_RESOURCE_INFO *pGmmResource) { __GMM_ASSERTPTR(pGmmResource, 0); return pGmmResource->GetBaseWidth(); } ///////////////////////////////////////////////////////////////////////////////////// /// C wrapper for GmmLib::GmmResourceInfoCommon::GetBaseAlignment. /// @see GmmLib::GmmResourceInfoCommon::GetBaseAlignment() /// /// @param[in] pGmmResource: Pointer to the GmmResourceInfo class /// @return Base Alignment ///////////////////////////////////////////////////////////////////////////////////// uint32_t GMM_STDCALL GmmResGetBaseAlignment(GMM_RESOURCE_INFO *pGmmResource) { __GMM_ASSERTPTR(pGmmResource, 0); return pGmmResource->GetBaseAlignment(); } ///////////////////////////////////////////////////////////////////////////////////// /// C wrapper for GmmLib::GmmResourceInfoCommon::GetBaseHeight. /// @see GmmLib::GmmResourceInfoCommon::GetBaseHeight() /// /// @param[in] pGmmResource: Pointer to the GmmResourceInfo class /// @return Height ///////////////////////////////////////////////////////////////////////////////////// uint32_t GMM_STDCALL GmmResGetBaseHeight(GMM_RESOURCE_INFO *pGmmResource) { __GMM_ASSERTPTR(pGmmResource, 0); return pGmmResource->GetBaseHeight(); } ///////////////////////////////////////////////////////////////////////////////////// /// C wrapper for GmmLib::GmmResourceInfoCommon::GmmResGetDepth. /// @see GmmLib::GmmResourceInfoCommon::GmmResGetDepth() /// /// @param[in] pGmmResource: Pointer to the GmmResourceInfo class /// @return Depth ///////////////////////////////////////////////////////////////////////////////////// uint32_t GMM_STDCALL GmmResGetDepth(GMM_RESOURCE_INFO *pGmmResource) { __GMM_ASSERTPTR(pGmmResource, 0); return pGmmResource->GetBaseDepth(); } ///////////////////////////////////////////////////////////////////////////////////// /// C wrapper for GmmLib::GmmResourceInfoCommon::GetMaxLod. /// @see GmmLib::GmmResourceInfoCommon::GetMaxLod() /// /// @param[in] pGmmResource: Pointer to the GmmResourceInfo class /// @return Max Lod ///////////////////////////////////////////////////////////////////////////////////// uint32_t GMM_STDCALL GmmResGetMaxLod(GMM_RESOURCE_INFO *pGmmResource) { __GMM_ASSERTPTR(pGmmResource, 0); return pGmmResource->GetMaxLod(); } ///////////////////////////////////////////////////////////////////////////////////// /// C wrapper for GmmLib::GmmResourceInfoCommon::GetMipTailStartLod.SurfaceState /// @see GmmLib::GmmResourceInfoCommon::GetMipTailStartLodSurfaceState() /// /// @param[in] pGmmResource: Pointer to the GmmResourceInfo class /// @return Mip Tail Starts ///////////////////////////////////////////////////////////////////////////////////// uint32_t GMM_STDCALL GmmResGetSurfaceStateMipTailStartLod(GMM_RESOURCE_INFO *pGmmResource) { __GMM_ASSERT(pGmmResource); return pGmmResource->GetMipTailStartLodSurfaceState(); } ///////////////////////////////////////////////////////////////////////////////////// /// C wrapper for GmmLib::GmmResourceInfoCommon::GetTileAddressMappingMode.SurfaceState /// @see GmmLib::GmmResourceInfoCommon::GetTileAddressMappingModeSurfaceState() /// /// @param[in] pGmmResource: Pointer to the GmmResourceInfo class /// @return Tile Address Mapping Mode ///////////////////////////////////////////////////////////////////////////////////// uint32_t GMM_STDCALL GmmResGetSurfaceStateTileAddressMappingMode(GMM_RESOURCE_INFO *pGmmResource) { __GMM_ASSERT(pGmmResource); return pGmmResource->GetTileAddressMappingModeSurfaceState(); } ///////////////////////////////////////////////////////////////////////////////////// /// C wrapper for GmmLib::GmmResourceInfoCommon::GetStdTilingModeExt.SurfaceState /// @see GmmLib::GmmResourceInfoCommon::GetStdTilingModeExtSurfaceState() /// /// @param[in] pGmmResource: Pointer to the GmmResourceInfo class /// @return Std Tiling Mode Ext ///////////////////////////////////////////////////////////////////////////////////// uint32_t GMM_STDCALL GmmResGetSurfaceStateStdTilingModeExt(GMM_RESOURCE_INFO *pGmmResource) { __GMM_ASSERTPTR(pGmmResource, GMM_INVALIDPARAM); return pGmmResource->GetStdTilingModeExtSurfaceState(); } ///////////////////////////////////////////////////////////////////////////////////// /// C wrapper for GmmLib::GmmResourceInfoCommon::GetArraySize. /// @see GmmLib::GmmResourceInfoCommon::GetArraySize() /// /// @param[in] pGmmResource: Pointer to the GmmResourceInfo class /// @return Array Size ///////////////////////////////////////////////////////////////////////////////////// uint32_t GMM_STDCALL GmmResGetArraySize(GMM_RESOURCE_INFO *pGmmResource) { __GMM_ASSERTPTR(pGmmResource, 0); return pGmmResource->GetArraySize(); } #if(LHDM) ///////////////////////////////////////////////////////////////////////////////////// /// C wrapper for GmmLib::GmmResourceInfoCommon::GetRefreshRate. /// @see GmmLib::GmmResourceInfoCommon::GetRefreshRate() /// /// @param[in] pGmmResource: Pointer to the GmmResourceInfo class /// @return Refresh rate ///////////////////////////////////////////////////////////////////////////////////// D3DDDI_RATIONAL GMM_STDCALL GmmResGetRefreshRate(GMM_RESOURCE_INFO *pGmmResource) { D3DDDI_RATIONAL RetVal = {0}; __GMM_ASSERTPTR(pGmmResource, RetVal); return pGmmResource->GetRefreshRate(); } #endif // LHDM #if(LHDM) ///////////////////////////////////////////////////////////////////////////////////// /// C wrapper for GmmLib::GmmResourceInfoWin::GetD3d9Flags. /// @see GmmLib::GmmResourceInfoWin::GetD3d9Flags() /// /// @param[in] pGmmResource: Pointer to the GmmResourceInfo class /// @param[out] pD3d9Flags: Mscaps data is copied to this param ///////////////////////////////////////////////////////////////////////////////////// void GMM_STDCALL GmmResGetD3d9Flags(GMM_RESOURCE_INFO * pGmmResource, D3DDDI_RESOURCEFLAGS *pD3d9Flags) { __GMM_ASSERTPTR(pGmmResource, VOIDRETURN); __GMM_ASSERTPTR(pD3d9Flags, VOIDRETURN); *pD3d9Flags = pGmmResource->GetD3d9Flags(); } ///////////////////////////////////////////////////////////////////////////////////// /// C wrapper for GmmLib::GmmResourceInfoWin::GetD3d9Format. /// @see GmmLib::GmmResourceInfoWin::GetD3d9Format() /// /// @param[in] pGmmResource: Pointer to the GmmResourceInfo class /// @return D3d9 format for the resource ///////////////////////////////////////////////////////////////////////////////////// D3DDDIFORMAT GMM_STDCALL GmmResGetD3d9Format(GMM_RESOURCE_INFO *pGmmResource) { __GMM_ASSERTPTR(pGmmResource, (D3DDDIFORMAT)0); return pGmmResource->GetD3d9Format(); } ///////////////////////////////////////////////////////////////////////////////////// /// C wrapper for GmmLib::GmmResourceInfoWin::GetVidSourceId. /// @see GmmLib::GmmResourceInfoWin::GetVidSourceId() /// /// @param[in] pGmmResource: Pointer to the GmmResourceInfo class /// @return Source Id ///////////////////////////////////////////////////////////////////////////////////// D3DDDI_VIDEO_PRESENT_SOURCE_ID GMM_STDCALL GmmResGetVidSourceId(GMM_RESOURCE_INFO *pGmmResource) { __GMM_ASSERTPTR(pGmmResource, 0); return pGmmResource->GetVidSourceId(); } #endif // LHDM ///////////////////////////////////////////////////////////////////////////////////// /// C wrapper for GmmLib::GmmResourceInfoWin::Is64KBPageSuitable. /// @see GmmLib::GmmResourceInfoWin::Is64KBPageSuitable() /// /// @param[in] pGmmResource: Pointer to the GmmResourceInfo class /// @return 1/0 ///////////////////////////////////////////////////////////////////////////////////// uint8_t GMM_STDCALL GmmResIs64KBPageSuitable(GMM_RESOURCE_INFO *pGmmResource) { __GMM_ASSERTPTR(pGmmResource, 0); return pGmmResource->Is64KBPageSuitable(); } ///////////////////////////////////////////////////////////////////////////////////// /// C wrapper for GmmLib::GmmResourceInfoCommon::GetRotateInfo. /// @see GmmLib::GmmResourceInfoCommon::GetRotateInfo() /// /// @param[in] pGmmResource: Pointer to the GmmResourceInfo class /// @return rotation info ///////////////////////////////////////////////////////////////////////////////////// uint32_t GMM_STDCALL GmmResGetRotateInfo(GMM_RESOURCE_INFO *pGmmResource) { __GMM_ASSERTPTR(pGmmResource, 0); return pGmmResource->GetRotateInfo(); } ///////////////////////////////////////////////////////////////////////////////////// /// C wrapper for GmmLib::GmmResourceInfoCommon::GetAuxQPitch. /// @see GmmLib::GmmResourceInfoCommon::GetAuxQPitch() /// /// @param[in] pGmmResource: Pointer to the GmmResourceInfo class /// @return Aux QPitch ///////////////////////////////////////////////////////////////////////////////////// uint32_t GMM_STDCALL GmmResGetAuxQPitch(GMM_RESOURCE_INFO *pGmmResource) { __GMM_ASSERTPTR(pGmmResource, 0); return pGmmResource->GetAuxQPitch(); } ///////////////////////////////////////////////////////////////////////////////////// /// C wrapper for GmmLib::GmmResourceInfoCommon::GetQPitch. /// @see GmmLib::GmmResourceInfoCommon::GetQPitch() /// /// @param[in] pGmmResource: Pointer to the GmmResourceInfo class /// @return QPitch ///////////////////////////////////////////////////////////////////////////////////// uint32_t GMM_STDCALL GmmResGetQPitch(GMM_RESOURCE_INFO *pGmmResource) { __GMM_ASSERTPTR(pGmmResource, 0); return pGmmResource->GetQPitch(); } ///////////////////////////////////////////////////////////////////////////////////// /// C wrapper for GmmLib::GmmResourceInfoCommon::GetQPitchPlanar. /// @see GmmLib::GmmResourceInfoCommon::GetQPitchPlanar() /// /// @param[in] pGmmResource: Pointer to the GmmResourceInfo class /// @return Planar QPitch ///////////////////////////////////////////////////////////////////////////////////// uint32_t GMM_STDCALL GmmResGetQPitchPlanar(GMM_RESOURCE_INFO *pGmmResource, GMM_YUV_PLANE Plane) { __GMM_ASSERTPTR(pGmmResource, 0); return pGmmResource->GetQPitchPlanar(Plane); } ///////////////////////////////////////////////////////////////////////////////////// /// C wrapper for GmmLib::GmmResourceInfoCommon::GetQPitchInBytes. /// @see GmmLib::GmmResourceInfoCommon::GetQPitchInBytes() /// /// @param[in] pGmmResource: Pointer to the GmmResourceInfo class /// @return QPitch ///////////////////////////////////////////////////////////////////////////////////// GMM_GFX_SIZE_T GMM_STDCALL GmmResGetQPitchInBytes(GMM_RESOURCE_INFO *pGmmResource) { __GMM_ASSERT(pGmmResource); return pGmmResource->GetQPitchInBytes(); } ///////////////////////////////////////////////////////////////////////////////////// /// C wrapper for GmmLib::GmmResourceInfoCommon::GetRenderPitch. /// @see GmmLib::GmmResourceInfoCommon::GetRenderPitch() /// /// @param[in] pGmmResource: Pointer to the GmmResourceInfo class /// @return Pitch ///////////////////////////////////////////////////////////////////////////////////// uint32_t GMM_STDCALL GmmResGetRenderPitch(GMM_RESOURCE_INFO *pGmmResource) { __GMM_ASSERTPTR(pGmmResource, 0); return GFX_ULONG_CAST(pGmmResource->GetRenderPitch()); } ///////////////////////////////////////////////////////////////////////////////////// /// C wrapper for GmmLib::GmmResourceInfoCommon::GetRenderPitchTiles. /// @see GmmLib::GmmResourceInfoCommon::GetRenderPitchTiles() /// /// @param[in] pGmmResource: Pointer to the GmmResourceInfo class /// @return Pitch in tiles ///////////////////////////////////////////////////////////////////////////////////// uint32_t GMM_STDCALL GmmResGetRenderPitchTiles(GMM_RESOURCE_INFO *pGmmResource) { __GMM_ASSERTPTR(pGmmResource, 0); return pGmmResource->GetRenderPitchTiles(); } ///////////////////////////////////////////////////////////////////////////////////// /// C wrapper for GmmLib::GmmResourceInfoCommon::GetRenderAuxPitchTiles. /// @see GmmLib::GmmResourceInfoCommon::GetRenderAuxPitchTiles() /// /// @param[in] pGmmResource: Pointer to the GmmResourceInfo class /// @return Aux Pitch in tiles ///////////////////////////////////////////////////////////////////////////////////// uint32_t GMM_STDCALL GmmResGetRenderAuxPitchTiles(GMM_RESOURCE_INFO *pGmmResource) { __GMM_ASSERTPTR(pGmmResource, 0); return pGmmResource->GetRenderAuxPitchTiles(); } ///////////////////////////////////////////////////////////////////////////////////// /// C wrapper for GmmLib::GmmResourceInfoCommon::GetUnifiedAuxPitch. /// @see GmmLib::GmmResourceInfoCommon::GetUnifiedAuxPitch() /// /// @param[in] pGmmResource: Pointer to the GmmResourceInfo class /// @return Aux Pitch ///////////////////////////////////////////////////////////////////////////////////// uint32_t GMM_STDCALL GmmResGetAuxPitch(GMM_RESOURCE_INFO *pGmmResource) { __GMM_ASSERTPTR(pGmmResource, 0); return GFX_ULONG_CAST(pGmmResource->GetUnifiedAuxPitch()); } ///////////////////////////////////////////////////////////////////////////////////// /// C wrapper for GmmLib::GmmResourceInfoCommon::GetBitsPerPixel. /// @see GmmLib::GmmResourceInfoCommon::GetBitsPerPixel() /// /// @param[in] pGmmResource: Pointer to the GmmResourceInfo class /// @return bpp ///////////////////////////////////////////////////////////////////////////////////// uint32_t GMM_STDCALL GmmResGetBitsPerPixel(GMM_RESOURCE_INFO *pGmmResource) { __GMM_ASSERTPTR(pGmmResource, 0); return pGmmResource->GetBitsPerPixel(); } ///////////////////////////////////////////////////////////////////////////////////// /// C wrapper for GmmLib::GmmResourceInfoCommon::GetUnifiedAuxBitsPerPixel. /// @see GmmLib::GmmResourceInfoCommon::GetUnifiedAuxBitsPerPixel() /// /// @param[in] pGmmResource: Pointer to the GmmResourceInfo class /// @return bpp ///////////////////////////////////////////////////////////////////////////////////// uint32_t GMM_STDCALL GmmResGetAuxBitsPerPixel(GMM_RESOURCE_INFO *pGmmResource) { __GMM_ASSERTPTR(pGmmResource, 0); return pGmmResource->GetUnifiedAuxBitsPerPixel(); } ///////////////////////////////////////////////////////////////////////////////////// /// C wrapper for GmmLib::GmmResourceInfoCommon::GetCompressionBlockXxx. /// @see GmmLib::GmmResourceInfoCommon::GetCompressionBlockWidth() /// @see GmmLib::GmmResourceInfoCommon::GetCompressionBlockHeight() /// @see GmmLib::GmmResourceInfoCommon::GetCompressionBlockDepth() /// /// @param[in] pRes: Pointer to the GmmResourceInfo class /// @return Compression Block Width/Height/Depth ///////////////////////////////////////////////////////////////////////////////////// #define GmmResGetCompressionBlockXxx(Xxx) \ uint32_t GMM_STDCALL GmmResGetCompressionBlock##Xxx(GMM_RESOURCE_INFO *pGmmResource) \ { \ __GMM_ASSERTPTR(pGmmResource, 1); \ return pGmmResource->GetCompressionBlock##Xxx(); \ } /////////////////////////////////////////////////////// GmmResGetCompressionBlockXxx(Width) GmmResGetCompressionBlockXxx(Height) GmmResGetCompressionBlockXxx(Depth) ///////////////////////////////////////////////////////////////////////////////////// /// C wrapper for GmmLib::GmmResourceInfoCommon::GetUnifiedAuxBitsPerPixel. /// @see GmmLib::GmmResourceInfoCommon::GetUnifiedAuxBitsPerPixel() /// /// @param[in] pGmmResource: Pointer to the GmmResourceInfo class /// @param[in][out] pReqInfo: Has info about which offset client is requesting. Offset is also /// passed back to the client in this parameter. /// @return ::GMM_STATUS ///////////////////////////////////////////////////////////////////////////////////// GMM_STATUS GMM_STDCALL GmmResGetOffset(GMM_RESOURCE_INFO * pGmmResource, GMM_REQ_OFFSET_INFO *pReqInfo) { __GMM_ASSERTPTR(pGmmResource, GMM_ERROR); __GMM_ASSERTPTR(pReqInfo, GMM_ERROR); return pGmmResource->GetOffset(*pReqInfo); } ///////////////////////////////////////////////////////////////////////////////////// /// C wrapper for GmmLib::GmmResourceInfoCommon::GetTextureLayout. /// @see GmmLib::GmmResourceInfoCommon::GetTextureLayout() /// /// @param[in] pGmmResource: Pointer to the GmmResourceInfo class /// @return GMM_2D_LAYOUT_RIGHT or GMM_2D_LAYOUT_BELOW ///////////////////////////////////////////////////////////////////////////////////// GMM_TEXTURE_LAYOUT GMM_STDCALL GmmResGetTextureLayout(GMM_RESOURCE_INFO *pGmmResource) { __GMM_ASSERT(pGmmResource); return pGmmResource->GetTextureLayout(); } ///////////////////////////////////////////////////////////////////////////////////// /// C wrapper for GmmLib::GmmResourceInfoCommon::GetTileType. /// @see GmmLib::GmmResourceInfoCommon::GetTileType() /// /// @param[in] pGmmResource: Pointer to the GmmResourceInfo class /// @return ::GMM_TILE_TYPE ///////////////////////////////////////////////////////////////////////////////////// GMM_TILE_TYPE GMM_STDCALL GmmResGetTileType(GMM_RESOURCE_INFO *pGmmResource) { __GMM_ASSERT(pGmmResource); return pGmmResource->GetTileType(); } ///////////////////////////////////////////////////////////////////////////////////// /// C wrapper for GmmLib::GmmResourceInfoCommon::GetMipHeight. /// @see GmmLib::GmmResourceInfoCommon::GetMipHeight() /// /// @param[in] pResourceInfo: Pointer to the GmmResourceInfo class /// @param[in] MipLevel: Mip level for which the info is needed /// @return Mip Height ///////////////////////////////////////////////////////////////////////////////////// uint32_t GMM_STDCALL GmmResGetMipHeight(GMM_RESOURCE_INFO *pResourceInfo, uint32_t MipLevel) { return pResourceInfo->GetMipHeight(MipLevel); } ///////////////////////////////////////////////////////////////////////////////////// /// C wrapper for GmmLib::GmmResourceInfoCommon::GetMipWidth. /// @see GmmLib::GmmResourceInfoCommon::GetMipWidth() /// /// @param[in] pResourceInfo: Pointer to the GmmResourceInfo class /// @param[in] MipLevel: Mip level for which the info is needed /// @return Mip Width ///////////////////////////////////////////////////////////////////////////////////// GMM_GFX_SIZE_T GMM_STDCALL GmmResGetMipWidth(GMM_RESOURCE_INFO *pResourceInfo, uint32_t MipLevel) { return pResourceInfo->GetMipWidth(MipLevel); } ///////////////////////////////////////////////////////////////////////////////////// /// C wrapper for GmmLib::GmmResourceInfoCommon::GetMipDepth. /// @see GmmLib::GmmResourceInfoCommon::GetMipDepth() /// /// @param[in] pResourceInfo: Pointer to the GmmResourceInfo class /// @param[in] MipLevel: Mip level for which the info is needed /// @return Mip Depth ///////////////////////////////////////////////////////////////////////////////////// uint32_t GMM_STDCALL GmmResGetMipDepth(GMM_RESOURCE_INFO *pResourceInfo, uint32_t MipLevel) { return pResourceInfo->GetMipDepth(MipLevel); } //============================================================================= // // Function:GmmResGetCornerTexelMode // // Desc: // Simple getter function to return the Corner Texel Mode of a surface. // // Parameters: // pGmmResource: ==> A previously allocated resource. // // Returns: // CornerTexelMode flag ==> uint8_t //----------------------------------------------------------------------------- uint8_t GMM_STDCALL GmmResGetCornerTexelMode(GMM_RESOURCE_INFO *pGmmResource) { GMM_DPF_ENTER; __GMM_ASSERT(pGmmResource); return ((pGmmResource->GetResFlags().Info.CornerTexelMode) ? 1 : 0); } ///////////////////////////////////////////////////////////////////////////////////// /// C wrapper for GmmLib::GmmResourceInfoCommon::GetCpuCacheType. /// @see GmmLib::GmmResourceInfoCommon::GetCpuCacheType() /// /// @param[in] pGmmResource: Pointer to the GmmResourceInfo class /// @return ::GMM_CPU_CACHE_TYPE ///////////////////////////////////////////////////////////////////////////////////// GMM_CPU_CACHE_TYPE GMM_STDCALL GmmResGetCpuCacheType(GMM_RESOURCE_INFO *pGmmResource) { __GMM_ASSERT(pGmmResource); return pGmmResource->GetCpuCacheType(); } ///////////////////////////////////////////////////////////////////////////////////// /// C wrapper for GmmLib::GmmResourceInfoCommon::GetMmcMode. /// @see GmmLib::GmmResourceInfoCommon::GetMmcMode() /// /// @param[in] pGmmResource: Pointer to the GmmResourceInfo class /// @param[in] ArrayIndex: ArrayIndex for which this info is needed /// @return Media Memory Compression Mode (Disabled, Horizontal, Vertical) ///////////////////////////////////////////////////////////////////////////////////// GMM_RESOURCE_MMC_INFO GMM_STDCALL GmmResGetMmcMode(GMM_RESOURCE_INFO *pGmmResource, uint32_t ArrayIndex) { __GMM_ASSERT(pGmmResource); return pGmmResource->GetMmcMode(ArrayIndex); } ///////////////////////////////////////////////////////////////////////////////////// /// C wrapper for GmmLib::GmmResourceInfoCommon::SetMmcMode. /// @see GmmLib::GmmResourceInfoCommon::SetMmcMode() /// /// @param[in] pGmmResource: Pointer to the GmmResourceInfo class /// @param[in] Mode Media Memory Compression Mode (Disabled, Horizontal, Vertical) /// @param[in] ArrayIndex ArrayIndex for which this info needs to be set ///////////////////////////////////////////////////////////////////////////////////// void GMM_STDCALL GmmResSetMmcMode(GMM_RESOURCE_INFO *pGmmResource, GMM_RESOURCE_MMC_INFO Mode, uint32_t ArrayIndex) { __GMM_ASSERTPTR(pGmmResource, VOIDRETURN); pGmmResource->SetMmcMode(Mode, ArrayIndex); } ///////////////////////////////////////////////////////////////////////////////////// /// C wrapper for GmmLib::GmmResourceInfoCommon::IsMediaMemoryCompressed. /// @see GmmLib::GmmResourceInfoCommon::IsMediaMemoryCompressed() /// /// @param[in] pGmmResource: Pointer to the GmmResourceInfo class /// @param[in] ArrayIndex ArrayIndex for which this info is needed /// @return 1 (enabled), 0 (disabled) ///////////////////////////////////////////////////////////////////////////////////// uint8_t GMM_STDCALL GmmResIsMediaMemoryCompressed(GMM_RESOURCE_INFO *pGmmResource, uint32_t ArrayIndex) { return pGmmResource->IsMediaMemoryCompressed(ArrayIndex); } ///////////////////////////////////////////////////////////////////////////////////// /// C wrapper for GmmLib::GmmResourceInfoCommon::GetMmcHint. /// @see GmmLib::GmmResourceInfoCommon::GetMmcHint() /// /// @param[in] pGmmResource: Pointer to the GmmResourceInfo class /// @param[in] ArrayIndex ArrayIndex for which this info is needed /// @return true/false ///////////////////////////////////////////////////////////////////////////////////// GMM_RESOURCE_MMC_HINT GMM_STDCALL GmmResGetMmcHint(GMM_RESOURCE_INFO *pGmmResource, uint32_t ArrayIndex) { __GMM_ASSERT(pGmmResource); return pGmmResource->GetMmcHint(ArrayIndex); } ///////////////////////////////////////////////////////////////////////////////////// /// C wrapper for GmmLib::GmmResourceInfoCommon::SetMmcHint. /// @see GmmLib::GmmResourceInfoCommon::SetMmcHint() /// /// @param[in] pGmmResource: Pointer to the GmmResourceInfo class /// @param[in] Hint Mmc hint to store /// @param[in] ArrayIndex ArrayIndex for which this info is needed /// @return true/false ///////////////////////////////////////////////////////////////////////////////////// void GMM_STDCALL GmmResSetMmcHint(GMM_RESOURCE_INFO *pGmmResource, GMM_RESOURCE_MMC_HINT Hint, uint32_t ArrayIndex) { __GMM_ASSERTPTR(pGmmResource, VOIDRETURN); pGmmResource->SetMmcHint(Hint, ArrayIndex); } ///////////////////////////////////////////////////////////////////////////////////// /// C wrapper for GmmLib::GmmResourceInfoCommon::GetNumSamples. /// @see GmmLib::GmmResourceInfoCommon::GetNumSamples() /// /// @param[in] pGmmResource: Pointer to the GmmResourceInfo class /// @return Sample count ///////////////////////////////////////////////////////////////////////////////////// uint32_t GMM_STDCALL GmmResGetNumSamples(GMM_RESOURCE_INFO *pGmmResource) { __GMM_ASSERTPTR(pGmmResource, 0); return pGmmResource->GetNumSamples(); } ///////////////////////////////////////////////////////////////////////////////////// /// C wrapper for GmmLib::GmmResourceInfoCommon::GetSamplePattern. /// @see GmmLib::GmmResourceInfoCommon::GetSamplePattern() /// /// @param[in] pGmmResource: Pointer to the GmmResourceInfo class /// @return Sample count ///////////////////////////////////////////////////////////////////////////////////// GMM_MSAA_SAMPLE_PATTERN GMM_STDCALL GmmResGetSamplePattern(GMM_RESOURCE_INFO *pGmmResource) { __GMM_ASSERT(pGmmResource); return pGmmResource->GetSamplePattern(); } ///////////////////////////////////////////////////////////////////////////////////// /// C wrapper for GmmLib::GmmResourceInfoCommon::GetHAlign. /// @see GmmLib::GmmResourceInfoCommon::GetHAlign() /// /// @param[in] pGmmResource: Pointer to the GmmResourceInfo class /// @return HAlign ///////////////////////////////////////////////////////////////////////////////////// uint32_t GMM_STDCALL GmmResGetHAlign(GMM_RESOURCE_INFO *pGmmResource) { __GMM_ASSERTPTR(pGmmResource, 0); return pGmmResource->GetHAlign(); } ///////////////////////////////////////////////////////////////////////////////////// /// C wrapper for GmmLib::GmmResourceInfoCommon::GetVAlign. /// @see GmmLib::GmmResourceInfoCommon::GetVAlign() /// /// @param[in] pGmmResource: Pointer to the GmmResourceInfo class /// @return VAlign ///////////////////////////////////////////////////////////////////////////////////// uint32_t GMM_STDCALL GmmResGetVAlign(GMM_RESOURCE_INFO *pGmmResource) { __GMM_ASSERTPTR(pGmmResource, 0); return pGmmResource->GetVAlign(); } ///////////////////////////////////////////////////////////////////////////////////// /// C wrapper for GmmLib::GmmResourceInfoCommon::GetAuxHAlign. /// @see GmmLib::GmmResourceInfoCommon::GetAuxHAlign() /// /// @param[in] pGmmResource: Pointer to the GmmResourceInfo class /// @return HAlign ///////////////////////////////////////////////////////////////////////////////////// uint32_t GMM_STDCALL GmmResGetAuxHAlign(GMM_RESOURCE_INFO *pGmmResource) { __GMM_ASSERTPTR(pGmmResource, 0); return pGmmResource->GetAuxHAlign(); } ///////////////////////////////////////////////////////////////////////////////////// /// C wrapper for GmmLib::GmmResourceInfoCommon::GetAuxVAlign. /// @see GmmLib::GmmResourceInfoCommon::GetAuxVAlign() /// /// @param[in] pGmmResource: Pointer to the GmmResourceInfo class /// @return VAlign ///////////////////////////////////////////////////////////////////////////////////// uint32_t GMM_STDCALL GmmResGetAuxVAlign(GMM_RESOURCE_INFO *pGmmResource) { __GMM_ASSERTPTR(pGmmResource, 0); return pGmmResource->GetAuxVAlign(); } ///////////////////////////////////////////////////////////////////////////////////// /// C wrapper for GmmLib::GmmResourceInfoCommon::IsArraySpacingSingleLod. /// @see GmmLib::GmmResourceInfoCommon::IsArraySpacingSingleLod() /// /// @param[in] pGmmResource: Pointer to the GmmResourceInfo class /// @return 1/0 ///////////////////////////////////////////////////////////////////////////////////// uint8_t GMM_STDCALL GmmResIsArraySpacingSingleLod(GMM_RESOURCE_INFO *pGmmResource) { __GMM_ASSERTPTR(pGmmResource, 0); return pGmmResource->IsArraySpacingSingleLod(); } ///////////////////////////////////////////////////////////////////////////////////// /// C wrapper for GmmLib::GmmResourceInfoCommon::IsASTC. /// @see GmmLib::GmmResourceInfoCommon::IsASTC() /// /// @param[in] pGmmResource: Pointer to the GmmResourceInfo class /// @return 1/0 ///////////////////////////////////////////////////////////////////////////////////// uint8_t GMM_STDCALL GmmResIsASTC(GMM_RESOURCE_INFO *pGmmResource) { __GMM_ASSERTPTR(pGmmResource, 0); return pGmmResource->IsASTC(); } ///////////////////////////////////////////////////////////////////////////////////// /// C wrapper for GmmLib::GmmResourceInfoCommon::IsMsaaFormatDepthStencil. /// @see GmmLib::GmmResourceInfoCommon::IsMsaaFormatDepthStencil() /// /// @param[in] pGmmResource: Pointer to the GmmResourceInfo class /// @return 1/0 ///////////////////////////////////////////////////////////////////////////////////// uint8_t GMM_STDCALL GmmResIsMsaaFormatDepthStencil(GMM_RESOURCE_INFO *pGmmResource) { __GMM_ASSERTPTR(pGmmResource, 0); return pGmmResource->IsMsaaFormatDepthStencil(); } ///////////////////////////////////////////////////////////////////////////////////// /// C wrapper for GmmLib::GmmResourceInfoCommon::IsSvm. /// @see GmmLib::GmmResourceInfoCommon::IsSvm() /// /// @param[in] pGmmResource: Pointer to the GmmResourceInfo class /// @return 1/0 ///////////////////////////////////////////////////////////////////////////////////// uint8_t GMM_STDCALL GmmResIsSvm(GMM_RESOURCE_INFO *pGmmResource) { __GMM_ASSERTPTR(pGmmResource, 0); return pGmmResource->IsSvm(); } ///////////////////////////////////////////////////////////////////////////////////// /// C wrapper for GmmResourceInfoCommon::ValidateParams /// @see GmmLib::GmmResourceInfoCommon::ValidateParams() /// /// @param[in] pResourceInfo: Pointer to GmmResourceInfo class /// @return 1 is validation passed. 0 otherwise. ///////////////////////////////////////////////////////////////////////////////////// uint8_t GMM_STDCALL GmmResValidateParams(GMM_RESOURCE_INFO *pResourceInfo) { return pResourceInfo->ValidateParams(); } ///////////////////////////////////////////////////////////////////////////////////// /// C wrapper for GmmResourceInfoCommon::SetPrivateData /// @see GmmLib::GmmResourceInfoCommon::SetPrivateData() /// /// @param[in] pGmmResource: Pointer to GmmResourceInfo class /// @param[in] pPrivateData: Pointer to opaque private data from clients ///////////////////////////////////////////////////////////////////////////////////// void GMM_STDCALL GmmResSetPrivateData(GMM_RESOURCE_INFO *pGmmResource, void *pPrivateData) { __GMM_ASSERTPTR(pGmmResource, VOIDRETURN); pGmmResource->SetPrivateData(pPrivateData); } ///////////////////////////////////////////////////////////////////////////////////// /// C wrapper for GmmResourceInfoCommon::GetPrivateData /// @see GmmLib::GmmResourceInfoCommon::GetPrivateData() /// /// @param[in] pGmmResource: Pointer to GmmResourceInfo class /// @return pointer to opaque private data ///////////////////////////////////////////////////////////////////////////////////// void *GMM_STDCALL GmmResGetPrivateData(GMM_RESOURCE_INFO *pGmmResource) { __GMM_ASSERTPTR(pGmmResource, 0); return pGmmResource->GetPrivateData(); } ///////////////////////////////////////////////////////////////////////////////////// /// C wrapper for GmmResourceInfoCommon::GetGfxAddress /// @see GmmLib::GmmResourceInfoCommon::GetGfxAddress() /// /// @param[in] pGmmResource: Pointer to GmmResourceInfo class /// @return Gfx address ///////////////////////////////////////////////////////////////////////////////////// GMM_GFX_ADDRESS GMM_STDCALL GmmResGetGfxAddress(GMM_RESOURCE_INFO *pGmmResource) { __GMM_ASSERTPTR(pGmmResource, 0); return pGmmResource->GetGfxAddress(); } ///////////////////////////////////////////////////////////////////////////////////// /// C wrapper for GmmResourceInfoCommon::GetTallBufferHeight /// @see GmmLib::GmmResourceInfoCommon::GetTallBufferHeight() /// /// @param[in] pResourceInfo: Pointer to GmmResourceInfo class /// @return Surface height ///////////////////////////////////////////////////////////////////////////////////// uint32_t GMM_STDCALL GmmResGetTallBufferHeight(GMM_RESOURCE_INFO *pResourceInfo) { __GMM_ASSERTPTR(pResourceInfo, 0); return pResourceInfo->GetTallBufferHeight(); }; ///////////////////////////////////////////////////////////////////////////////////// /// C wrapper for GmmResourceInfoCommon::GetSizeMainSurface /// @see GmmLib::GmmResourceInfoCommon::GetSizeMainSurface() /// /// @param[in] pResourceInfo: Pointer to GmmResourceInfo class /// @return Size of main surface ///////////////////////////////////////////////////////////////////////////////////// GMM_GFX_SIZE_T GMM_STDCALL GmmResGetSizeMainSurface(const GMM_RESOURCE_INFO *pResourceInfo) { return pResourceInfo->GetSizeMainSurface(); } //TODO(Low) : Remove when client moves to new interface ///////////////////////////////////////////////////////////////////////////////////// /// C wrapper for GmmResourceInfoCommon::GetSizeSurface /// @see GmmLib::GmmResourceInfoCommon::GetSizeSurface() /// /// @param[in] pResourceInfo: Pointer to GmmResourceInfo class /// @return Surface Size ///////////////////////////////////////////////////////////////////////////////////// uint32_t GMM_STDCALL GmmResGetRenderSize(GMM_RESOURCE_INFO *pResourceInfo) { __GMM_ASSERTPTR(pResourceInfo, 0); return GFX_ULONG_CAST(pResourceInfo->GetSizeSurface()); } uint32_t GMM_STDCALL GmmResGetAuxSurfaceSize(GMM_RESOURCE_INFO *pGmmResource, GMM_UNIFIED_AUX_TYPE GmmAuxType) { return GFX_ULONG_CAST(GmmResGetSizeAuxSurface(pGmmResource, GmmAuxType)); } ///////////////////////////////////////////////////////////////////////////////////// /// C wrapper for GmmResourceInfoCommon::GetSizeSurface /// @see GmmLib::GmmResourceInfoCommon::GetSizeSurface() /// /// @param[in] pResourceInfo: Pointer to GmmResourceInfo class /// @return Surface Size ///////////////////////////////////////////////////////////////////////////////////// GMM_GFX_SIZE_T GMM_STDCALL GmmResGetSizeSurface(GMM_RESOURCE_INFO *pResourceInfo) { __GMM_ASSERTPTR(pResourceInfo, 0); return pResourceInfo->GetSizeSurface(); } ///////////////////////////////////////////////////////////////////////////////////// /// C wrapper for GmmResourceInfoCommon::GetSizeAllocation /// @see GmmLib::GmmResourceInfoCommon::GetSizeAllocation() /// /// @param[in] pResourceInfo: Pointer to GmmResourceInfo class /// @return Allocation Size ///////////////////////////////////////////////////////////////////////////////////// GMM_GFX_SIZE_T GMM_STDCALL GmmResGetSizeAllocation(GMM_RESOURCE_INFO *pResourceInfo) { __GMM_ASSERTPTR(pResourceInfo, 0); return pResourceInfo->GetSizeAllocation(); } ///////////////////////////////////////////////////////////////////////////////////// /// C wrapper for GmmResourceInfoCommon::GetResourceFormatSurfaceState /// @see GmmLib::GmmResourceInfoCommon::GetResourceFormatSurfaceState() /// /// @param[in] pGmmResource: Pointer to GmmResourceInfo class /// @return Resource format ///////////////////////////////////////////////////////////////////////////////////// GMM_SURFACESTATE_FORMAT GMM_STDCALL GmmResGetSurfaceStateFormat(GMM_RESOURCE_INFO *pGmmResource) { __GMM_ASSERTPTR(pGmmResource, GMM_SURFACESTATE_FORMAT_INVALID); return pGmmResource->GetResourceFormatSurfaceState(); } //============================================================================= // // Function: GmmGetSurfaceStateFormat // // Desc: See below. // // Returns: // SURFACE_STATE.Format for the given resource or // GMM_SURFACESTATE_FORMAT_INVALID if resource wasn't created with a // direct SURFACE_STATE.Format. // //----------------------------------------------------------------------------- GMM_SURFACESTATE_FORMAT GMM_STDCALL GmmGetSurfaceStateFormat(GMM_RESOURCE_FORMAT Format, GMM_LIB_CONTEXT *pGmmLibContext) { return ((Format > GMM_FORMAT_INVALID) && (Format < GMM_RESOURCE_FORMATS)) ? pGmmLibContext->GetPlatformInfo().FormatTable[Format].SurfaceStateFormat : GMM_SURFACESTATE_FORMAT_INVALID; } //============================================================================= // // Function: GmmGetCompressionFormat // // Desc: See below. // // Returns: // CompressionFormat.CompressionFormat // //----------------------------------------------------------------------------- uint8_t GMM_STDCALL GmmGetCompressionFormat(GMM_RESOURCE_FORMAT Format, GMM_LIB_CONTEXT *pGmmLibContext) { return (((Format > GMM_FORMAT_INVALID) && (Format < GMM_RESOURCE_FORMATS)) ? pGmmLibContext->GetPlatformInfo().FormatTable[Format].CompressionFormat.CompressionFormat : GMM_UNIFIED_CMF_INVALID); } ///////////////////////////////////////////////////////////////////////////////////// /// C wrapper for GmmResourceInfoCommon::GetHAlignSurfaceState /// @see GmmLib::GmmResourceInfoCommon::GetHAlignSurfaceState() /// /// @param[in] pGmmResource: Pointer to GmmResourceInfo class /// @return HAlign ///////////////////////////////////////////////////////////////////////////////////// uint32_t GMM_STDCALL GmmResGetSurfaceStateHAlign(GMM_RESOURCE_INFO *pGmmResource) { __GMM_ASSERTPTR(pGmmResource, 0); return pGmmResource->GetHAlignSurfaceState(); } ///////////////////////////////////////////////////////////////////////////////////// /// C wrapper for GmmResourceInfoCommon::GetVAlignSurfaceState /// @see GmmLib::GmmResourceInfoCommon::GetVAlignSurfaceState() /// /// @param[in] pGmmResource: Pointer to GmmResourceInfo class /// @return VAlign ///////////////////////////////////////////////////////////////////////////////////// uint32_t GMM_STDCALL GmmResGetSurfaceStateVAlign(GMM_RESOURCE_INFO *pGmmResource) { __GMM_ASSERTPTR(pGmmResource, 0); return pGmmResource->GetVAlignSurfaceState(); } ///////////////////////////////////////////////////////////////////////////////////// /// C wrapper for GmmResourceInfoCommon::GetTiledResourceModeSurfaceState /// @see GmmLib::GmmResourceInfoCommon::GetTiledResourceModeSurfaceState() /// /// @param[in] pGmmResource: Pointer to GmmResourceInfo class /// @return Tiled Resource Mode ///////////////////////////////////////////////////////////////////////////////////// uint32_t GMM_STDCALL GmmResGetSurfaceStateTiledResourceMode(GMM_RESOURCE_INFO *pGmmResource) { __GMM_ASSERTPTR(pGmmResource, 0); return pGmmResource->GetTiledResourceModeSurfaceState(); } ///////////////////////////////////////////////////////////////////////////////////// /// Returns the surface offset for unified allocations. Truncates the offset to size /// of uint32_t. /// @see GmmResGetAuxSurfaceOffset64() /// /// @param[in] pGmmResource: Pointer to GmmResourceInfo class /// @param[in] GmmAuxType: the type of aux the offset is needed for /// @return Surface Offset in bytes ///////////////////////////////////////////////////////////////////////////////////// uint32_t GMM_STDCALL GmmResGetAuxSurfaceOffset(GMM_RESOURCE_INFO *pGmmResource, GMM_UNIFIED_AUX_TYPE GmmAuxType) { return GFX_ULONG_CAST(GmmResGetAuxSurfaceOffset64(pGmmResource, GmmAuxType)); } ///////////////////////////////////////////////////////////////////////////////////// /// C wrapper for GmmResourceInfoCommon::GetUnifiedAuxSurfaceOffset /// @see GmmLib::GmmResourceInfoCommon::GetUnifiedAuxSurfaceOffset() /// /// @param[in] pGmmResource: Pointer to GmmResourceInfo class /// @param[in] GmmAuxType: the type of aux the offset is needed for /// @return Surface Offset in bytes ///////////////////////////////////////////////////////////////////////////////////// GMM_GFX_SIZE_T GMM_STDCALL GmmResGetAuxSurfaceOffset64(GMM_RESOURCE_INFO *pGmmResource, GMM_UNIFIED_AUX_TYPE GmmAuxType) { __GMM_ASSERTPTR(pGmmResource, 0); return pGmmResource->GetUnifiedAuxSurfaceOffset(GmmAuxType); } ///////////////////////////////////////////////////////////////////////////////////// /// C wrapper for GmmResourceInfoCommon::GetSizeAuxSurface /// @see GmmLib::GmmResourceInfoCommon::GetSizeAuxSurface() /// /// @param[in] pGmmResource: Pointer to GmmResourceInfo class /// @param[in] GmmAuxType: the type of aux the size is needed for /// @return Surface size in bytes ///////////////////////////////////////////////////////////////////////////////////// GMM_GFX_SIZE_T GMM_STDCALL GmmResGetSizeAuxSurface(GMM_RESOURCE_INFO *pGmmResource, GMM_UNIFIED_AUX_TYPE GmmAuxType) { __GMM_ASSERTPTR(pGmmResource, 0); return pGmmResource->GetSizeAuxSurface(GmmAuxType); } ///////////////////////////////////////////////////////////////////////////////////// /// C wrapper for GmmResourceInfoCommon::GetSetHardwareProtection /// @see GmmLib::GmmResourceInfoCommon::GetSetHardwareProtection() /// @see GmmLib::GmmResourceInfoWin::GetSetHardwareProtection() /// /// @param[in] pGmmResource: Pointer to GmmResourceInfo class /// @param[in] GetIsEncrypted: Read encryption status /// @param[in] SetIsEncrypted: Write encryption status /// @return Whether surface is encrypted or not ///////////////////////////////////////////////////////////////////////////////////// uint8_t GMM_STDCALL GmmResGetSetHardwareProtection(GMM_RESOURCE_INFO *pGmmResource, uint8_t GetIsEncrypted, uint8_t SetIsEncrypted) { return pGmmResource ? pGmmResource->GetSetHardwareProtection(GetIsEncrypted, SetIsEncrypted) : 0; } ///////////////////////////////////////////////////////////////////////////////////// /// C wrapper for GmmResourceInfoCommon::CpuBlt /// @see GmmLib::GmmResourceInfoCommon::CpuBlt() /// /// @param[in] pGmmResource: Pointer to GmmResourceInfo class /// @param[in] pBlt: Describes the blit operation. See ::GMM_RES_COPY_BLT for more info. /// @return 1 if succeeded, 0 otherwise ///////////////////////////////////////////////////////////////////////////////////// uint8_t GMM_STDCALL GmmResCpuBlt(GMM_RESOURCE_INFO *pGmmResource, GMM_RES_COPY_BLT *pBlt) { __GMM_ASSERTPTR(pGmmResource, 0); return pGmmResource->CpuBlt(pBlt); } ///////////////////////////////////////////////////////////////////////////////////// /// C wrapper for GmmResourceInfoCommon::GetStdLayoutSize /// @see GmmLib::GmmResourceInfoCommon::GetStdLayoutSize() /// /// @param[in] pGmmResource: Pointer to GmmResourceInfo class /// @return Size in bytes of Standard Layout version of surface. ///////////////////////////////////////////////////////////////////////////////////// GMM_GFX_SIZE_T GMM_STDCALL GmmResGetStdLayoutSize(GMM_RESOURCE_INFO *pGmmResource) { __GMM_ASSERT(pGmmResource); return pGmmResource->GetStdLayoutSize(); } ///////////////////////////////////////////////////////////////////////////////////// /// C wrapper for GmmResourceInfoCommon::GetMappingSpanDesc /// @see GmmLib::GmmResourceInfoCommon::GetMappingSpanDesc() /// /// @param[in] pGmmResource: Pointer to GmmResourceInfo class /// @param[in] pMapping: Clients call the function with initially zero'd out GMM_GET_MAPPING. /// @return 1 if more span descriptors to report, 0 if all mapping is done ///////////////////////////////////////////////////////////////////////////////////// uint8_t GMM_STDCALL GmmResGetMappingSpanDesc(GMM_RESOURCE_INFO *pGmmResource, GMM_GET_MAPPING *pMapping) { __GMM_ASSERTPTR(pGmmResource, 0); return pGmmResource->GetMappingSpanDesc(pMapping); } ///////////////////////////////////////////////////////////////////////////////////// /// C wrapper for GmmResourceInfoCommon::IsColorSeparation /// @see GmmLib::GmmResourceInfoCommon::IsColorSeparation() /// /// @param[in] pGmmResource: Pointer to GmmResourceInfo class /// @return 1 if the resource is color separated target, 0 otherwise ///////////////////////////////////////////////////////////////////////////////////// uint8_t GMM_STDCALL GmmResIsColorSeparation(GMM_RESOURCE_INFO *pGmmResource) { __GMM_ASSERTPTR(pGmmResource, 0); return pGmmResource->IsColorSeparation(); } ///////////////////////////////////////////////////////////////////////////////////// /// C wrapper for GmmResourceInfoCommon::TranslateColorSeparationX /// @see GmmLib::GmmResourceInfoCommon::TranslateColorSeparationX() /// /// @param[in] pGmmResource: Pointer to GmmResourceInfo class /// @param[in] x: X coordinate /// @return Translated color separation target x coordinate ///////////////////////////////////////////////////////////////////////////////////// uint32_t GMM_STDCALL GmmResTranslateColorSeparationX(GMM_RESOURCE_INFO *pGmmResource, uint32_t x) { __GMM_ASSERTPTR(pGmmResource, false); return pGmmResource->TranslateColorSeparationX(x); } ///////////////////////////////////////////////////////////////////////////////////// /// C wrapper for GmmResourceInfoCommon::GetColorSeparationArraySize /// @see GmmLib::GmmResourceInfoCommon::GetColorSeparationArraySize() /// /// @param[in] pGmmResource: Pointer to GmmResourceInfo class /// @return Array size of a color separated target resource ///////////////////////////////////////////////////////////////////////////////////// uint32_t GMM_STDCALL GmmResGetColorSeparationArraySize(GMM_RESOURCE_INFO *pGmmResource) { __GMM_ASSERTPTR(pGmmResource, 0); return pGmmResource->GetColorSeparationArraySize(); } ///////////////////////////////////////////////////////////////////////////////////// /// C wrapper for GmmResourceInfoCommon::GetColorSeparationPhysicalWidth /// @see GmmLib::GmmResourceInfoCommon::GetColorSeparationPhysicalWidth() /// /// @param[in] pGmmResource: Pointer to GmmResourceInfo class /// @return Physical width of a color separated target resource ///////////////////////////////////////////////////////////////////////////////////// uint32_t GMM_STDCALL GmmResGetColorSeparationPhysicalWidth(GMM_RESOURCE_INFO *pGmmResource) { __GMM_ASSERTPTR(pGmmResource, 0); return pGmmResource->GetColorSeparationPhysicalWidth(); } //============================================================================= // // Function: GmmResGetMaxGpuVirtualAddressBits // // Desc: This function returns max no of GpuVA bits supported per surface on current platform // // Parameters: // GMM_RESOURCE_INFO *pGmmResource (Don't care) // Function will return the current Gen MaxGpuVirtualAddressBitsPerResource // // Returns: // uint32_t - Max no of GpuVA bits //----------------------------------------------------------------------------- uint32_t GMM_STDCALL GmmResGetMaxGpuVirtualAddressBits(GMM_RESOURCE_INFO *pGmmResource, GMM_LIB_CONTEXT *pGmmLibContext) { if(pGmmResource == NULL) { __GMM_ASSERTPTR(pGmmLibContext, 0); const GMM_PLATFORM_INFO &PlatformInfo = pGmmLibContext->GetPlatformInfo(); return PlatformInfo.MaxGpuVirtualAddressBitsPerResource; } return pGmmResource->GetMaxGpuVirtualAddressBits(); } ///////////////////////////////////////////////////////////////////////////////////// /// C wrapper for GmmResourceInfoCommon::IsSurfaceFaultable /// @see GmmLib::GmmResourceInfoCommon::IsSurfaceFaultable() /// @see GmmLib::GmmResourceInfoWin::IsSurfaceFaultable() /// /// @param[in] pGmmResource: Pointer to GmmResourceInfo class /// @return 1 is surface can be faulted on ///////////////////////////////////////////////////////////////////////////////////// uint8_t GMM_STDCALL GmmIsSurfaceFaultable(GMM_RESOURCE_INFO *pGmmResource) { __GMM_ASSERTPTR(pGmmResource, 0); return pGmmResource->IsSurfaceFaultable(); } ///////////////////////////////////////////////////////////////////////////////////// /// C wrapper for GmmResourceInfoCommon::GetResFlags /// @see GmmLib::GmmResourceInfoCommon::GetResFlags() /// /// @param[in] pGmmResource: Pointer to GmmResourceInfo class /// @return Copy of ::GMM_RESOURCE_FLAGS ///////////////////////////////////////////////////////////////////////////////////// GMM_RESOURCE_FLAG GMM_STDCALL GmmResGetResourceFlags(const GMM_RESOURCE_INFO *pGmmResource) { __GMM_ASSERT(pGmmResource); return const_cast(pGmmResource)->GetResFlags(); } ///////////////////////////////////////////////////////////////////////////////////// /// C wrapper for GmmResourceInfoCommon::GetMaximumRenamingListLength /// @see GmmLib::GmmResourceInfoCommon::GetMaximumRenamingListLength() /// /// @param[in] pGmmResource: Pointer to GmmResourceInfo class /// @return maximum remaining list length ///////////////////////////////////////////////////////////////////////////////////// uint32_t GMM_STDCALL GmmResGetMaximumRenamingListLength(GMM_RESOURCE_INFO *pGmmResource) { __GMM_ASSERT(pGmmResource); return pGmmResource->GetMaximumRenamingListLength(); } //============================================================================= // // Function: GmmGetLogicalTileShape // // Desc: This function returns the logical tile shape // // Parameters: // See Function arguments // // Returns: // GMM_STATUS //----------------------------------------------------------------------------- GMM_STATUS GMM_STDCALL GmmGetLogicalTileShape(uint32_t TileMode, uint32_t *pWidthInBytes, uint32_t *pHeight, uint32_t *pDepth, GMM_LIB_CONTEXT *pGmmLibContext) { __GMM_ASSERT(TileMode < GMM_TILE_MODES); if(pWidthInBytes) { *pWidthInBytes = pGmmLibContext->GetPlatformInfo().TileInfo[TileMode].LogicalTileWidth; } if(pHeight) { *pHeight = pGmmLibContext->GetPlatformInfo().TileInfo[TileMode].LogicalTileHeight; } if(pDepth) { *pDepth = pGmmLibContext->GetPlatformInfo().TileInfo[TileMode].LogicalTileDepth; } return GMM_SUCCESS; } ///////////////////////////////////////////////////////////////////////////////////// /// C wrapper for GmmResourceInfoCommon::OverrideSize /// @see GmmLib::GmmResourceInfoCommon::OverrideSize() /// /// @param[in] pGmmResource: Pointer to GmmResourceInfo class /// @param[in] Size: new size of the resource ///////////////////////////////////////////////////////////////////////////////////// void GMM_STDCALL GmmResOverrideAllocationSize(GMM_RESOURCE_INFO *pGmmResource, GMM_GFX_SIZE_T Size) { __GMM_ASSERT(pGmmResource); pGmmResource->OverrideSize(Size); } ///////////////////////////////////////////////////////////////////////////////////// /// C wrapper for GmmResourceInfoCommon::OverridePitch /// @see GmmLib::GmmResourceInfoCommon::OverridePitch() /// /// @param[in] pGmmResource: Pointer to GmmResourceInfo class /// @param[in] Pitch: new pitch of the resource ///////////////////////////////////////////////////////////////////////////////////// void GMM_STDCALL GmmResOverrideAllocationPitch(GMM_RESOURCE_INFO *pGmmResource, GMM_GFX_SIZE_T Pitch) { __GMM_ASSERT(pGmmResource); pGmmResource->OverridePitch(Pitch); } ///////////////////////////////////////////////////////////////////////////////////// /// C wrapper for GmmResourceInfoCommon::OverrideUnifiedAuxPitch /// @see GmmLib::GmmResourceInfoCommon::OverrideUnifiedAuxPitch() /// /// @param[in] pGmmResource: Pointer to GmmResourceInfo class /// @param[in] Pitch: new pitch of the resource ///////////////////////////////////////////////////////////////////////////////////// void GMM_STDCALL GmmResOverrideAuxAllocationPitch(GMM_RESOURCE_INFO *pGmmResource, GMM_GFX_SIZE_T Pitch) { __GMM_ASSERT(pGmmResource); pGmmResource->OverrideUnifiedAuxPitch(Pitch); } ///////////////////////////////////////////////////////////////////////////////////// /// C wrapper for GmmResourceInfoCommon::OverrideUnifiedAuxPitch /// @see GmmLib::GmmResourceInfoCommon::OverrideUnifiedAuxPitch() /// /// @param[in] pGmmResource: Pointer to GmmResourceInfo class /// @param[in] Pitch: new pitch of the resource ///////////////////////////////////////////////////////////////////////////////////// void GMM_STDCALL GmmResOverrideAllocationFlags(GMM_RESOURCE_INFO *pGmmResource, GMM_RESOURCE_FLAG *pFlags) { __GMM_ASSERT(pGmmResource); __GMM_ASSERT(pFlags); pGmmResource->OverrideAllocationFlags(*pFlags); } ///////////////////////////////////////////////////////////////////////////////////// /// C wrapper for GmmResourceInfoCommon::OverrideHAlign /// @see GmmLib::GmmResourceInfoCommon::OverrideHAlign() /// /// @param[in] pGmmResource: Pointer to GmmResourceInfo class /// @param[in] Pitch: new pitch of the resource ///////////////////////////////////////////////////////////////////////////////////// void GMM_STDCALL GmmResOverrideAllocationHAlign(GMM_RESOURCE_INFO *pGmmResource, uint32_t HAlign) { __GMM_ASSERT(pGmmResource); pGmmResource->OverrideHAlign(HAlign); } ///////////////////////////////////////////////////////////////////////////////////// /// C wrapper for GmmResourceInfoCommon::OverrideBaseAlignment /// @see GmmLib::GmmResourceInfoCommon::OverrideBaseAlignment() /// /// @param[in] pGmmResource: Pointer to GmmResourceInfo class /// @param[in] Alignment: new BaseAlignment of the resource ///////////////////////////////////////////////////////////////////////////////////// void GMM_STDCALL GmmResOverrideAllocationBaseAlignment(GMM_RESOURCE_INFO *pGmmResource, uint32_t Alignment) { __GMM_ASSERT(pGmmResource); pGmmResource->OverrideBaseAlignment(Alignment); } ///////////////////////////////////////////////////////////////////////////////////// /// C wrapper for GmmResourceInfoCommon::OverrideBaseWidth /// @see GmmLib::GmmResourceInfoCommon::OverrideBaseWidth() /// /// @param[in] pGmmResource: Pointer to GmmResourceInfo class /// @param[in] BaseWidth: new BaseWidth of the resource ///////////////////////////////////////////////////////////////////////////////////// void GMM_STDCALL GmmResOverrideAllocationBaseWidth(GMM_RESOURCE_INFO *pGmmResource, GMM_GFX_SIZE_T BaseWidth) { __GMM_ASSERT(pGmmResource); pGmmResource->OverrideBaseWidth(BaseWidth); } ///////////////////////////////////////////////////////////////////////////////////// /// C wrapper for GmmResourceInfoCommon::OverrideBaseHeight /// @see GmmLib::GmmResourceInfoCommon::OverrideBaseHeight() /// /// @param[in] pGmmResource: Pointer to GmmResourceInfo class /// @param[in] BaseHeight: new BaseWidth of the resource ///////////////////////////////////////////////////////////////////////////////////// void GMM_STDCALL GmmResOverrideAllocationBaseHeight(GMM_RESOURCE_INFO *pGmmResource, uint32_t BaseHeight) { __GMM_ASSERT(pGmmResource); pGmmResource->OverrideBaseHeight(BaseHeight); } ///////////////////////////////////////////////////////////////////////////////////// /// C wrapper for GmmResourceInfoCommon::OverrideDepth /// @see GmmLib::GmmResourceInfoCommon::OverrideDepth() /// /// @param[in] pGmmResource: Pointer to GmmResourceInfo class /// @param[in] Depth: new Depth of the resource ///////////////////////////////////////////////////////////////////////////////////// void GMM_STDCALL GmmResOverrideAllocationDepth(GMM_RESOURCE_INFO *pGmmResource, uint32_t Depth) { __GMM_ASSERT(pGmmResource); pGmmResource->OverrideDepth(Depth); } ///////////////////////////////////////////////////////////////////////////////////// /// C wrapper for GmmResourceInfoCommon::OverrideTileMode /// @see GmmLib::GmmResourceInfoCommon::OverrideTileMode() /// /// @param[in] pGmmResource: Pointer to GmmResourceInfo class /// @param[in] TileMode: new tile mode of the resource ///////////////////////////////////////////////////////////////////////////////////// void GMM_STDCALL GmmResOverrideResourceTiling(GMM_RESOURCE_INFO *pGmmResource, uint32_t TileMode) { __GMM_ASSERT(pGmmResource); pGmmResource->OverrideTileMode(static_cast(TileMode)); } ///////////////////////////////////////////////////////////////////////////////////// /// C wrapper for GmmResourceInfoCommon::OverrideUnifiedAuxTileMode /// @see GmmLib::GmmResourceInfoCommon::OverrideUnifiedAuxTileMode() /// /// @param[in] pGmmResource: Pointer to GmmResourceInfo class /// @param[in] TileMode: new tile mode of the unified auxresource ///////////////////////////////////////////////////////////////////////////////////// void GMM_STDCALL GmmResOverrideAuxResourceTiling(GMM_RESOURCE_INFO *pGmmResource, uint32_t TileMode) { __GMM_ASSERT(pGmmResource); pGmmResource->OverrideUnifiedAuxTileMode(static_cast(TileMode)); } ///////////////////////////////////////////////////////////////////////////////////// /// C wrapper for GmmResourceInfoCommon::OverrideSurfaceFormat /// @see GmmLib::GmmResourceInfoCommon::OverrideSurfaceFormat() /// /// @param[in] pGmmResource: Pointer to GmmResourceInfo class /// @param[in] Format: new format for the resource ///////////////////////////////////////////////////////////////////////////////////// void GMM_STDCALL GmmResOverrideAllocationFormat(GMM_RESOURCE_INFO *pGmmResource, GMM_RESOURCE_FORMAT Format) { __GMM_ASSERT(pGmmResource); pGmmResource->OverrideSurfaceFormat(Format); } ///////////////////////////////////////////////////////////////////////////////////// /// C wrapper for GmmResourceInfoCommon::OverrideSurfaceType /// @see GmmLib::GmmResourceInfoCommon::OverrideSurfaceType() /// /// @param[in] pGmmResource: Pointer to GmmResourceInfo class /// @param[in] ResourceType: new type for the resource ///////////////////////////////////////////////////////////////////////////////////// void GMM_STDCALL GmmResOverrideSurfaceType(GMM_RESOURCE_INFO *pGmmResource, GMM_RESOURCE_TYPE ResourceType) { __GMM_ASSERT(pGmmResource); pGmmResource->OverrideSurfaceType(ResourceType); } ///////////////////////////////////////////////////////////////////////////////////// /// C wrapper for GmmResourceInfoCommon::GmmResOverrideSvmGfxAddress /// @see GmmLib::GmmResourceInfoCommon::GmmResOverrideSvmGfxAddress() /// /// @param[in] pGmmResource: Pointer to GmmResourceInfo class /// @param[in] SvmGfxAddress: new svm gfx address for the resource ///////////////////////////////////////////////////////////////////////////////////// void GMM_STDCALL GmmResOverrideSvmGfxAddress(GMM_RESOURCE_INFO *pGmmResource, GMM_GFX_ADDRESS SvmGfxAddress) { __GMM_ASSERT(pGmmResource); pGmmResource->OverrideSvmGfxAddress(SvmGfxAddress); } ///////////////////////////////////////////////////////////////////////////////////// /// C wrapper for GmmResourceInfoCommon::OverrideArraySize /// @see GmmLib::GmmResourceInfoCommon::OverrideArraySize() /// /// @param[in] pGmmResource: Pointer to GmmResourceInfo class /// @param[in] ArraySize: new array size for the resource ///////////////////////////////////////////////////////////////////////////////////// void GMM_STDCALL GmmResOverrideAllocationArraySize(GMM_RESOURCE_INFO *pGmmResource, uint32_t ArraySize) { __GMM_ASSERT(pGmmResource); pGmmResource->OverrideArraySize(ArraySize); } ///////////////////////////////////////////////////////////////////////////////////// /// C wrapper for GmmResourceInfoCommon::OverrideArraySize /// @see GmmLib::GmmResourceInfoCommon::OverrideArraySize() /// /// @param[in] pGmmResource: Pointer to GmmResourceInfo class /// @param[in] MaxLod: new max LOD for the resource ///////////////////////////////////////////////////////////////////////////////////// void GMM_STDCALL GmmResOverrideAllocationMaxLod(GMM_RESOURCE_INFO *pGmmResource, uint32_t MaxLod) { __GMM_ASSERT(pGmmResource); pGmmResource->OverrideMaxLod(MaxLod); } ///////////////////////////////////////////////////////////////////////////////////// /// C wrapper for GmmResourceInfoCommon::GetPlanarXOffset /// @see GmmLib::GmmResourceInfoCommon::GetPlanarXOffset() /// /// @param[in] pGmmResource: Pointer to GmmResourceInfo class /// @param[in] Plane: Plane for which the offset is needed /// @return X offset ///////////////////////////////////////////////////////////////////////////////////// GMM_GFX_SIZE_T GMM_STDCALL GmmResGetPlanarGetXOffset(GMM_RESOURCE_INFO *pGmmResource, GMM_YUV_PLANE Plane) { __GMM_ASSERT(pGmmResource); return pGmmResource->GetPlanarXOffset(Plane); } ///////////////////////////////////////////////////////////////////////////////////// /// C wrapper for GmmResourceInfoCommon::GetPlanarYOffset /// @see GmmLib::GmmResourceInfoCommon::GetPlanarYOffset() /// /// @param[in] pGmmResource: Pointer to GmmResourceInfo class /// @param[in] Plane: Plane for which the offset is needed /// @return Y offset ///////////////////////////////////////////////////////////////////////////////////// GMM_GFX_SIZE_T GMM_STDCALL GmmResGetPlanarGetYOffset(GMM_RESOURCE_INFO *pGmmResource, GMM_YUV_PLANE Plane) { __GMM_ASSERT(pGmmResource); return pGmmResource->GetPlanarYOffset(Plane); } ///////////////////////////////////////////////////////////////////////////////////// /// C wrapper for GmmResourceInfoCommon::GetPlanarAuxOffset /// @see GmmLib::GmmResourceInfoCommon::GetPlanarAuxOffset() /// /// @param[in] pGmmResource: Pointer to GmmResourceInfo class /// @param[in] Plane: Plane for which the offset is needed /// @return Y offset ///////////////////////////////////////////////////////////////////////////////////// GMM_GFX_SIZE_T GMM_STDCALL GmmResGetPlanarAuxOffset(GMM_RESOURCE_INFO *pGmmResource, uint32_t ArrayIndex, GMM_UNIFIED_AUX_TYPE AuxType) { __GMM_ASSERT(pGmmResource); return pGmmResource->GetPlanarAuxOffset(ArrayIndex, AuxType); } ///////////////////////////////////////////////////////////////////////////////////// /// C wrapper for GmmResourceInfoCommon::SetGmmLibContext /// @see GmmLib::GmmResourceInfoCommon::SetGmmLibContext() /// /// @param[in] pGmmResource: Pointer to GmmResourceInfo class /// @param[in] pLibContext: Pointer to GmmLibContext ///////////////////////////////////////////////////////////////////////////////////// void GMM_STDCALL GmmResSetLibContext(GMM_RESOURCE_INFO *pGmmResource, void *pLibContext) { if(pGmmResource) { pGmmResource->SetGmmLibContext(pLibContext); } } ///////////////////////////////////////////////////////////////////////////////////// /// C wrapper for GmmResourceInfoCommon::IsResourceMappedCompressible /// @see GmmLib::GmmResourceInfoCommon::IsResourceMappedCompressible() /// /// @param[in] pGmmResource: Pointer to GmmResourceInfo class ///////////////////////////////////////////////////////////////////////////////////// uint32_t GMM_STDCALL GmmResIsMappedCompressible(GMM_RESOURCE_INFO *pGmmResource) { return pGmmResource->IsResourceMappedCompressible(); } //============================================================================= // // Function: __CanSupportStdTiling // // Desc: Verifies texture parameters can support StdTiling // // Parameters: // GMM_TEXTURE_INFO& Surf // // Returns: // //----------------------------------------------------------------------------- uint8_t __CanSupportStdTiling(GMM_TEXTURE_INFO Surf, GMM_LIB_CONTEXT *pGmmLibContext) { const __GMM_PLATFORM_RESOURCE *pPlatformResource = GMM_OVERRIDE_PLATFORM_INFO(&Surf, pGmmLibContext); // SKL+ Tiled Resource Mode Restrictions if((Surf.Flags.Info.TiledYf || Surf.Flags.Info.TiledYs) && !((GFX_GET_CURRENT_RENDERCORE(pPlatformResource->Platform) >= IGFX_GEN9_CORE) && // TiledY must be set unless 1D surface. ((Surf.Flags.Info.TiledY && (Surf.Type != RESOURCE_1D)) || (Surf.Flags.Info.Linear && (Surf.Type == RESOURCE_1D || Surf.Type == RESOURCE_BUFFER))) && // 8, 16, 32, 64, or 128 bpp ((!GmmIsCompressed(pGmmLibContext, Surf.Format) && ((Surf.BitsPerPixel == 8) || (Surf.BitsPerPixel == 16) || (Surf.BitsPerPixel == 32) || (Surf.BitsPerPixel == 64) || (Surf.BitsPerPixel == 128))) || // Compressed Modes: BC*, ETC*, EAC*, ASTC* (GmmIsCompressed(pGmmLibContext, Surf.Format) && (Surf.Format != GMM_FORMAT_FXT1))))) /* Not currently supported... // YCRCB* Formats GmmIsYUVPacked(Surf.Format) */ { return 0; } return 1; } gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/Resource/GmmResourceInfoCommon.cpp000066400000000000000000002656771466655022700266120ustar00rootroot00000000000000/*============================================================================== Copyright(c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ============================================================================*/ #include "Internal/Common/GmmLibInc.h" ///////////////////////////////////////////////////////////////////////////////////// /// Returns indication of whether resource is eligible for 64KB pages or not. /// On Windows, UMD must call this api after GmmResCreate() /// @return 1/0 ///////////////////////////////////////////////////////////////////////////////////// uint8_t GMM_STDCALL GmmLib::GmmResourceInfoCommon::Is64KBPageSuitable() { bool Ignore64KBPadding = false; //!!!! DO NOT USE GetSizeSurface() as it returns the padded size and not natural size. GMM_GFX_SIZE_T Size = Surf.Size + AuxSurf.Size + AuxSecSurf.Size; __GMM_ASSERT(Size); // All ESM resources and VirtuaPadding are exempt from 64KB paging if(Surf.Flags.Info.ExistingSysMem || Surf.Flags.Info.XAdapter || Surf.Flags.Gpu.CameraCapture || Surf.Flags.Info.KernelModeMapped || (Surf.Flags.Gpu.S3d && !Surf.Flags.Gpu.S3dDx && !GetGmmLibContext()->GetSkuTable().FtrDisplayEngineS3d) #if(LHDM) || (Surf.Flags.Info.AllowVirtualPadding && ExistingSysMem.hParentAllocation) #endif ) { Ignore64KBPadding = true; } if(GetGmmLibContext()->GetSkuTable().FtrLocalMemory) { Ignore64KBPadding |= (Surf.Flags.Info.Shared && !Surf.Flags.Info.NotLockable); Ignore64KBPadding |= ((GetGmmLibContext()->GetSkuTable().FtrLocalMemoryAllows4KB) && Surf.Flags.Info.NoOptimizationPadding); Ignore64KBPadding |= ((GetGmmLibContext()->GetSkuTable().FtrLocalMemoryAllows4KB || Surf.Flags.Info.NonLocalOnly) && (((Size * (100 + (GMM_GFX_SIZE_T)GetGmmLibContext()->GetAllowedPaddingFor64KbPagesPercentage())) / 100) < GFX_ALIGN(Size, GMM_KBYTE(64)))); } else { // The final padded size cannot be larger then a set percentage of the original size if((Surf.Flags.Info.NoOptimizationPadding && !GFX_IS_ALIGNED(Size, GMM_KBYTE(64))) /*Surface is not 64kb aligned*/ || (!Surf.Flags.Info.NoOptimizationPadding && (((Size * (100 + (GMM_GFX_SIZE_T)GetGmmLibContext()->GetAllowedPaddingFor64KbPagesPercentage())) / 100) < GFX_ALIGN(Size, GMM_KBYTE(64)))) /*10% padding TBC */) { Ignore64KBPadding |= true; } } // If 64KB paging is enabled pad out the resource to 64KB alignment if(GetGmmLibContext()->GetSkuTable().FtrWddm2_1_64kbPages && // Ignore the padding for the above VirtualPadding or ESM cases (!Ignore64KBPadding) && // Resource must be 64KB aligned (GFX_IS_ALIGNED(Surf.Alignment.BaseAlignment, GMM_KBYTE(64)) || // Or must be aligned to a factor of 64KB (Surf.Alignment.BaseAlignment == GMM_KBYTE(32)) || (Surf.Alignment.BaseAlignment == GMM_KBYTE(16)) || (Surf.Alignment.BaseAlignment == GMM_KBYTE(8)) || (Surf.Alignment.BaseAlignment == GMM_KBYTE(4)))) { return 1; } return 0; } ///////////////////////////////////////////////////////////////////////////////////// /// Allows clients to "create" any type of resource. This function does not /// allocate any memory for the resource. It just calculates the various parameters /// which are useful for the client and can be queried using other functions. /// /// @param[in] GmmLib Context: Reference to ::GmmLibContext /// @param[in] CreateParams: Flags which specify what sort of resource to create /// /// @return ::GMM_STATUS ///////////////////////////////////////////////////////////////////////////////////// GMM_STATUS GMM_STDCALL GmmLib::GmmResourceInfoCommon::Create(GMM_RESCREATE_PARAMS &CreateParams) { GMM_STATUS Status = GMM_ERROR; // ToDo: Only Vk is using this Create API directly. Derive the GmmLibCOntext from the ClientContext stored in // ResInfo object. Status = Create(*(reinterpret_cast(pClientContext)->GetLibContext()), CreateParams); return Status; } ///////////////////////////////////////////////////////////////////////////////////// /// Allows clients to "create" Custom memory layout received from the App as user pointer or DMABUF // This function does not allocate any memory for the resource. It just calculates/ populates the various parameters /// which are useful for the client and can be queried using other functions. /// /// @param[in] GmmLib Context: Reference to ::GmmLibContext /// @param[in] CreateParams: Flags which specify what sort of resource to create /// /// @return ::GMM_STATUS ///////////////////////////////////////////////////////////////////////////////////// GMM_STATUS GMM_STDCALL GmmLib::GmmResourceInfoCommon::CreateCustomRes(Context &GmmLibContext, GMM_RESCREATE_CUSTOM_PARAMS &CreateParams) { const GMM_PLATFORM_INFO *pPlatform; GMM_STATUS Status = GMM_ERROR; GMM_TEXTURE_CALC * pTextureCalc = NULL; uint32_t BitsPerPixel, i; GMM_DPF_ENTER; GET_GMM_CLIENT_TYPE(pClientContext, ClientType); pGmmUmdLibContext = reinterpret_cast(&GmmLibContext); __GMM_ASSERTPTR(pGmmUmdLibContext, GMM_ERROR); if((CreateParams.Format > GMM_FORMAT_INVALID) && (CreateParams.Format < GMM_RESOURCE_FORMATS)) { BitsPerPixel = GetGmmLibContext()->GetPlatformInfo().FormatTable[CreateParams.Format].Element.BitsPer; } else { GMM_ASSERTDPF(0, "Format Error"); Status = GMM_INVALIDPARAM; goto ERROR_CASE; } pPlatform = GMM_OVERRIDE_PLATFORM_INFO(&Surf, GetGmmLibContext()); pTextureCalc = GMM_OVERRIDE_TEXTURE_CALC(&Surf, GetGmmLibContext()); Surf.Type = CreateParams.Type; Surf.Format = CreateParams.Format; Surf.BaseWidth = CreateParams.BaseWidth64; Surf.BaseHeight = CreateParams.BaseHeight; Surf.Flags = CreateParams.Flags; Surf.CachePolicy.Usage = CreateParams.Usage; Surf.Pitch = CreateParams.Pitch; Surf.Size = CreateParams.Size; Surf.Alignment.BaseAlignment = CreateParams.BaseAlignment; Surf.MaxLod = 1; Surf.ArraySize = 1; Surf.CpTag = CreateParams.CpTag; #if(_DEBUG || _RELEASE_INTERNAL) Surf.Platform = GetGmmLibContext()->GetPlatformInfo().Platform; #endif Surf.BitsPerPixel = BitsPerPixel; Surf.Alignment.QPitch = (GMM_GLOBAL_GFX_SIZE_T)(Surf.Pitch * Surf.BaseHeight); pTextureCalc->SetTileMode(&Surf); if(GmmIsPlanar(Surf.Format)) { pTextureCalc->SetPlanarOffsetInfo(&Surf, CreateParams); if (Surf.ArraySize > 1) { //Surf.OffsetInfo.Plane.ArrayQPitch = Surf.Size; //Not required as this new interface doesn't support arrayed surfaces. } UpdateUnAlignedParams(); } switch(Surf.Type) { case RESOURCE_1D: case RESOURCE_2D: case RESOURCE_PRIMARY: case RESOURCE_SHADOW: case RESOURCE_STAGING: case RESOURCE_GDI: case RESOURCE_NNDI: case RESOURCE_HARDWARE_MBM: case RESOURCE_OVERLAY_INTERMEDIATE_SURFACE: case RESOURCE_IFFS_MAPTOGTT: #if _WIN32 case RESOURCE_WGBOX_ENCODE_DISPLAY: case RESOURCE_WGBOX_ENCODE_REFERENCE: #endif { if (Surf.ArraySize > 1) { // Surf.OffsetInfo.Texture2DOffsetInfo.ArrayQPitchRender = // Surf.OffsetInfo.Texture2DOffsetInfo.ArrayQPitchLock = Surf.Pitch * Surf.BaseHeight; //Not required as this new interface doesn't support arrayed surfaces. } for(i = 0; i <= Surf.MaxLod; i++) { Surf.OffsetInfo.Texture2DOffsetInfo.Offset[i] = 0; } break; } default: { GMM_ASSERTDPF(0, "GmmTexAlloc: Unknown surface type!"); Status = GMM_INVALIDPARAM; goto ERROR_CASE; ; } }; GMM_DPF_EXIT; return GMM_SUCCESS; ERROR_CASE: //Zero out all the members new(this) GmmResourceInfoCommon(); GMM_DPF_EXIT; return Status; } #ifndef __GMM_KMD__ ///////////////////////////////////////////////////////////////////////////////////// /// Allows clients to "create" Custom memory layout received from the App as user pointer or DMABUF // This function does not allocate any memory for the resource. It just calculates/ populates the various parameters /// which are useful for the client and can be queried using other functions. /// /// @param[in] GmmLib Context: Reference to ::GmmLibContext /// @param[in] CreateParams: Flags which specify what sort of resource to create /// /// @return ::GMM_STATUS ///////////////////////////////////////////////////////////////////////////////////// GMM_STATUS GMM_STDCALL GmmLib::GmmResourceInfoCommon::CreateCustomRes_2(Context &GmmLibContext, GMM_RESCREATE_CUSTOM_PARAMS_2 &CreateParams) { const GMM_PLATFORM_INFO *pPlatform; GMM_STATUS Status = GMM_ERROR; GMM_TEXTURE_CALC * pTextureCalc = NULL; uint32_t BitsPerPixel, i; GMM_DPF_ENTER; GET_GMM_CLIENT_TYPE(pClientContext, ClientType); pGmmUmdLibContext = reinterpret_cast(&GmmLibContext); __GMM_ASSERTPTR(pGmmUmdLibContext, GMM_ERROR); if((CreateParams.Format > GMM_FORMAT_INVALID) && (CreateParams.Format < GMM_RESOURCE_FORMATS)) { BitsPerPixel = GetGmmLibContext()->GetPlatformInfo().FormatTable[CreateParams.Format].Element.BitsPer; } else { GMM_ASSERTDPF(0, "Format Error"); Status = GMM_INVALIDPARAM; goto ERROR_CASE; } pPlatform = GMM_OVERRIDE_PLATFORM_INFO(&Surf, GetGmmLibContext()); pTextureCalc = GMM_OVERRIDE_TEXTURE_CALC(&Surf, GetGmmLibContext()); Surf.Type = CreateParams.Type; Surf.Format = CreateParams.Format; Surf.BaseWidth = CreateParams.BaseWidth64; Surf.BaseHeight = CreateParams.BaseHeight; Surf.Flags = CreateParams.Flags; Surf.CachePolicy.Usage = CreateParams.Usage; Surf.Pitch = CreateParams.Pitch; Surf.Size = CreateParams.Size; Surf.Alignment.BaseAlignment = CreateParams.BaseAlignment; Surf.MaxLod = 1; Surf.ArraySize = 1; Surf.CpTag = CreateParams.CpTag; #if(_DEBUG || _RELEASE_INTERNAL) Surf.Platform = GetGmmLibContext()->GetPlatformInfo().Platform; #endif Surf.BitsPerPixel = BitsPerPixel; Surf.Alignment.QPitch = (GMM_GLOBAL_GFX_SIZE_T)(Surf.Pitch * Surf.BaseHeight); pTextureCalc->SetTileMode(&Surf); if(GmmIsPlanar(Surf.Format)) { pTextureCalc->SetPlanarOffsetInfo_2(&Surf, CreateParams); if(Surf.ArraySize > 1) { //Not required as this new interface doesn't support arrayed surfaces. } UpdateUnAlignedParams(); } switch(Surf.Type) { case RESOURCE_1D: case RESOURCE_2D: case RESOURCE_PRIMARY: case RESOURCE_SHADOW: case RESOURCE_STAGING: case RESOURCE_GDI: case RESOURCE_NNDI: case RESOURCE_HARDWARE_MBM: case RESOURCE_OVERLAY_INTERMEDIATE_SURFACE: case RESOURCE_IFFS_MAPTOGTT: #if _WIN32 case RESOURCE_WGBOX_ENCODE_DISPLAY: case RESOURCE_WGBOX_ENCODE_REFERENCE: #endif { if(Surf.ArraySize > 1) { //Not required as this new interface doesn't support arrayed surfaces. } for(i = 0; i <= Surf.MaxLod; i++) { Surf.OffsetInfo.Texture2DOffsetInfo.Offset[i] = 0; } break; } default: { GMM_ASSERTDPF(0, "GmmTexAlloc: Unknown surface type!"); Status = GMM_INVALIDPARAM; goto ERROR_CASE; ; } }; if(Surf.Flags.Gpu.UnifiedAuxSurface || Surf.Flags.Gpu.CCS) { if(GetGmmLibContext()->GetSkuTable().FtrLinearCCS) { AuxSurf.Flags.Gpu.__NonMsaaLinearCCS = 1; } AuxSurf.Flags.Info.TiledW = 0; AuxSurf.Flags.Info.TiledYf = 0; AuxSurf.Flags.Info.TiledX = 0; AuxSurf.Flags.Info.Linear = 1; GMM_SET_64KB_TILE(AuxSurf.Flags, 0, GetGmmLibContext()); GMM_SET_4KB_TILE(AuxSurf.Flags, 0, GetGmmLibContext()); AuxSurf.ArraySize = 1; AuxSurf.BitsPerPixel = 8; if(GmmIsPlanar(CreateParams.Format) || GmmIsUVPacked(CreateParams.Format)) { AuxSurf.OffsetInfo.Plane.X[GMM_PLANE_Y] = CreateParams.AuxSurf.PlaneOffset.X[GMM_PLANE_Y]; AuxSurf.OffsetInfo.Plane.Y[GMM_PLANE_Y] = CreateParams.AuxSurf.PlaneOffset.Y[GMM_PLANE_Y]; AuxSurf.OffsetInfo.Plane.X[GMM_PLANE_U] = CreateParams.AuxSurf.PlaneOffset.X[GMM_PLANE_U]; AuxSurf.OffsetInfo.Plane.Y[GMM_PLANE_U] = CreateParams.AuxSurf.PlaneOffset.Y[GMM_PLANE_U]; AuxSurf.OffsetInfo.Plane.X[GMM_PLANE_V] = CreateParams.AuxSurf.PlaneOffset.X[GMM_PLANE_V]; AuxSurf.OffsetInfo.Plane.Y[GMM_PLANE_V] = CreateParams.AuxSurf.PlaneOffset.Y[GMM_PLANE_V]; AuxSurf.OffsetInfo.Plane.ArrayQPitch = CreateParams.AuxSurf.Size; } AuxSurf.Size = CreateParams.AuxSurf.Size; AuxSurf.Pitch = CreateParams.AuxSurf.Pitch; AuxSurf.Type = RESOURCE_BUFFER; AuxSurf.Alignment = {0}; AuxSurf.Alignment.QPitch = GFX_ULONG_CAST(AuxSurf.Size); AuxSurf.Alignment.BaseAlignment = CreateParams.AuxSurf.BaseAlignment; //TODO: TiledResource? AuxSurf.Size = GFX_ALIGN(AuxSurf.Size, PAGE_SIZE); //page-align final size if(AuxSurf.Flags.Gpu.TiledResource) { AuxSurf.Alignment.BaseAlignment = GMM_KBYTE(64); //TODO: TiledResource? AuxSurf.Size = GFX_ALIGN(AuxSurf.Size, GMM_KBYTE(64)); //page-align final size } //Clear compression request in CCS AuxSurf.Flags.Info.RenderCompressed = 0; AuxSurf.Flags.Info.MediaCompressed = 0; AuxSurf.Flags.Info.RedecribedPlanes = 0; pTextureCalc->SetTileMode(&AuxSurf); AuxSurf.UnpaddedSize = AuxSurf.Size; } GMM_DPF_EXIT; return GMM_SUCCESS; ERROR_CASE: //Zero out all the members new(this) GmmResourceInfoCommon(); GMM_DPF_EXIT; return Status; } #endif ///////////////////////////////////////////////////////////////////////////////////// /// Allows clients to "create" any type of resource. This function does not /// allocate any memory for the resource. It just calculates the various parameters /// which are useful for the client and can be queried using other functions. /// /// @param[in] GmmLib Context: Reference to ::GmmLibContext /// @param[in] CreateParams: Flags which specify what sort of resource to create /// /// @return ::GMM_STATUS ///////////////////////////////////////////////////////////////////////////////////// GMM_STATUS GMM_STDCALL GmmLib::GmmResourceInfoCommon::Create(Context &GmmLibContext, GMM_RESCREATE_PARAMS &CreateParams) { const GMM_PLATFORM_INFO *pPlatform; GMM_STATUS Status = GMM_ERROR; GMM_TEXTURE_CALC * pTextureCalc = NULL; GMM_DPF_ENTER; GET_GMM_CLIENT_TYPE(pClientContext, ClientType); pGmmUmdLibContext = reinterpret_cast(&GmmLibContext); __GMM_ASSERTPTR(pGmmUmdLibContext, GMM_ERROR); if(CreateParams.Flags.Info.ExistingSysMem && (CreateParams.Flags.Info.TiledW || CreateParams.Flags.Info.TiledX || GMM_IS_4KB_TILE(CreateParams.Flags) || GMM_IS_64KB_TILE(CreateParams.Flags))) { GMM_ASSERTDPF(0, "Tiled System Accelerated Memory not supported."); Status = GMM_INVALIDPARAM; goto ERROR_CASE; } if(!CopyClientParams(CreateParams)) { Status = GMM_INVALIDPARAM; goto ERROR_CASE; } pPlatform = GMM_OVERRIDE_PLATFORM_INFO(&Surf, GetGmmLibContext()); pTextureCalc = GMM_OVERRIDE_TEXTURE_CALC(&Surf, GetGmmLibContext()); if (!pTextureCalc) { Status = GMM_ERROR; GMM_ASSERTDPF(0, "Texture Calculation pointer is NULL."); goto ERROR_CASE; } #if defined(__GMM_KMD__) || !defined(_WIN32) if(!CreateParams.Flags.Info.ExistingSysMem) #else // TiledResource uses a private gfx alloc, which doesn't receive a WDDM CreateAllocation if(!CreateParams.Flags.Info.ExistingSysMem && (CreateParams.NoGfxMemory || CreateParams.Flags.Gpu.TiledResource)) #endif { if(!ValidateParams()) { GMM_ASSERTDPF(0, "Invalid parameter!"); Status = GMM_INVALIDPARAM; goto ERROR_CASE; } if(GMM_SUCCESS != pTextureCalc->AllocateTexture(&Surf)) { GMM_ASSERTDPF(0, "GmmTexAlloc failed!"); goto ERROR_CASE; } if(Surf.Flags.Gpu.UnifiedAuxSurface) { GMM_GFX_SIZE_T TotalSize; uint32_t Alignment; if(GMM_SUCCESS != pTextureCalc->FillTexCCS(&Surf, (AuxSecSurf.Type != RESOURCE_INVALID ? &AuxSecSurf : &AuxSurf))) { GMM_ASSERTDPF(0, "GmmTexAlloc failed!"); goto ERROR_CASE; } if(AuxSurf.Size == 0 && AuxSurf.Type != RESOURCE_INVALID && GMM_SUCCESS != pTextureCalc->AllocateTexture(&AuxSurf)) { GMM_ASSERTDPF(0, "GmmTexAlloc failed!"); goto ERROR_CASE; } AuxSurf.UnpaddedSize = AuxSurf.Size; if(Surf.Flags.Gpu.IndirectClearColor || Surf.Flags.Gpu.ColorDiscard) { if(GetGmmLibContext()->GetSkuTable().FtrFlatPhysCCS && AuxSurf.Type == RESOURCE_INVALID) { //ie only AuxType is CCS, doesn't exist with FlatCCS, enable it for CC if (!GetGmmLibContext()->GetSkuTable().FtrXe2Compression || (GetGmmLibContext()->GetSkuTable().FtrXe2Compression && (Surf.MSAA.NumSamples > 1))) { AuxSurf.Type = Surf.Type; } } if (!Surf.Flags.Gpu.TiledResource) { if (!GetGmmLibContext()->GetSkuTable().FtrXe2Compression) { AuxSurf.CCSize = PAGE_SIZE; // 128bit Float Value + 32bit RT Native Value + Padding. AuxSurf.Size += PAGE_SIZE; } else { if (Surf.MSAA.NumSamples > 1) { AuxSurf.UnpaddedSize += PAGE_SIZE; AuxSurf.Size += PAGE_SIZE; // Clear Color stored only for MSAA surfaces } } } else { if (!GetGmmLibContext()->GetSkuTable().FtrXe2Compression) { AuxSurf.CCSize = GMM_KBYTE(64); // 128bit Float Value + 32bit RT Native Value + Padding. AuxSurf.Size += GMM_KBYTE(64); } else { if (Surf.MSAA.NumSamples > 1) { AuxSurf.UnpaddedSize += GMM_KBYTE(64); AuxSurf.Size += GMM_KBYTE(64); // Clear Color stored only for MSAA surfaces, stored as part of MCS } } } } if(Surf.Flags.Gpu.ProceduralTexture) { //Do not require main surface access either in GPUVA/physical space. Surf.Size = 0; } TotalSize = Surf.Size + AuxSurf.Size; //Not including AuxSecSurf size, multi-Aux surface isn't supported for displayables Alignment = GFX_ULONG_CAST(Surf.Pitch * pPlatform->TileInfo[Surf.TileMode].LogicalTileHeight); // We need to pad the aux size to the size of the paired surface's tile row (i.e. Pitch * TileHeight) to // ensure the entire surface can be described with a constant pitch (for GGTT aliasing, clean FENCE'ing and // AcquireSwizzlingRange, even though the aux isn't intentionally part of such fencing). if(Surf.Flags.Gpu.FlipChain && (!__GMM_IS_ALIGN(TotalSize, Alignment))) { AuxSurf.Size += (GFX_ALIGN_NP2(TotalSize, Alignment) - TotalSize); } if((Surf.Size + AuxSurf.Size + AuxSecSurf.Size) > (GMM_GFX_SIZE_T)(pPlatform->SurfaceMaxSize)) { GMM_ASSERTDPF(0, "Surface too large!"); goto ERROR_CASE; } } } if(Surf.Flags.Info.ExistingSysMem) { Surf.ExistingSysMem.IsGmmAllocated = (CreateParams.pExistingSysMem && CreateParams.ExistingSysMemSize) ? false : true; if(!Surf.ExistingSysMem.IsGmmAllocated) { Surf.ExistingSysMem.IsPageAligned = (((CreateParams.pExistingSysMem & (PAGE_SIZE - 1)) == 0) && (((CreateParams.pExistingSysMem + CreateParams.ExistingSysMemSize) & (PAGE_SIZE - 1)) == 0)) ? true : false; } if(!ValidateParams()) { GMM_ASSERTDPF(0, "Invalid parameter!"); goto ERROR_CASE; } // Get surface Gfx memory size required. if(GMM_SUCCESS != pTextureCalc->AllocateTexture(&Surf)) { GMM_ASSERTDPF(0, "GmmTexAlloc failed!"); goto ERROR_CASE; } if(CreateParams.pExistingSysMem && CreateParams.ExistingSysMemSize) { // Client provided own memory and is not assumed to be Gfx aligned ExistingSysMem.IsGmmAllocated = 0; ExistingSysMem.pExistingSysMem = CreateParams.pExistingSysMem; ExistingSysMem.Size = CreateParams.ExistingSysMemSize; // An upper dword of 0xffffffff is invalid and may mean the address // was sign extended or came from a rogue UMD. In either case // we can truncate the address down to 32 bits prevent attempts // to access an invalid address range. if((ExistingSysMem.pExistingSysMem & (0xffffffff00000000ull)) == (0xffffffff00000000ull)) { ExistingSysMem.pExistingSysMem &= 0xffffffff; } //Align the base address to new ESM requirements. if(!Surf.ExistingSysMem.IsPageAligned) { if(GMM_SUCCESS != ApplyExistingSysMemRestrictions()) { GMM_ASSERTDPF(0, "Malloc'ed Sys Mem too small for gfx surface!"); goto ERROR_CASE; } } else { ExistingSysMem.pVirtAddress = ExistingSysMem.pGfxAlignedVirtAddress = CreateParams.pExistingSysMem; } if((ExistingSysMem.pVirtAddress + Surf.Size) > (CreateParams.pExistingSysMem + ExistingSysMem.Size)) { GMM_ASSERTDPF(0, "Malloc'ed Sys Mem too small for gfx surface"); goto ERROR_CASE; } } else { __GMM_BUFFER_TYPE Restrictions = {0}; ExistingSysMem.IsGmmAllocated = 1; Surf.ExistingSysMem.IsPageAligned = 1; // Adjust memory size to compensate for Gfx alignment. pTextureCalc->GetResRestrictions(&Surf, Restrictions); ExistingSysMem.Size = Restrictions.Alignment + Surf.Size; ExistingSysMem.pVirtAddress = (uint64_t)GMM_MALLOC(GFX_ULONG_CAST(ExistingSysMem.Size)); if(!ExistingSysMem.pVirtAddress) { GMM_ASSERTDPF(0, "Failed to allocate System Accelerated Memory."); goto ERROR_CASE; } else { ExistingSysMem.pGfxAlignedVirtAddress = (uint64_t)GFX_ALIGN(ExistingSysMem.pVirtAddress, Restrictions.Alignment); } } } if(Is64KBPageSuitable() && GetGmmLibContext()->GetSkuTable().FtrLocalMemory) { // BaseAlignment can be greater than 64KB and needs to be aligned to 64KB Surf.Alignment.BaseAlignment = GFX_MAX(GFX_ALIGN(Surf.Alignment.BaseAlignment, GMM_KBYTE(64)), GMM_KBYTE(64)); } GMM_DPF_EXIT; return GMM_SUCCESS; ERROR_CASE: //Zero out all the members new(this) GmmResourceInfoCommon(); if(CreateParams.pPreallocatedResInfo) { this->GetResFlags().Info.__PreallocatedResInfo = 1; // Set flag if PreAllocated ResInfo has been set by the Client. } GMM_DPF_EXIT; return Status; } void GmmLib::GmmResourceInfoCommon::UpdateUnAlignedParams() { uint32_t YHeight = 0, VHeight = 0, Height = 0; uint32_t WidthBytesPhysical = GFX_ULONG_CAST(Surf.BaseWidth) * Surf.BitsPerPixel >> 3; GMM_TEXTURE_CALC *pTextureCalc = GMM_OVERRIDE_TEXTURE_CALC(&Surf, GetGmmLibContext()); __GMM_ASSERTPTR(((Surf.TileMode < GMM_TILE_MODES) && (Surf.TileMode >= TILE_NONE)), VOIDRETURN); GMM_DPF_ENTER; Height = Surf.BaseHeight; switch(Surf.Format) { case GMM_FORMAT_IMC1: // IMC1 = IMC3 with Swapped U/V case GMM_FORMAT_IMC3: case GMM_FORMAT_MFX_JPEG_YUV420: // Same as IMC3. // YYYYYYYY // YYYYYYYY // YYYYYYYY // YYYYYYYY // UUUU // UUUU // VVVV // VVVV case GMM_FORMAT_MFX_JPEG_YUV422V: // Similar to IMC3 but U/V are full width. // YYYYYYYY // YYYYYYYY // YYYYYYYY // YYYYYYYY // UUUUUUUU // UUUUUUUU // VVVVVVVV // VVVVVVVV { YHeight = GFX_ALIGN(Surf.BaseHeight, GMM_IMCx_PLANE_ROW_ALIGNMENT); VHeight = GFX_ALIGN(GFX_CEIL_DIV(Surf.BaseHeight, 2), GMM_IMCx_PLANE_ROW_ALIGNMENT); break; } case GMM_FORMAT_MFX_JPEG_YUV411R_TYPE: //Similar to IMC3 but U/V are quarther height and full width. //YYYYYYYY //YYYYYYYY //YYYYYYYY //YYYYYYYY //UUUUUUUU //VVVVVVVV { YHeight = GFX_ALIGN(Surf.BaseHeight, GMM_IMCx_PLANE_ROW_ALIGNMENT); VHeight = GFX_ALIGN(GFX_CEIL_DIV(Surf.BaseHeight, 4), GMM_IMCx_PLANE_ROW_ALIGNMENT); break; } case GMM_FORMAT_MFX_JPEG_YUV411: // Similar to IMC3 but U/V are quarter width and full height. // YYYYYYYY // YYYYYYYY // YYYYYYYY // YYYYYYYY // UU // UU // UU // UU // VV // VV // VV // VV case GMM_FORMAT_MFX_JPEG_YUV422H: // Similar to IMC3 but U/V are full height. // YYYYYYYY // YYYYYYYY // YYYYYYYY // YYYYYYYY // UUUU // UUUU // UUUU // UUUU // VVVV // VVVV // VVVV // VVVV case GMM_FORMAT_BGRP: case GMM_FORMAT_RGBP: case GMM_FORMAT_MFX_JPEG_YUV444: // Similar to IMC3 but U/V are full size. // YYYYYYYY // YYYYYYYY // YYYYYYYY // YYYYYYYY // UUUUUUUU // UUUUUUUU // UUUUUUUU // UUUUUUUU // VVVVVVVV // VVVVVVVV // VVVVVVVV // VVVVVVVV { YHeight = GFX_ALIGN(Surf.BaseHeight, GMM_IMCx_PLANE_ROW_ALIGNMENT); VHeight = GFX_ALIGN(Surf.BaseHeight, GMM_IMCx_PLANE_ROW_ALIGNMENT); break; } case GMM_FORMAT_IMC2: // IMC2 = IMC4 with Swapped U/V case GMM_FORMAT_IMC4: { // YYYYYYYY // YYYYYYYY // YYYYYYYY // YYYYYYYY // UUUUVVVV // UUUUVVVV __GMM_ASSERT((Surf.Pitch & 1) == 0); YHeight = GFX_ALIGN(Surf.BaseHeight, GMM_IMCx_PLANE_ROW_ALIGNMENT); VHeight = GFX_CEIL_DIV(YHeight, 2); break; } case GMM_FORMAT_I420: // I420 = IYUV case GMM_FORMAT_IYUV: // I420/IYUV = YV12 with Swapped U/V case GMM_FORMAT_YV12: case GMM_FORMAT_YVU9: { // YYYYYYYY // YYYYYYYY // YYYYYYYY // YYYYYYYY // VVVVVV.. <-- V and U planes follow the Y plane, as linear // ..UUUUUU arrays--without respect to pitch. uint32_t YSize, YVSizeRShift, VSize, UOffset; uint32_t YSizeForUVPurposes, YSizeForUVPurposesDimensionalAlignment; YSize = GFX_ULONG_CAST(Surf.Pitch) * Surf.BaseHeight; // YVU9 has one U/V pixel for each 4x4 Y block. // The others have one U/V pixel for each 2x2 Y block. // YVU9 has a Y:V size ratio of 16 (4x4 --> 1). // The others have a ratio of 4 (2x2 --> 1). YVSizeRShift = (Surf.Format != GMM_FORMAT_YVU9) ? 2 : 4; // If a Y plane isn't fully-aligned to its Y-->U/V block size, the // extra/unaligned Y pixels still need corresponding U/V pixels--So // for the purpose of computing the UVSize, we must consider a // dimensionally "rounded-up" YSize. (E.g. a 13x5 YVU9 Y plane would // require 4x2 U/V planes--the same UVSize as a fully-aligned 16x8 Y.) YSizeForUVPurposesDimensionalAlignment = (Surf.Format != GMM_FORMAT_YVU9) ? 2 : 4; YSizeForUVPurposes = GFX_ALIGN(GFX_ULONG_CAST(Surf.Pitch), YSizeForUVPurposesDimensionalAlignment) * GFX_ALIGN(Surf.BaseHeight, YSizeForUVPurposesDimensionalAlignment); VSize = (YSizeForUVPurposes >> YVSizeRShift); YHeight = GFX_CEIL_DIV(YSize + 2 * VSize, WidthBytesPhysical); break; } case GMM_FORMAT_NV12: case GMM_FORMAT_NV21: case GMM_FORMAT_NV11: case GMM_FORMAT_P010: case GMM_FORMAT_P012: case GMM_FORMAT_P016: case GMM_FORMAT_P208: { // YYYYYYYY // YYYYYYYY // YYYYYYYY // YYYYYYYY // [UV-Packing] YHeight = GFX_ALIGN(Height, __GMM_EVEN_ROW); if((Surf.Format == GMM_FORMAT_NV12) || (Surf.Format == GMM_FORMAT_NV21) || (Surf.Format == GMM_FORMAT_P010) || (Surf.Format == GMM_FORMAT_P012) || (Surf.Format == GMM_FORMAT_P016)) { VHeight = GFX_CEIL_DIV(Height, 2); } else { VHeight = YHeight; // U/V plane is same as Y } break; } default: { GMM_ASSERTDPF(0, "Unknown Video Format U\n"); break; } } pTextureCalc->SetPlaneUnAlignedTexOffsetInfo(&Surf, YHeight, VHeight); } ///////////////////////////////////////////////////////////////////////////////////// /// Returns downscaled width for fast clear of given subresource /// @param[in] uint32_t : MipLevel /// @return Width ///////////////////////////////////////////////////////////////////////////////////// uint64_t GmmLib::GmmResourceInfoCommon::GetFastClearWidth(uint32_t MipLevel) { uint64_t width = 0; uint64_t mipWidth = GetMipWidth(MipLevel); uint32_t numSamples = GetNumSamples(); GMM_TEXTURE_CALC *pTextureCalc; pTextureCalc = GMM_OVERRIDE_TEXTURE_CALC(&Surf, GetGmmLibContext()); if(numSamples == 1) { width = pTextureCalc->ScaleFCRectWidth(&Surf, mipWidth); } else if(numSamples == 2 || numSamples == 4) { if (GetGmmLibContext()->GetSkuTable().FtrXe2Compression) { width = GFX_ALIGN(mipWidth, 64) / 64; } else { width = GFX_ALIGN(mipWidth, 8) / 8; } } else if(numSamples == 8) { if (GetGmmLibContext()->GetSkuTable().FtrXe2Compression) { width = GFX_ALIGN(mipWidth, 16) / 16; } else { width = GFX_ALIGN(mipWidth, 2) / 2; } } else // numSamples == 16 { if (GetGmmLibContext()->GetSkuTable().FtrXe2Compression) { width = GFX_ALIGN(mipWidth, 8) / 8; } else { width = mipWidth; } } return width; } ///////////////////////////////////////////////////////////////////////////////////// /// Returns downscaled height for fast clear of given subresource /// @param[in] uint32_t : MipLevel /// @return height ///////////////////////////////////////////////////////////////////////////////////// uint32_t GmmLib::GmmResourceInfoCommon::GetFastClearHeight(uint32_t MipLevel) { uint32_t height = 0; uint32_t mipHeight = GetMipHeight(MipLevel); uint32_t numSamples = GetNumSamples(); GMM_TEXTURE_CALC *pTextureCalc; pTextureCalc = GMM_OVERRIDE_TEXTURE_CALC(&Surf, GetGmmLibContext()); if(numSamples == 1) { height = pTextureCalc->ScaleFCRectHeight(&Surf, mipHeight); } else { if (GetGmmLibContext()->GetSkuTable().FtrXe2Compression) { height = GFX_ALIGN(mipHeight, 4) / 4; } else { height = GFX_ALIGN(mipHeight, 2) / 2; } } return height; } ///////////////////////////////////////////////////////////////////////////////////// /// Returns 2D Surface width to be used for fast clear for a given 3D surface /// @param[in] uint32_t : MipLevel /// @return height ///////////////////////////////////////////////////////////////////////////////////// uint64_t GmmLib::GmmResourceInfoCommon::Get2DFastClearSurfaceWidthFor3DSurface(uint32_t MipLevel) { uint64_t width = 0; uint64_t mipWidth = GetMipWidth(MipLevel); GMM_TEXTURE_CALC *pTextureCalc; pTextureCalc = GMM_OVERRIDE_TEXTURE_CALC(&Surf, GetGmmLibContext()); width = pTextureCalc->Get2DFCSurfaceWidthFor3DSurface(&Surf, mipWidth); return width; } uint64_t GmmLib::GmmResourceInfoCommon::Get2DFastClearSurfaceHeightFor3DSurface(uint32_t MipLevel) { uint64_t height = 0; uint32_t mipHeight = GetMipHeight(MipLevel); uint32_t mipDepth = GetMipDepth(MipLevel); GMM_TEXTURE_CALC *pTextureCalc; pTextureCalc = GMM_OVERRIDE_TEXTURE_CALC(&Surf, GetGmmLibContext()); height = pTextureCalc->Get2DFCSurfaceHeightFor3DSurface(&Surf, mipHeight, mipDepth); return height; } ///////////////////////////////////////////////////////////////////////////////////// /// Returns the Platform info. If Platform has been overriden by the clients, then /// it returns the overriden Platform Info struct. /// @return Reference to the relevent ::GMM_PLATFORM_INFO ///////////////////////////////////////////////////////////////////////////////////// const GMM_PLATFORM_INFO &GmmLib::GmmResourceInfoCommon::GetPlatformInfo() { #if(defined(__GMM_KMD__) && (_DEBUG || _RELEASE_INTERNAL)) if(GFX_GET_CURRENT_RENDERCORE(Surf.Platform) != GFX_GET_CURRENT_RENDERCORE(((Context *)pGmmKmdLibContext)->GetPlatformInfo().Platform)) { return ((Context *)pGmmKmdLibContext)->GetOverridePlatformInfo(); } else { return ((Context *)pGmmKmdLibContext)->GetPlatformInfo(); } #else return ((Context *)pGmmUmdLibContext)->GetPlatformInfo(); #endif } ///////////////////////////////////////////////////////////////////////////////////// /// Returns width padded to HAlign. Only called for special flags. See asserts in /// function for which surfaces are supported. /// /// @param[in] MipLevel Mip level for which the width is requested /// @return Padded Width ///////////////////////////////////////////////////////////////////////////////////// uint32_t GMM_STDCALL GmmLib::GmmResourceInfoCommon::GetPaddedWidth(uint32_t MipLevel) { GMM_TEXTURE_CALC *pTextureCalc; uint32_t AlignedWidth; GMM_GFX_SIZE_T MipWidth; uint32_t HAlign; __GMM_ASSERT(MipLevel <= Surf.MaxLod); pTextureCalc = GMM_OVERRIDE_TEXTURE_CALC(&Surf, GetGmmLibContext()); // This shall be called for Depth and Separate Stencil main surface resource // This shall be called for the Aux surfaces (MCS, CCS and Hiz) too. // MCS will have Surf.Flags.Gpu.CCS set // Hiz will have Surf.Flags.Gpu.HiZ set __GMM_ASSERT(Surf.Flags.Gpu.Depth || Surf.Flags.Gpu.SeparateStencil || Surf.Flags.Gpu.CCS || Surf.Flags.Gpu.HiZ || AuxSurf.Flags.Gpu.__MsaaTileMcs || AuxSurf.Flags.Gpu.CCS || AuxSurf.Flags.Gpu.__NonMsaaTileYCcs); MipWidth = pTextureCalc->GmmTexGetMipWidth(&Surf, MipLevel); HAlign = Surf.Alignment.HAlign; if(AuxSurf.Flags.Gpu.CCS && AuxSurf.Flags.Gpu.__NonMsaaTileYCcs) { HAlign = AuxSurf.Alignment.HAlign; } AlignedWidth = __GMM_EXPAND_WIDTH(pTextureCalc, GFX_ULONG_CAST(MipWidth), HAlign, &Surf); if(Surf.Flags.Gpu.SeparateStencil) { if(Surf.Flags.Info.TiledW) { AlignedWidth *= 2; } // Reverse MSAA Expansion //////////////////////////////////////////////// // It might seem strange that we ExpandWidth (with consideration for MSAA) // only to "reverse" the MSAA portion of the expansion...It's an order-of- // operations thing--The intention of the reversal isn't to have // disregarded the original MSAA expansion but to produce a width, that // when MSAA'ed will match the true physical width (which requires MSAA // consideration to compute). switch(Surf.MSAA.NumSamples) { case 1: break; case 2: // Same as 4x... case 4: AlignedWidth /= 2; break; case 8: // Same as 16x... case 16: AlignedWidth /= 4; break; default: __GMM_ASSERT(0); } } // CCS Aux surface, Aligned width needs to be scaled based on main surface bpp if(AuxSurf.Flags.Gpu.CCS && AuxSurf.Flags.Gpu.__NonMsaaTileYCcs) { AlignedWidth = pTextureCalc->ScaleTextureWidth(&AuxSurf, AlignedWidth); } return AlignedWidth; } ///////////////////////////////////////////////////////////////////////////////////// /// Returns height padded to VAlign. Only called for special flags. See asserts in /// function for which surfaces are supported. /// /// @param[in] MipLevel Mip level for which the height is requested /// @return Padded height ///////////////////////////////////////////////////////////////////////////////////// uint32_t GMM_STDCALL GmmLib::GmmResourceInfoCommon::GetPaddedHeight(uint32_t MipLevel) { GMM_TEXTURE_CALC *pTextureCalc; uint32_t AlignedHeight, MipHeight; uint32_t VAlign; __GMM_ASSERT(MipLevel <= Surf.MaxLod); // See note in GmmResGetPaddedWidth. __GMM_ASSERT(Surf.Flags.Gpu.Depth || Surf.Flags.Gpu.SeparateStencil || Surf.Flags.Gpu.CCS || Surf.Flags.Gpu.HiZ || AuxSurf.Flags.Gpu.__MsaaTileMcs || AuxSurf.Flags.Gpu.CCS || AuxSurf.Flags.Gpu.__NonMsaaTileYCcs); pTextureCalc = GMM_OVERRIDE_TEXTURE_CALC(&Surf, GetGmmLibContext()); MipHeight = pTextureCalc->GmmTexGetMipHeight(&Surf, MipLevel); VAlign = Surf.Alignment.VAlign; if(AuxSurf.Flags.Gpu.CCS && AuxSurf.Flags.Gpu.__NonMsaaTileYCcs) { VAlign = AuxSurf.Alignment.VAlign; } AlignedHeight = __GMM_EXPAND_HEIGHT(pTextureCalc, MipHeight, VAlign, &Surf); if(Surf.Flags.Gpu.SeparateStencil) { if(Surf.Flags.Info.TiledW) { AlignedHeight /= 2; } // Reverse MSAA Expansion //////////////////////////////////////////////// // See note in GmmResGetPaddedWidth. switch(Surf.MSAA.NumSamples) { case 1: break; case 2: break; // No height adjustment for 2x... case 4: // Same as 8x... case 8: AlignedHeight /= 2; break; case 16: AlignedHeight /= 4; break; default: __GMM_ASSERT(0); } } // CCS Aux surface, AlignedHeight needs to be scaled by 16 if(AuxSurf.Flags.Gpu.CCS && AuxSurf.Flags.Gpu.__NonMsaaTileYCcs) { AlignedHeight = pTextureCalc->ScaleTextureHeight(&AuxSurf, AlignedHeight); } return AlignedHeight; } ///////////////////////////////////////////////////////////////////////////////////// /// Returns pitch padded to VAlign. Only called for special flags. See asserts in /// function for which surfaces are supported. /// /// @param[in] MipLevel Mip level for which the pitch is requested /// @return Padded pitch ///////////////////////////////////////////////////////////////////////////////////// uint32_t GMM_STDCALL GmmLib::GmmResourceInfoCommon::GetPaddedPitch(uint32_t MipLevel) { uint32_t AlignedWidth; uint32_t AlignedPitch; uint32_t BitsPerPixel; __GMM_ASSERT(MipLevel <= Surf.MaxLod); // See note in GetPaddedWidth. AlignedWidth = GetPaddedWidth(MipLevel); BitsPerPixel = Surf.BitsPerPixel; if(AuxSurf.Flags.Gpu.CCS && AuxSurf.Flags.Gpu.__NonMsaaTileYCcs) { BitsPerPixel = 8; //Aux surface are 8bpp } AlignedPitch = AlignedWidth * BitsPerPixel >> 3; return AlignedPitch; } ///////////////////////////////////////////////////////////////////////////////////// /// Returns resource's QPitch. /// /// @return QPitch ///////////////////////////////////////////////////////////////////////////////////// uint32_t GMM_STDCALL GmmLib::GmmResourceInfoCommon::GetQPitch() { const GMM_PLATFORM_INFO *pPlatform; uint32_t QPitch; pPlatform = GMM_OVERRIDE_PLATFORM_INFO(&Surf, GetGmmLibContext()); __GMM_ASSERT(GFX_GET_CURRENT_RENDERCORE(pPlatform->Platform) >= IGFX_GEN8_CORE); __GMM_ASSERT((Surf.Type != RESOURCE_3D) || (GFX_GET_CURRENT_RENDERCORE(pPlatform->Platform) >= IGFX_GEN9_CORE)); // 2D/CUBE ==> distance in rows between array slices // 3D ==> distance in rows between R-slices // Compressed ==> one row contains a complete compression block vertically // HiZ ==> HZ_PxPerByte * HZ_QPitch // Stencil ==> logical, i.e. not halved if((GFX_GET_CURRENT_RENDERCORE(pPlatform->Platform) >= IGFX_GEN9_CORE) && GmmIsCompressed(GetGmmLibContext(), Surf.Format)) { QPitch = Surf.Alignment.QPitch / GetCompressionBlockHeight(); if((Surf.Type == RESOURCE_3D) && !Surf.Flags.Info.Linear) { const GMM_TILE_MODE TileMode = Surf.TileMode; __GMM_ASSERT(TileMode < GMM_TILE_MODES); QPitch = GFX_ALIGN(QPitch, pPlatform->TileInfo[TileMode].LogicalTileHeight); } } else if(Surf.Flags.Gpu.HiZ) { QPitch = Surf.Alignment.QPitch * pPlatform->HiZPixelsPerByte; } else { QPitch = Surf.Alignment.QPitch; } return QPitch; } ///////////////////////////////////////////////////////////////////////////////////// /// Returns offset information to a particular mip map or plane. /// /// @param[in][out] Has info about which offset client is requesting. Offset is also /// passed back to the client in this parameter. /// @return ::GMM_STATUS ///////////////////////////////////////////////////////////////////////////////////// GMM_STATUS GMM_STDCALL GmmLib::GmmResourceInfoCommon::GetOffset(GMM_REQ_OFFSET_INFO &ReqInfo) { GMM_TEXTURE_CALC *pTextureCalc; pTextureCalc = GMM_OVERRIDE_TEXTURE_CALC(&Surf, GetGmmLibContext()); __GMM_ASSERT((pTextureCalc != NULL)); if(Surf.Flags.Info.RedecribedPlanes) { uint8_t RestoreReqStdLayout = ReqInfo.ReqStdLayout ? 1 : 0; // Lock and Render offsets do not require additional handling if(ReqInfo.ReqLock || ReqInfo.ReqRender) { ReqInfo.ReqStdLayout = 0; GmmTexGetMipMapOffset(&Surf, &ReqInfo, GetGmmLibContext()); ReqInfo.ReqStdLayout = RestoreReqStdLayout; } if(ReqInfo.ReqStdLayout) { GMM_REQ_OFFSET_INFO TempReqInfo[GMM_MAX_PLANE] = {0}; GMM_TEXTURE_INFO TexInfo[GMM_MAX_PLANE]; uint32_t Plane, TotalPlanes = GmmLib::Utility::GmmGetNumPlanes(Surf.Format); // Caller must specify which plane they need the offset into if not // getting the whole surface size if(ReqInfo.Plane >= GMM_MAX_PLANE || (ReqInfo.StdLayout.Offset != -1 && !ReqInfo.Plane)) { __GMM_ASSERT(0); return GMM_ERROR; } TempReqInfo[GMM_PLANE_Y] = *&ReqInfo; TempReqInfo[GMM_PLANE_Y].Plane = GMM_NO_PLANE; TempReqInfo[GMM_PLANE_Y].ReqLock = TempReqInfo[GMM_PLANE_Y].ReqRender = 0; TempReqInfo[GMM_PLANE_V] = TempReqInfo[GMM_PLANE_U] = TempReqInfo[GMM_PLANE_Y]; pTextureCalc->GetRedescribedPlaneParams(&Surf, GMM_PLANE_Y, &TexInfo[GMM_PLANE_Y]); pTextureCalc->GetRedescribedPlaneParams(&Surf, GMM_PLANE_U, &TexInfo[GMM_PLANE_U]); pTextureCalc->GetRedescribedPlaneParams(&Surf, GMM_PLANE_V, &TexInfo[GMM_PLANE_V]); if(GMM_SUCCESS != GmmTexGetMipMapOffset(&TexInfo[GMM_PLANE_Y], &TempReqInfo[GMM_PLANE_Y], GetGmmLibContext()) || GMM_SUCCESS != GmmTexGetMipMapOffset(&TexInfo[GMM_PLANE_U], &TempReqInfo[GMM_PLANE_U], GetGmmLibContext()) || GMM_SUCCESS != GmmTexGetMipMapOffset(&TexInfo[GMM_PLANE_V], &TempReqInfo[GMM_PLANE_V], GetGmmLibContext())) { __GMM_ASSERT(0); return GMM_ERROR; } ReqInfo.StdLayout.TileDepthPitch = TempReqInfo[ReqInfo.Plane].StdLayout.TileDepthPitch; ReqInfo.StdLayout.TileRowPitch = TempReqInfo[ReqInfo.Plane].StdLayout.TileRowPitch; if(ReqInfo.StdLayout.Offset == -1) { // Special request to get the StdLayout size ReqInfo.StdLayout.Offset = TempReqInfo[ReqInfo.Plane].StdLayout.Offset; if(!ReqInfo.Plane) { for(Plane = GMM_PLANE_Y; Plane <= TotalPlanes; Plane++) { ReqInfo.StdLayout.Offset += TempReqInfo[Plane].StdLayout.Offset; } } } else { ReqInfo.StdLayout.Offset = TempReqInfo[ReqInfo.Plane].StdLayout.Offset; for(Plane = GMM_PLANE_Y; Plane < (uint32_t)ReqInfo.Plane; Plane++) { // Find the size of the previous planes and add it to the offset TempReqInfo[Plane].StdLayout.Offset = -1; if(GMM_SUCCESS != GmmTexGetMipMapOffset(&TexInfo[Plane], &TempReqInfo[Plane], GetGmmLibContext())) { __GMM_ASSERT(0); return GMM_ERROR; } ReqInfo.StdLayout.Offset += TempReqInfo[Plane].StdLayout.Offset; } } } return GMM_SUCCESS; } else { return GmmTexGetMipMapOffset(&Surf, &ReqInfo, GetGmmLibContext()); } } ///////////////////////////////////////////////////////////////////////////////////// /// Performs a CPU BLT between a specified GPU resource and a system memory surface, /// as defined by the GMM_RES_COPY_BLT descriptor. /// /// @param[in] pBlt: Describes the blit operation. See ::GMM_RES_COPY_BLT for more info. /// @return 1 if succeeded, 0 otherwise ///////////////////////////////////////////////////////////////////////////////////// uint8_t GMM_STDCALL GmmLib::GmmResourceInfoCommon::CpuBlt(GMM_RES_COPY_BLT *pBlt) { #define REQUIRE(e) \ if(!(e)) \ { \ __GMM_ASSERT(0); \ Success = 0; \ goto EXIT; \ } const GMM_PLATFORM_INFO *pPlatform; uint8_t Success = 1; GMM_TEXTURE_INFO * pTexInfo; GMM_TEXTURE_CALC * pTextureCalc; GMM_TEXTURE_INFO RedescribedPlaneInfo; __GMM_ASSERTPTR(pBlt, 0); pPlatform = GMM_OVERRIDE_PLATFORM_INFO(&Surf, GetGmmLibContext()); pTextureCalc = GMM_OVERRIDE_TEXTURE_CALC(&Surf, GetGmmLibContext()); __GMM_ASSERT( Surf.Type == RESOURCE_1D || Surf.Type == RESOURCE_2D || Surf.Type == RESOURCE_PRIMARY || Surf.Type == RESOURCE_CUBE || Surf.Type == RESOURCE_3D); __GMM_ASSERT(pBlt->Gpu.MipLevel <= Surf.MaxLod); __GMM_ASSERT(Surf.MSAA.NumSamples <= 1); // Supported by CpuSwizzleBlt--but not yet this function. __GMM_ASSERT(!Surf.Flags.Gpu.Depth || Surf.MSAA.NumSamples <= 1); // MSAA depth currently ends up with a few exchange swizzles--CpuSwizzleBlt could support with expanded XOR'ing, but probably no use case. __GMM_ASSERT(!( pBlt->Blt.Upload && Surf.Flags.Gpu.Depth && (Surf.BitsPerPixel == 32) && (pBlt->Sys.PixelPitch == 4) && (pBlt->Blt.BytesPerPixel == 3))); // When uploading D24 data from D24S8 to D24X8, no harm in copying S8 to X8 and upload will then be faster. pTexInfo = &(Surf); // YUV Planar surface if(pTextureCalc->IsTileAlignedPlanes(pTexInfo) && GmmIsPlanar(Surf.Format)) { uint32_t PlaneId = GMM_NO_PLANE; pTextureCalc->GetPlaneIdForCpuBlt(pTexInfo, pBlt, &PlaneId); if(PlaneId == GMM_MAX_PLANE) { // TODO BLT rect should not overlap between planes. { // __GMM_ASSERT(0); // decide later, for now blt it //return 0; } // BLT monolithic surface per plane and remove padding due to tiling. for(PlaneId = GMM_PLANE_Y; PlaneId <= pTextureCalc->GetNumberOfPlanes(pTexInfo); PlaneId++) { pTextureCalc->GetBltInfoPerPlane(pTexInfo, pBlt, PlaneId); CpuBlt(pBlt); } } // else continue below } // UV packed planar surfaces will have different tiling geometries for the // Y and UV planes. Blts cannot span across the tiling boundaries and we // must select the proper mode for each plane. Non-UV packed formats will // have a constant tiling mode, and so do not have the same limits if(Surf.Flags.Info.RedecribedPlanes && GmmIsUVPacked(Surf.Format)) { if(!((pBlt->Gpu.OffsetY >= pTexInfo->OffsetInfo.Plane.Y[GMM_PLANE_U]) || ((pBlt->Gpu.OffsetY + pBlt->Blt.Height) <= pTexInfo->OffsetInfo.Plane.Y[GMM_PLANE_U]))) { __GMM_ASSERT(0); return false; } if(pBlt->Gpu.OffsetY < pTexInfo->OffsetInfo.Plane.Y[GMM_PLANE_U]) { pTextureCalc->GetRedescribedPlaneParams(pTexInfo, GMM_PLANE_Y, &RedescribedPlaneInfo); // Y Plane pTexInfo = &RedescribedPlaneInfo; } else { // UV Plane pTextureCalc->GetRedescribedPlaneParams(pTexInfo, GMM_PLANE_U, &RedescribedPlaneInfo); pTexInfo = &RedescribedPlaneInfo; } } if(pBlt->Blt.Slices > 1) { GMM_RES_COPY_BLT SliceBlt = *pBlt; uint32_t Slice; SliceBlt.Blt.Slices = 1; for(Slice = pBlt->Gpu.Slice; Slice < (pBlt->Gpu.Slice + pBlt->Blt.Slices); Slice++) { SliceBlt.Gpu.Slice = Slice; SliceBlt.Sys.pData = (void *)((char *)pBlt->Sys.pData + (Slice - pBlt->Gpu.Slice) * pBlt->Sys.SlicePitch); SliceBlt.Sys.BufferSize = pBlt->Sys.BufferSize - GFX_ULONG_CAST((char *)SliceBlt.Sys.pData - (char *)pBlt->Sys.pData); CpuBlt(&SliceBlt); } } else // Single Subresource... { uint32_t ResPixelPitch = pTexInfo->BitsPerPixel / CHAR_BIT; uint32_t BlockWidth, BlockHeight, BlockDepth; uint32_t __CopyWidthBytes, __CopyHeight, __OffsetXBytes, __OffsetY; GMM_REQ_OFFSET_INFO GetOffset = {0}; pTextureCalc->GetCompressionBlockDimensions(pTexInfo->Format, &BlockWidth, &BlockHeight, &BlockDepth); #if(LHDM) if(pTexInfo->MsFormat == D3DDDIFMT_G8R8_G8B8 || pTexInfo->MsFormat == D3DDDIFMT_R8G8_B8G8) { BlockWidth = 2; ResPixelPitch = 4; } #endif { // __CopyWidthBytes... uint32_t Width; if(!pBlt->Blt.Width) // i.e. "Full Width" { __GMM_ASSERT(!GmmIsPlanar(pTexInfo->Format)); // Caller must set Blt.Width--GMM "auto-size on zero" not supported with planars since multiple interpretations would confuse more than help. Width = GFX_ULONG_CAST(pTextureCalc->GmmTexGetMipWidth(pTexInfo, pBlt->Gpu.MipLevel)); __GMM_ASSERT(Width >= pBlt->Gpu.OffsetX); Width -= pBlt->Gpu.OffsetX; __GMM_ASSERT(Width); } else { Width = pBlt->Blt.Width; } if(((pBlt->Sys.PixelPitch == 0) || (pBlt->Sys.PixelPitch == ResPixelPitch)) && ((pBlt->Blt.BytesPerPixel == 0) || (pBlt->Blt.BytesPerPixel == ResPixelPitch))) { // Full-Pixel BLT... __CopyWidthBytes = GFX_CEIL_DIV(Width, BlockWidth) * ResPixelPitch; } else // Partial-Pixel BLT... { __GMM_ASSERT(BlockWidth == 1); // No partial-pixel support for block-compressed formats. // When copying between surfaces with different pixel pitches, // specify CopyWidthBytes in terms of unswizzled surface // (convenient convention used by CpuSwizzleBlt). __CopyWidthBytes = Width * (pBlt->Sys.PixelPitch ? pBlt->Sys.PixelPitch : ResPixelPitch); } } { // __CopyHeight... if(!pBlt->Blt.Height) // i.e. "Full Height" { __GMM_ASSERT(!GmmIsPlanar(pTexInfo->Format)); // Caller must set Blt.Height--GMM "auto-size on zero" not supported with planars since multiple interpretations would confuse more than help. __CopyHeight = pTextureCalc->GmmTexGetMipHeight(pTexInfo, pBlt->Gpu.MipLevel); __GMM_ASSERT(__CopyHeight >= pBlt->Gpu.OffsetY); __CopyHeight -= pBlt->Gpu.OffsetY; __GMM_ASSERT(__CopyHeight); } else { __CopyHeight = pBlt->Blt.Height; } __CopyHeight = GFX_CEIL_DIV(__CopyHeight, BlockHeight); } __GMM_ASSERT((pBlt->Gpu.OffsetX % BlockWidth) == 0); __OffsetXBytes = (pBlt->Gpu.OffsetX / BlockWidth) * ResPixelPitch + pBlt->Gpu.OffsetSubpixel; __GMM_ASSERT((pBlt->Gpu.OffsetY % BlockHeight) == 0); __OffsetY = (pBlt->Gpu.OffsetY / BlockHeight); { // Get pResData Offsets to this subresource... GetOffset.ReqLock = pTexInfo->Flags.Info.Linear; GetOffset.ReqStdLayout = !GetOffset.ReqLock && pTexInfo->Flags.Info.StdSwizzle; GetOffset.ReqRender = !GetOffset.ReqLock && !GetOffset.ReqStdLayout; GetOffset.MipLevel = pBlt->Gpu.MipLevel; switch(pTexInfo->Type) { case RESOURCE_1D: case RESOURCE_2D: case RESOURCE_PRIMARY: { GetOffset.ArrayIndex = pBlt->Gpu.Slice; break; } case RESOURCE_CUBE: { GetOffset.ArrayIndex = pBlt->Gpu.Slice / 6; GetOffset.CubeFace = (GMM_CUBE_FACE_ENUM)(pBlt->Gpu.Slice % 6); break; } case RESOURCE_3D: { GetOffset.Slice = (GMM_IS_64KB_TILE(pTexInfo->Flags) || pTexInfo->Flags.Info.TiledYf) ? (pBlt->Gpu.Slice / pPlatform->TileInfo[pTexInfo->TileMode].LogicalTileDepth) : pBlt->Gpu.Slice; break; } default: __GMM_ASSERT(0); } REQUIRE(this->GetOffset(GetOffset) == GMM_SUCCESS); } if(pTexInfo->Flags.Info.Linear) { char * pDest, *pSrc; uint32_t DestPitch, SrcPitch; uint32_t y; __GMM_ASSERT( // Linear-to-linear subpixel BLT unexpected--Not implemented. (!pBlt->Sys.PixelPitch || (pBlt->Sys.PixelPitch == ResPixelPitch)) && (!pBlt->Blt.BytesPerPixel || (pBlt->Blt.BytesPerPixel == ResPixelPitch))); if(pBlt->Blt.Upload) { pDest = (char *)pBlt->Gpu.pData; DestPitch = GFX_ULONG_CAST(pTexInfo->Pitch); pSrc = (char *)pBlt->Sys.pData; SrcPitch = pBlt->Sys.RowPitch; } else { pDest = (char *)pBlt->Sys.pData; DestPitch = pBlt->Sys.RowPitch; pSrc = (char *)pBlt->Gpu.pData; SrcPitch = GFX_ULONG_CAST(pTexInfo->Pitch); } __GMM_ASSERT(GetOffset.Lock.Offset < pTexInfo->Size); pDest += GetOffset.Lock.Offset + (__OffsetY * DestPitch + __OffsetXBytes); for(y = 0; y < __CopyHeight; y++) { // Memcpy per row isn't optimal, but doubt this linear-to-linear path matters. #if _WIN32 #ifdef __GMM_KMD__ GFX_MEMCPY_S #else memcpy_s #endif (pDest, __CopyWidthBytes, pSrc, __CopyWidthBytes); #else memcpy(pDest, pSrc, __CopyWidthBytes); #endif pDest += DestPitch; pSrc += SrcPitch; } } else // Swizzled BLT... { CPU_SWIZZLE_BLT_SURFACE LinearSurface = {0}, SwizzledSurface; uint32_t ZOffset = 0; __GMM_ASSERT(GetOffset.Render.Offset64 < pTexInfo->Size); ZOffset = (pTexInfo->Type == RESOURCE_3D && (GMM_IS_64KB_TILE(pTexInfo->Flags) || pTexInfo->Flags.Info.TiledYf)) ? (pBlt->Gpu.Slice % pPlatform->TileInfo[pTexInfo->TileMode].LogicalTileDepth) : 0; if(pTexInfo->Flags.Info.StdSwizzle == 1) { SwizzledSurface.pBase = (char *)pBlt->Gpu.pData + GFX_ULONG_CAST(GetOffset.StdLayout.Offset); SwizzledSurface.OffsetX = __OffsetXBytes; SwizzledSurface.OffsetY = __OffsetY; SwizzledSurface.OffsetZ = ZOffset; uint32_t MipWidth = GFX_ULONG_CAST(pTextureCalc->GmmTexGetMipWidth(pTexInfo, pBlt->Gpu.MipLevel)); uint32_t MipHeight = pTextureCalc->GmmTexGetMipHeight(pTexInfo, pBlt->Gpu.MipLevel); pTextureCalc->AlignTexHeightWidth(pTexInfo, &MipHeight, &MipWidth); SwizzledSurface.Height = MipHeight; SwizzledSurface.Pitch = MipWidth * ResPixelPitch; } else { SwizzledSurface.pBase = (char *)pBlt->Gpu.pData + GFX_ULONG_CAST(GetOffset.Render.Offset64); SwizzledSurface.Pitch = GFX_ULONG_CAST(pTexInfo->Pitch); SwizzledSurface.OffsetX = GetOffset.Render.XOffset + __OffsetXBytes; SwizzledSurface.OffsetY = GetOffset.Render.YOffset + __OffsetY; SwizzledSurface.OffsetZ = GetOffset.Render.ZOffset + ZOffset; SwizzledSurface.Height = GFX_ULONG_CAST(pTexInfo->Size / pTexInfo->Pitch); } SwizzledSurface.Element.Pitch = ResPixelPitch; LinearSurface.pBase = pBlt->Sys.pData; LinearSurface.Pitch = pBlt->Sys.RowPitch; LinearSurface.Height = pBlt->Sys.BufferSize / (pBlt->Sys.RowPitch ? pBlt->Sys.RowPitch : pBlt->Sys.BufferSize); LinearSurface.Element.Pitch = pBlt->Sys.PixelPitch ? pBlt->Sys.PixelPitch : ResPixelPitch; LinearSurface.Element.Size = SwizzledSurface.Element.Size = pBlt->Blt.BytesPerPixel ? pBlt->Blt.BytesPerPixel : ResPixelPitch; SwizzledSurface.pSwizzle = NULL; if(pTexInfo->Flags.Info.TiledW) { SwizzledSurface.pSwizzle = &INTEL_TILE_W; // Correct for GMM's 2x Pitch handling of stencil... // (Unlike the HW, CpuSwizzleBlt handles TileW as a natural, // 64x64=4KB tile, so the pre-Gen10 "double-pitch/half-height" // kludging to TileY shape must be reversed.) __GMM_ASSERT((SwizzledSurface.Pitch % 2) == 0); SwizzledSurface.Pitch /= 2; SwizzledSurface.Height *= 2; } else if(GMM_IS_4KB_TILE(pTexInfo->Flags) && !(pTexInfo->Flags.Info.TiledYf || GMM_IS_64KB_TILE(pTexInfo->Flags))) { if(GetGmmLibContext()->GetSkuTable().FtrTileY) { SwizzledSurface.pSwizzle = &INTEL_TILE_Y; } else { SwizzledSurface.pSwizzle = &INTEL_TILE_4; } } else if(pTexInfo->Flags.Info.TiledX) { SwizzledSurface.pSwizzle = &INTEL_TILE_X; } else // Yf/s... { // clang-format off #define NA #define CASE(Layout, Tile, msaa, xD, bpe) \ case bpe: \ SwizzledSurface.pSwizzle = &Layout##_##Tile##_##msaa##xD##bpe; \ break #define SWITCH_BPP(Layout, Tile, msaa, xD) \ switch(pTexInfo->BitsPerPixel) \ { \ CASE(Layout, Tile, msaa, xD, 8); \ CASE(Layout, Tile, msaa, xD, 16); \ CASE(Layout, Tile, msaa, xD, 32); \ CASE(Layout, Tile, msaa, xD, 64); \ CASE(Layout, Tile, msaa, xD, 128); \ } #define SWITCH_MSAA_TILE64(Layout, Tile, xD) \ {\ switch(pTexInfo->MSAA.NumSamples) \ { \ case 0: \ SWITCH_BPP(Layout, TILE_64, , xD); \ break; \ case 1: \ SWITCH_BPP(Layout, TILE_64, , xD); \ break; \ case 2: \ if(GetGmmLibContext()->GetSkuTable().FtrXe2PlusTiling)\ { \ SWITCH_BPP(Layout, TILE_64_V2, MSAA2_, xD); \ }\ else\ { \ SWITCH_BPP(Layout, TILE_64, MSAA2_, xD); \ } \ break; \ case 4: \ if(GetGmmLibContext()->GetSkuTable().FtrXe2PlusTiling)\ { \ SWITCH_BPP(Layout, TILE_64_V2, MSAA4_, xD); \ }\ else\ { \ SWITCH_BPP(Layout, TILE_64, MSAA_, xD); \ } \ break; \ case 8: \ if(GetGmmLibContext()->GetSkuTable().FtrXe2PlusTiling)\ { \ SWITCH_BPP(Layout, TILE_64_V2, MSAA8_, xD); \ }\ else\ { \ SWITCH_BPP(Layout, TILE_64, MSAA_, xD); \ } \ break; \ case 16: \ if(GetGmmLibContext()->GetSkuTable().FtrXe2PlusTiling)\ { \ SWITCH_BPP(Layout, TILE_64_V2, MSAA16_, xD); \ }\ else\ { \ SWITCH_BPP(Layout, TILE_64, MSAA_, xD); \ } \ break; \ } \ } \ #define SWITCH_MSAA(Layout, Tile, xD) \ {\ switch(pTexInfo->MSAA.NumSamples) \ { \ case 0: \ SWITCH_BPP(Layout, Tile, , xD); \ break; \ case 1: \ SWITCH_BPP(Layout, Tile, , xD); \ break; \ case 2: \ SWITCH_BPP(Layout, Tile, MSAA2_, xD); \ break; \ case 4: \ SWITCH_BPP(Layout, Tile, MSAA4_, xD); \ break; \ case 8: \ SWITCH_BPP(Layout, Tile, MSAA8_, xD); \ break; \ case 16: \ SWITCH_BPP(Layout, Tile, MSAA16_, xD); \ break; \ }\ } // clang-format on if(pTexInfo->Type == RESOURCE_3D) { if(pTexInfo->Flags.Info.TiledYf) { SWITCH_BPP(INTEL, TILE_YF, , 3D_); } else if(GMM_IS_64KB_TILE(pTexInfo->Flags)) { if(GetGmmLibContext()->GetSkuTable().FtrTileY) { SWITCH_BPP(INTEL, TILE_YS, , 3D_); } else { if (GetGmmLibContext()->GetSkuTable().FtrXe2PlusTiling) { SWITCH_BPP(INTEL, TILE_64_V2, , 3D_); } else { SWITCH_BPP(INTEL, TILE_64, , 3D_); } } } } else // 2D/Cube... { if(pTexInfo->Flags.Info.TiledYf) { SWITCH_MSAA(INTEL, TILE_YF, ); } else if(GMM_IS_64KB_TILE(pTexInfo->Flags)) { if(GetGmmLibContext()->GetSkuTable().FtrTileY) { SWITCH_MSAA(INTEL, TILE_YS, ); } else { SWITCH_MSAA_TILE64(INTEL, TILE_64, ); } } } } __GMM_ASSERT(SwizzledSurface.pSwizzle); if(pBlt->Blt.Upload) { CpuSwizzleBlt(&SwizzledSurface, &LinearSurface, __CopyWidthBytes, __CopyHeight); } else { CpuSwizzleBlt(&LinearSurface, &SwizzledSurface, __CopyWidthBytes, __CopyHeight); } } } EXIT: return Success; } ///////////////////////////////////////////////////////////////////////////////////// /// Helper function that helps UMDs map in the surface in a layout that /// our HW understands. Clients call this function in a loop until it /// returns failure. Clients will get back information in pMapping->Span, /// which they can use to map Span.Size bytes to Span.VirtualOffset gfx /// address with Span.PhysicalOffset physical page. /// /// @param[in] pMapping: Clients call the function with initially zero'd out GMM_GET_MAPPING. /// @return 1 if more span descriptors to report, 0 if all mapping is done ///////////////////////////////////////////////////////////////////////////////////// uint8_t GMM_STDCALL GmmLib::GmmResourceInfoCommon::GetMappingSpanDesc(GMM_GET_MAPPING *pMapping) { const GMM_PLATFORM_INFO *pPlatform; uint8_t WasFinalSpan = 0; GMM_TEXTURE_INFO * pTexInfo; GMM_TEXTURE_CALC * pTextureCalc; GMM_TEXTURE_INFO RedescribedPlaneInfo; bool Aux = false; __GMM_ASSERT(Surf.Flags.Info.StdSwizzle); pPlatform = GMM_OVERRIDE_PLATFORM_INFO(&Surf, GetGmmLibContext()); pTextureCalc = GMM_OVERRIDE_TEXTURE_CALC(&Surf, GetGmmLibContext()); __GMM_ASSERT(pTextureCalc != NULL); pTexInfo = &Surf; if((pMapping->Type == GMM_MAPPING_YUVPLANAR_AUX || pMapping->Type == GMM_MAPPING_YUVPLANAR) && GmmIsPlanar(Surf.Format)) { uint32_t Plane; GMM_REQ_OFFSET_INFO ReqInfo = {0}, NextSpanReqInfo = {0}; GMM_GFX_SIZE_T SpanPhysicalOffset, SpanVirtualOffset; if(pMapping->Type == GMM_MAPPING_YUVPLANAR_AUX) { // Unpack GMM_MAPPING_YUVPLANAR and Aux from caller function. // Applicalble only for Aux mapping for Y/UV Plane // GMM_MAPPING_YUVPLANAR_AUX is unpacked as (GMM_MAPPING_YUVPLANAR , Aux) Aux = true; } if(Aux) { memset(pMapping, 0, sizeof(*pMapping)); pMapping->Type = GMM_MAPPING_YUVPLANAR; WasFinalSpan = 1; SpanPhysicalOffset = GetSizeMainSurfacePhysical(); SpanVirtualOffset = GetSizeMainSurface(); NextSpanReqInfo.Lock.Offset64 = SpanPhysicalOffset + GetSizeAuxSurface(GMM_AUX_SURF); NextSpanReqInfo.Render.Offset64 = GetSizeSurface(); } else { if(pMapping->Scratch.Plane == GMM_NO_PLANE) { uint32_t ArrayIndex = pMapping->Scratch.Slice; memset(pMapping, 0, sizeof(*pMapping)); pMapping->Type = GMM_MAPPING_YUVPLANAR; pMapping->Scratch.Plane = GMM_PLANE_Y; pMapping->Scratch.Slice = ArrayIndex; SpanPhysicalOffset = SpanVirtualOffset = 0; if(GmmLib::Utility::GmmGetNumPlanes(Surf.Format) == GMM_PLANE_V) { pMapping->Scratch.LastPlane = GMM_PLANE_V; } else { pMapping->Scratch.LastPlane = GMM_PLANE_U; } Plane = pMapping->Scratch.Plane; } else { // If we've crossed into a new plane then need to reset // the current mapping info and adjust the mapping // params accordingly Plane = pMapping->Scratch.Plane + 1; GMM_YUV_PLANE LastPlane = pMapping->Scratch.LastPlane; SpanPhysicalOffset = pMapping->__NextSpan.PhysicalOffset; SpanVirtualOffset = pMapping->__NextSpan.VirtualOffset; uint32_t ArrayIndex = pMapping->Scratch.Slice; memset(pMapping, 0, sizeof(*pMapping)); pMapping->Type = GMM_MAPPING_YUVPLANAR; pMapping->Scratch.Plane = GMM_YUV_PLANE(Plane); pMapping->Scratch.LastPlane = LastPlane; pMapping->Scratch.Slice = ArrayIndex; } { if(pMapping->Scratch.Plane == GMM_PLANE_Y) { ReqInfo.ReqRender = ReqInfo.ReqLock = 1; ReqInfo.Plane = GMM_YUV_PLANE(Plane); ReqInfo.ArrayIndex = pMapping->Scratch.Slice; this->GetOffset(ReqInfo); SpanPhysicalOffset = ReqInfo.Lock.Offset64; SpanVirtualOffset = ReqInfo.Render.Offset64; } if(GMM_YUV_PLANE(Plane) < pMapping->Scratch.LastPlane) { NextSpanReqInfo.ReqRender = NextSpanReqInfo.ReqLock = 1; NextSpanReqInfo.Plane = GMM_YUV_PLANE(Plane + 1); NextSpanReqInfo.ArrayIndex = pMapping->Scratch.Slice; this->GetOffset(NextSpanReqInfo); } else // last plane of that array { NextSpanReqInfo.Lock.Offset64 = (GetSizeMainSurfacePhysical() / GFX_MAX(Surf.ArraySize, 1)) * (pMapping->Scratch.Slice + 1); NextSpanReqInfo.Render.Offset64 = (GetSizeMainSurface() / GFX_MAX(Surf.ArraySize, 1)) * (pMapping->Scratch.Slice + 1); WasFinalSpan = 1; } } } // Plane offsets pMapping->Span.PhysicalOffset = SpanPhysicalOffset; pMapping->Span.VirtualOffset = SpanVirtualOffset; pMapping->__NextSpan.PhysicalOffset = NextSpanReqInfo.Lock.Offset64; pMapping->__NextSpan.VirtualOffset = NextSpanReqInfo.Render.Offset64; pMapping->Span.Size = pMapping->__NextSpan.PhysicalOffset - pMapping->Span.PhysicalOffset; } else if(pMapping->Type == GMM_MAPPING_GEN9_YS_TO_STDSWIZZLE) { __GMM_ASSERT(Surf.Flags.Info.StdSwizzle); const uint32_t TileSize = GMM_KBYTE(64); __GMM_ASSERT(Surf.Flags.Info.TiledYs); __GMM_ASSERT( (Surf.Type == RESOURCE_2D) || (Surf.Type == RESOURCE_3D) || (Surf.Type == RESOURCE_CUBE)); __GMM_ASSERT(Surf.Flags.Gpu.Depth == 0); // TODO(Minor): Proper StdSwizzle exemptions? __GMM_ASSERT(Surf.Flags.Gpu.SeparateStencil == 0); __GMM_ASSERT(AuxSurf.Size == 0); // TODO(Medium): Support not yet implemented, but DX12 UMD not using yet. __GMM_ASSERT(Surf.Flags.Gpu.MMC == 0); // TODO(Medium): Support not yet implemented, but not yet needed for DX12. // For planar surfaces we need to reorder the planes into what HW expects. // OS will provide planes in [Y0][Y1][U0][U1][V0][V1] order while // HW requires them to be in [Y0][U0][V0][Y1][U1][V1] order if(Surf.Flags.Info.RedecribedPlanes) { if(pMapping->Scratch.Plane == GMM_NO_PLANE) { pMapping->Scratch.Plane = GMM_PLANE_Y; if(GmmLib::Utility::GmmGetNumPlanes(Surf.Format) == GMM_PLANE_V) { pMapping->Scratch.LastPlane = GMM_PLANE_V; } else { pMapping->Scratch.LastPlane = GMM_PLANE_U; } } else if(pMapping->Scratch.Row == pMapping->Scratch.Rows) { // If we've crossed into a new plane then need to reset // the current mapping info and adjust the mapping // params accordingly GMM_REQ_OFFSET_INFO ReqInfo = {0}; uint32_t Plane = pMapping->Scratch.Plane + 1; GMM_YUV_PLANE LastPlane = pMapping->Scratch.LastPlane; memset(pMapping, 0, sizeof(*pMapping)); pMapping->Type = GMM_MAPPING_GEN9_YS_TO_STDSWIZZLE; pMapping->Scratch.Plane = GMM_YUV_PLANE(Plane); pMapping->Scratch.LastPlane = LastPlane; ReqInfo.ReqRender = ReqInfo.ReqStdLayout = 1; ReqInfo.Plane = GMM_YUV_PLANE(Plane); this->GetOffset(ReqInfo); pMapping->__NextSpan.PhysicalOffset = ReqInfo.StdLayout.Offset; pMapping->__NextSpan.VirtualOffset = ReqInfo.Render.Offset64; } pTextureCalc->GetRedescribedPlaneParams(pTexInfo, GMM_PLANE_Y, &RedescribedPlaneInfo); pTexInfo = &RedescribedPlaneInfo; } // Initialization of Mapping Params... if(pMapping->Scratch.Element.Width == 0) // i.e. initially zero'ed struct. { uint32_t BytesPerElement = pTexInfo->BitsPerPixel / CHAR_BIT; pMapping->Scratch.EffectiveLodMax = GFX_MIN(pTexInfo->MaxLod, pTexInfo->Alignment.MipTailStartLod); pTextureCalc->GetCompressionBlockDimensions( pTexInfo->Format, &pMapping->Scratch.Element.Width, &pMapping->Scratch.Element.Height, &pMapping->Scratch.Element.Depth); { // Tile Dimensions... GMM_TILE_MODE TileMode = pTexInfo->TileMode; __GMM_ASSERT(TileMode < GMM_TILE_MODES); // Get Tile Logical Tile Dimensions (i.e. uncompressed pixels)... pMapping->Scratch.Tile.Width = (pPlatform->TileInfo[TileMode].LogicalTileWidth / BytesPerElement) * pMapping->Scratch.Element.Width; pMapping->Scratch.Tile.Height = pPlatform->TileInfo[TileMode].LogicalTileHeight * pMapping->Scratch.Element.Height; pMapping->Scratch.Tile.Depth = pPlatform->TileInfo[TileMode].LogicalTileDepth * pMapping->Scratch.Element.Depth; pMapping->Scratch.RowPitchVirtual = GFX_ULONG_CAST(pTexInfo->Pitch) * pPlatform->TileInfo[TileMode].LogicalTileHeight * pPlatform->TileInfo[TileMode].LogicalTileDepth; } { // Slice... uint32_t Lod; uint32_t LodsPerSlice = (pTexInfo->Type != RESOURCE_3D) ? pMapping->Scratch.EffectiveLodMax + 1 : 1; // 3D Std Swizzle traverses slices before MIP's. if(pMapping->Scratch.Plane) { // If planar then we need the parent descriptors planar pitch pMapping->Scratch.SlicePitch.Virtual = GFX_ULONG_CAST(Surf.OffsetInfo.Plane.ArrayQPitch) * (pMapping->Scratch.Tile.Depth / pMapping->Scratch.Element.Depth); } else { pMapping->Scratch.SlicePitch.Virtual = GFX_ULONG_CAST(pTexInfo->OffsetInfo.Texture2DOffsetInfo.ArrayQPitchRender) * (pMapping->Scratch.Tile.Depth / pMapping->Scratch.Element.Depth); } // SlicePitch.Physical... __GMM_ASSERT(pMapping->Scratch.SlicePitch.Physical == 0); for(Lod = 0; Lod < LodsPerSlice; Lod++) { uint32_t MipCols, MipRows; GMM_GFX_SIZE_T MipWidth; uint32_t MipHeight; MipWidth = pTextureCalc->GmmTexGetMipWidth(pTexInfo, Lod); MipHeight = pTextureCalc->GmmTexGetMipHeight(pTexInfo, Lod); MipCols = GFX_ULONG_CAST( GFX_CEIL_DIV( MipWidth, pMapping->Scratch.Tile.Width)); MipRows = GFX_CEIL_DIV( MipHeight, pMapping->Scratch.Tile.Height); pMapping->Scratch.SlicePitch.Physical += MipCols * MipRows * TileSize; } } { // Mip0... if(pTexInfo->Type != RESOURCE_3D) { pMapping->Scratch.Slices = GFX_MAX(pTexInfo->ArraySize, 1) * ((pTexInfo->Type == RESOURCE_CUBE) ? 6 : 1); } else { pMapping->Scratch.Slices = GFX_CEIL_DIV(pTexInfo->Depth, pMapping->Scratch.Tile.Depth); } if(pTexInfo->Pitch == (GFX_ALIGN(pTexInfo->BaseWidth, pMapping->Scratch.Tile.Width) / pMapping->Scratch.Element.Width * BytesPerElement)) { // Treat Each LOD0 MIP as Single, Large Mapping Row... pMapping->Scratch.Rows = 1; pMapping->__NextSpan.Size = GFX_CEIL_DIV(pTexInfo->BaseWidth, pMapping->Scratch.Tile.Width) * GFX_CEIL_DIV(pTexInfo->BaseHeight, pMapping->Scratch.Tile.Height) * TileSize; } else { pMapping->Scratch.Rows = GFX_CEIL_DIV(pTexInfo->BaseHeight, pMapping->Scratch.Tile.Height); pMapping->__NextSpan.Size = GFX_CEIL_DIV(pTexInfo->BaseWidth, pMapping->Scratch.Tile.Width) * TileSize; } } } // This iteration's span descriptor... pMapping->Span = pMapping->__NextSpan; // Prepare for Next Iteration... // for(Lod = 0; Lod <= EffectiveLodMax; Lod += 1) // for(Row = 0; Row < Rows; Row += 1) // for(Slice = 0; Slice < Slices; Slice += 1) if((pMapping->Scratch.Slice += 1) < pMapping->Scratch.Slices) { pMapping->__NextSpan.PhysicalOffset += pMapping->Scratch.SlicePitch.Physical; pMapping->__NextSpan.VirtualOffset += pMapping->Scratch.SlicePitch.Virtual; } else { pMapping->Scratch.Slice = 0; if((pMapping->Scratch.Row += 1) < pMapping->Scratch.Rows) { pMapping->__NextSpan.PhysicalOffset = pMapping->Scratch.Slice0MipOffset.Physical += pMapping->Span.Size; pMapping->__NextSpan.VirtualOffset = pMapping->Scratch.Slice0MipOffset.Virtual += pMapping->Scratch.RowPitchVirtual; } else if((pMapping->Scratch.Lod += 1) <= pMapping->Scratch.EffectiveLodMax) { GMM_REQ_OFFSET_INFO GetOffset = {0}; GMM_GFX_SIZE_T MipWidth; uint32_t MipHeight, MipCols; MipWidth = pTextureCalc->GmmTexGetMipWidth(pTexInfo, pMapping->Scratch.Lod); MipHeight = pTextureCalc->GmmTexGetMipHeight(pTexInfo, pMapping->Scratch.Lod); MipCols = GFX_ULONG_CAST( GFX_CEIL_DIV( MipWidth, pMapping->Scratch.Tile.Width)); pMapping->Scratch.Row = 0; pMapping->Scratch.Rows = GFX_CEIL_DIV( MipHeight, pMapping->Scratch.Tile.Height); if(pTexInfo->Type != RESOURCE_3D) { pMapping->__NextSpan.PhysicalOffset = pMapping->Scratch.Slice0MipOffset.Physical += pMapping->Span.Size; } else { uint32_t MipDepth; MipDepth = pTextureCalc->GmmTexGetMipDepth(pTexInfo, pMapping->Scratch.Lod); // 3D Std Swizzle traverses slices before MIP's... pMapping->Scratch.Slice0MipOffset.Physical = pMapping->__NextSpan.PhysicalOffset += pMapping->Span.Size; pMapping->Scratch.Slices = GFX_CEIL_DIV( MipDepth, pMapping->Scratch.Tile.Depth); pMapping->Scratch.SlicePitch.Physical = MipCols * pMapping->Scratch.Rows * TileSize; } GetOffset.ReqRender = 1; GetOffset.MipLevel = pMapping->Scratch.Lod; this->GetOffset(GetOffset); pMapping->__NextSpan.VirtualOffset = pMapping->Scratch.Slice0MipOffset.Virtual = GFX_ALIGN_FLOOR(GetOffset.Render.Offset64, TileSize); // Truncate for packed MIP Tail. pMapping->__NextSpan.Size = MipCols * TileSize; } else { // If the resource was a planar surface then need to iterate over the remaining planes WasFinalSpan = pMapping->Scratch.Plane == pMapping->Scratch.LastPlane; } } } else { __GMM_ASSERT(0); } return !WasFinalSpan; } //============================================================================= // // Function: GetTiledResourceMipPacking // // Desc: Get number of packed mips and total #tiles for packed mips // // Parameters: // See function arguments. // // Returns: // void //----------------------------------------------------------------------------- void GMM_STDCALL GmmLib::GmmResourceInfoCommon::GetTiledResourceMipPacking(uint32_t *pNumPackedMips, uint32_t *pNumTilesForPackedMips) { if(GetMaxLod() == 0) { *pNumPackedMips = 0; *pNumTilesForPackedMips = 0; return; } if(GetResFlags().Info.TiledYf || GMM_IS_64KB_TILE(GetResFlags())) { if(Surf.Alignment.MipTailStartLod == GMM_TILED_RESOURCE_NO_MIP_TAIL) { *pNumPackedMips = 0; *pNumTilesForPackedMips = 0; } else { *pNumPackedMips = GetMaxLod() - Surf.Alignment.MipTailStartLod + 1; *pNumTilesForPackedMips = 1; } } else { // Error, unsupported format. __GMM_ASSERT(false); } } //============================================================================= // // Function: GetPackedMipTailStartLod // // Desc: Get Lod of first packed Mip. // // Parameters: // See function arguments. // // Returns: // Lod of first packed Mip //----------------------------------------------------------------------------- uint32_t GMM_STDCALL GmmLib::GmmResourceInfoCommon::GetPackedMipTailStartLod() { uint32_t NumPackedMips = 0, NumTilesForPackedMips = 0; const GMM_PLATFORM_INFO *pPlatform = GMM_OVERRIDE_PLATFORM_INFO(&Surf, GetGmmLibContext()); GetTiledResourceMipPacking(&NumPackedMips, &NumTilesForPackedMips); return (GetMaxLod() == 0) ? pPlatform->MaxLod : GetMaxLod() - NumPackedMips + 1; //GetMaxLod srarts at index 0, while NumPackedMips is just //the number of mips. So + 1 to bring them to same units. } ///////////////////////////////////////////////////////////////////////////////////// /// Verifies if all mips are RCC-aligned /// @return true/false ///////////////////////////////////////////////////////////////////////////////////// bool GMM_STDCALL GmmLib::GmmResourceInfoCommon::IsMipRCCAligned(uint8_t &MisAlignedLod) { const uint8_t RCCCachelineWidth = 32; const uint8_t RCCCachelineHeight = 4; for(uint8_t lod = 0; lod <= GetMaxLod(); lod++) { if(!(GFX_IS_ALIGNED(GetMipWidth(lod), RCCCachelineWidth) && GFX_IS_ALIGNED(GetMipHeight(lod), RCCCachelineHeight))) { MisAlignedLod = lod; return false; } } return true; } ///////////////////////////////////////////////////////////////////////////////////// /// Return the logical width of mip level /// @param[in] MipLevel: Mip level for which the info is needed /// @return Mip width ///////////////////////////////////////////////////////////////////////////////////// GMM_GFX_SIZE_T GMM_STDCALL GmmLib::GmmResourceInfoCommon::GetMipWidth(uint32_t MipLevel) { GMM_TEXTURE_CALC *pTextureCalc = GMM_OVERRIDE_TEXTURE_CALC(&Surf, GetGmmLibContext()); return pTextureCalc->GmmTexGetMipWidth(&Surf, MipLevel); } ///////////////////////////////////////////////////////////////////////////////////// /// Return the logical height of mip level /// @param[in] MipLevel: Mip level for which the info is needed /// @return Mip width ///////////////////////////////////////////////////////////////////////////////////// uint32_t GMM_STDCALL GmmLib::GmmResourceInfoCommon::GetMipHeight(uint32_t MipLevel) { GMM_TEXTURE_CALC *pTextureCalc = GMM_OVERRIDE_TEXTURE_CALC(&Surf, GetGmmLibContext()); return pTextureCalc->GmmTexGetMipHeight(&Surf, MipLevel); } ///////////////////////////////////////////////////////////////////////////////////// /// Return the logical depth of mip level /// @param[in] MipLevel Mip level for which the info is needed /// @return Mip width ///////////////////////////////////////////////////////////////////////////////////// uint32_t GMM_STDCALL GmmLib::GmmResourceInfoCommon::GetMipDepth(uint32_t MipLevel) { GMM_TEXTURE_CALC *pTextureCalc = GMM_OVERRIDE_TEXTURE_CALC(&Surf, GetGmmLibContext()); return pTextureCalc->GmmTexGetMipDepth(&Surf, MipLevel); } gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/Resource/GmmResourceInfoCommonEx.cpp000066400000000000000000001306101466655022700270610ustar00rootroot00000000000000/*============================================================================== Copyright(c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ============================================================================*/ #include "Internal/Common/GmmLibInc.h" ///////////////////////////////////////////////////////////////////////////////////// /// Copies parameters or sets flags based on info sent by the client. /// /// @param[in] CreateParams: Flags which specify what sort of resource to create /// @return false if encountered invalid param. true otherwise. ///////////////////////////////////////////////////////////////////////////////////// bool GmmLib::GmmResourceInfoCommon::CopyClientParams(GMM_RESCREATE_PARAMS &CreateParams) { uint32_t BitsPerPixel; uint8_t Optimize64KBTile = 0; if((CreateParams.Format > GMM_FORMAT_INVALID) && (CreateParams.Format < GMM_RESOURCE_FORMATS)) { BitsPerPixel = GetGmmLibContext()->GetPlatformInfo().FormatTable[CreateParams.Format].Element.BitsPer; } else { GMM_ASSERTDPF(0, "Format Error"); return false; } { // Promote tiling options if caller does not provide any. // X/Y/W/L are tiling formats, and Yf/Ys are modifiers to the internal // ordering for Y and L macro-formats. if((CreateParams.Flags.Info.Linear + CreateParams.Flags.Info.TiledW + CreateParams.Flags.Info.TiledX + CreateParams.Flags.Info.TiledY) == 0) { if(CreateParams.Type == RESOURCE_1D || CreateParams.Type == RESOURCE_BUFFER || CreateParams.Type == RESOURCE_SCRATCH || CreateParams.Flags.Info.ExistingSysMem) { CreateParams.Flags.Info.Linear = true; } if(GetGmmLibContext()->GetSkuTable().FtrTileY) { CreateParams.Flags.Info.TiledYs |= CreateParams.Flags.Info.StdSwizzle || CreateParams.Flags.Gpu.TiledResource; // Propose L+Y by default. CreateParams.Flags.Info.Linear = true; CreateParams.Flags.Info.TiledY = true; // Pre-Gen11 Planar if(GmmIsPlanar(CreateParams.Format) && (GFX_GET_CURRENT_RENDERCORE(GetGmmLibContext()->GetPlatformInfo().Platform) < IGFX_GEN11_CORE)) { CreateParams.Flags.Info.TiledX = true; } } //Auto-tiling selection if not Linear already else if(CreateParams.Flags.Info.Linear == 0) { // Xe_HP onwards. if((CreateParams.Flags.Info.TiledYs + CreateParams.Flags.Info.TiledYf + CreateParams.Flags.Info.Tile4 + CreateParams.Flags.Info.Tile64) == 0) { GMM_ASSERTDPF(!CreateParams.Flags.Info.StdSwizzle, "StdSwizzle not supported on current platform"); if(!GetGmmLibContext()->GetSkuTable().FtrForceTile4) // FtrForceTile4 should never be set by default, used for debug purpose only { // Default Tiling is set to Tile64 on FtrTileY disabled platforms uint8_t IsYUVSurface = GmmIsPlanar(CreateParams.Format) || (GmmIsYUVPacked(CreateParams.Format)); //YCRCB* formats uint8_t IsYCrCbSurface = ((CreateParams.Format == GMM_FORMAT_YCRCB_NORMAL) || (CreateParams.Format == GMM_FORMAT_YCRCB_SWAPUV) || (CreateParams.Format == GMM_FORMAT_YCRCB_SWAPUVY) || (CreateParams.Format == GMM_FORMAT_YCRCB_SWAPY)); CreateParams.Flags.Info.Tile4 = ((!GMM_IS_SUPPORTED_BPP_ON_TILE_64_YF_YS(BitsPerPixel)) || // 24,48,96 bpps are not supported on Tile64, Tile4 is bpp independent ((CreateParams.Type == RESOURCE_3D) && (CreateParams.Flags.Gpu.Depth || CreateParams.Flags.Gpu.SeparateStencil)) || ((!GetGmmLibContext()->GetSkuTable().FtrDisplayDisabled) && (CreateParams.Flags.Gpu.FlipChain || CreateParams.Flags.Gpu.Overlay) ) || IsYUVSurface || IsYCrCbSurface); CreateParams.Flags.Info.Tile64 = !CreateParams.Flags.Info.Tile4; // Optimize only when GMM makes tiling decision on behalf of UMD clients. // Defering the memory calculations until GMM_TEXTURE_INFO is available. if(CreateParams.Flags.Info.Tile64) { Optimize64KBTile = 1; } } else { CreateParams.Flags.Info.Tile64 = (CreateParams.MSAA.NumSamples > 1) || CreateParams.Flags.Gpu.TiledResource; // Colour & Depth/Stencil(IMS) MSAA should use Tile64 CreateParams.Flags.Info.Tile4 = !CreateParams.Flags.Info.Tile64; } } else if((CreateParams.Flags.Info.TiledYs + CreateParams.Flags.Info.TiledYf) > 0) { GMM_ASSERTDPF(0, "Tile Yf/Ys not supported on given platform"); // Overrides the flags. if(GetGmmLibContext()->GetSkuTable().FtrForceTile4)// FtrForceTile4 should never be set by default, used for debug purpose only. { CreateParams.Flags.Info.Tile64 = CreateParams.Flags.Info.TiledYs || (CreateParams.MSAA.NumSamples > 1) || CreateParams.Flags.Gpu.TiledResource; // Colour & Depth/Stencil(IMS) MSAA should use Tile64 CreateParams.Flags.Info.Tile4 = !CreateParams.Flags.Info.Tile64; CreateParams.Flags.Info.TiledYf = 0; CreateParams.Flags.Info.TiledYs = 0; } } } } //Convert non linear & non-tiledX tiling selection by client to proper tiling. else if(CreateParams.Flags.Info.Linear + CreateParams.Flags.Info.TiledX == 0) { if(!GetGmmLibContext()->GetSkuTable().FtrTileY) { __GMM_ASSERT(!(CreateParams.Flags.Info.TiledYs || CreateParams.Flags.Info.TiledYf || CreateParams.Flags.Info.TiledY)); // On Xe_HP onwards translate UMD's TileY/TileYs request to Tile4/Tile64 respectively // Exclude TileX, Linear from override if((GetGmmLibContext()->GetSkuTable().FtrForceTile4) && (CreateParams.Flags.Info.TiledYs || CreateParams.Flags.Info.TiledY)) { CreateParams.Flags.Info.Tile64 = CreateParams.Flags.Info.TiledYs || (CreateParams.MSAA.NumSamples > 1) || CreateParams.Flags.Gpu.TiledResource; CreateParams.Flags.Info.Tile4 = !CreateParams.Flags.Info.Tile64; CreateParams.Flags.Info.TiledY = 0; CreateParams.Flags.Info.TiledYs = 0; CreateParams.Flags.Info.TiledW = 0; CreateParams.Flags.Info.TiledYf = 0; } // Displayable surfaces cannot be Tiled4/64. __GMM_ASSERT(!GetGmmLibContext()->GetSkuTable().FtrDisplayYTiling); //override displayable surfaces to TileX if(GetGmmLibContext()->GetSkuTable().FtrDisplayXTiling) { if(CreateParams.Flags.Gpu.FlipChain || CreateParams.Flags.Gpu.Overlay || CreateParams.Flags.Gpu.Presentable) { CreateParams.Flags.Info.TiledX = 1; CreateParams.Flags.Info.TiledY = 0; CreateParams.Flags.Info.Tile4 = 0; CreateParams.Flags.Info.Tile64 = 0; } } } } //ExistingSysMem allocations must be Linear __GMM_ASSERT(!CreateParams.Flags.Info.ExistingSysMem || CreateParams.Flags.Info.Linear); } if(GetGmmLibContext()->GetSkuTable().FtrMultiTileArch) { // For Naive apps, UMD does not populate multi tile arch params. // Gmm will populate them based on the kmd assigned tile to the umd process if(!CreateParams.MultiTileArch.Enable) { uint32_t GpuTile = 0; __GMM_ASSERT(CreateParams.MultiTileArch.GpuVaMappingSet == 0); __GMM_ASSERT(CreateParams.MultiTileArch.LocalMemEligibilitySet == 0); __GMM_ASSERT(CreateParams.MultiTileArch.LocalMemPreferredSet == 0); __GMM_ASSERT(GetGmmLibContext()->GetSkuTable().FtrAssignedGpuTile < 4); #if !__GMM_KMD__ GpuTile = GetGmmLibContext()->GetSkuTable().FtrAssignedGpuTile; CreateParams.MultiTileArch.GpuVaMappingSet = __BIT(GpuTile); #else GpuTile = 0; CreateParams.MultiTileArch.GpuVaMappingSet = GetGmmLibContext()->GetGtSysInfo()->MultiTileArchInfo.TileMask; #endif CreateParams.MultiTileArch.Enable = true; if(!CreateParams.Flags.Info.NonLocalOnly) { CreateParams.MultiTileArch.LocalMemEligibilitySet = __BIT(GpuTile); CreateParams.MultiTileArch.LocalMemPreferredSet = __BIT(GpuTile); } } } Surf.Type = CreateParams.Type; Surf.Format = CreateParams.Format; Surf.BaseWidth = CreateParams.BaseWidth64; Surf.BaseHeight = CreateParams.BaseHeight; Surf.Depth = CreateParams.Depth; Surf.MaxLod = CreateParams.MaxLod; Surf.ArraySize = CreateParams.ArraySize; Surf.Flags = CreateParams.Flags; Surf.MSAA = CreateParams.MSAA; Surf.Alignment.BaseAlignment = CreateParams.BaseAlignment; Surf.CachePolicy.Usage = CreateParams.Usage; Surf.MSAA.NumSamples = GFX_MAX(Surf.MSAA.NumSamples, 1); Surf.MaximumRenamingListLength = CreateParams.MaximumRenamingListLength; Surf.OverridePitch = CreateParams.OverridePitch; Surf.CpTag = CreateParams.CpTag; Surf.Flags.Info.__PreWddm2SVM = Surf.Flags.Info.SVM && !(GetGmmLibContext()->GetSkuTable().FtrWddm2GpuMmu || GetGmmLibContext()->GetSkuTable().FtrWddm2Svm); #if !__GMM_KMD__ && LHDM if(GetGmmLibContext()->GetWaTable().WaLLCCachingUnsupported) { Surf.Flags.Info.GttMapType = (CreateParams.Flags.Info.Cacheable) ? GMM_GTT_CACHETYPE_VLV_SNOOPED : GMM_GTT_CACHETYPE_UNCACHED; } if(GetGmmLibContext()->GetSkuTable().FtrCameraCaptureCaching == false && CreateParams.Flags.Gpu.CameraCapture) { Surf.Flags.Info.Cacheable = 0; } Surf.Flags.Wa.ForceStdAllocAlign = 0; #endif #if(_DEBUG || _RELEASE_INTERNAL) Surf.Platform = GetGmmLibContext()->GetPlatformInfo().Platform; #endif Surf.BitsPerPixel = BitsPerPixel; // Get pTextureCalc after surface evaluation GMM_TEXTURE_CALC *pTextureCalc = GMM_OVERRIDE_TEXTURE_CALC(&Surf, GetGmmLibContext()); GetGmmLibContext()->GetPlatformInfoObj()->SetCCSFlag(this->GetResFlags()); // Moderate down displayable flags if input parameters are not conducive. // Reject non displayable tiling modes if(Surf.Flags.Gpu.FlipChain || Surf.Flags.Gpu.Overlay) { if(Surf.Flags.Info.TiledY && !GetGmmLibContext()->GetSkuTable().FtrDisplayYTiling) { if(Surf.Flags.Gpu.FlipChainPreferred) { Surf.Flags.Gpu.Overlay = 0; Surf.Flags.Gpu.FlipChain = 0; } else { GMM_ASSERTDPF(0, "Y-Tiling mode not displayable"); //return false; } } } // Memory optimization for 64KB tiled Surface. if (!GetGmmLibContext()->GetSkuTable().FtrTileY) { if ((GetGmmLibContext()->GetSkuTable().FtrTile64Optimization) && Optimize64KBTile) { if ((GetGmmLibContext()->GetWaTable().Wa_14020040029) && (Surf.Flags.Gpu.Depth)) { // if SW uses Tile4 merely to reduce surface size for Depth buffers, // then use Tile64 instead GMM_SET_64KB_TILE(Surf.Flags, 1, GetGmmLibContext()); GMM_SET_4KB_TILE(Surf.Flags, 0, GetGmmLibContext()); //Also update CreateParams, if client reuses the modified struct, it'd see final tile-selection by Gmm. //Gmm's auto-tile-selection & tile-mode for size-optimization doesn't work for explicit tile-selection GMM_SET_64KB_TILE(CreateParams.Flags, 1, GetGmmLibContext()); GMM_SET_4KB_TILE(CreateParams.Flags, 0, GetGmmLibContext()); } else { if (pTextureCalc->SurfaceRequires64KBTileOptimization(&Surf)) { GMM_SET_64KB_TILE(Surf.Flags, 0, GetGmmLibContext()); GMM_SET_4KB_TILE(Surf.Flags, 1, GetGmmLibContext()); //Also update CreateParams, if client reuses the modified struct, it'd see final tile-selection by Gmm. //Gmm's auto-tile-selection & tile-mode for size-optimization doesn't work for explicit tile-selection GMM_SET_64KB_TILE(CreateParams.Flags, 0, GetGmmLibContext()); GMM_SET_4KB_TILE(CreateParams.Flags, 1, GetGmmLibContext()); } } } } // Convert Any Pseudo Creation Params to Actual... if(Surf.Flags.Gpu.UnifiedAuxSurface) { AuxSurf = Surf; if(Surf.Flags.Gpu.Depth && Surf.Flags.Gpu.CCS) //Depth + HiZ+CCS { //GMM_ASSERTDPF(Surf.Flags.Gpu.HiZ, "Lossless Z compression supported when Depth+HiZ+CCS is unified"); AuxSecSurf = Surf; AuxSecSurf.Type = GetGmmLibContext()->GetSkuTable().FtrFlatPhysCCS ? RESOURCE_INVALID : AuxSecSurf.Type; Surf.Flags.Gpu.HiZ = 0; //Its depth buffer, so clear HiZ AuxSecSurf.Flags.Gpu.HiZ = 0; AuxSurf.Flags.Gpu.IndirectClearColor = 0; //Clear Depth flags from HiZ, contained with separate/legacy HiZ when Depth isn't compressible. AuxSurf.Flags.Gpu.CCS = 0; AuxSurf.Type = (AuxSurf.Flags.Gpu.HiZ) ? AuxSurf.Type : RESOURCE_INVALID; AuxSurf.Flags.Info.RenderCompressed = AuxSurf.Flags.Info.MediaCompressed = 0; AuxSurf.Flags.Info.NotCompressed = 1; } else if(Surf.Flags.Gpu.Depth && Surf.Flags.Gpu.HiZ && !Surf.Flags.Gpu.CCS) // Depth + HiZ only, CCS is disabled { // main surface is depth, AuxSurf is HiZ Surf.Flags.Gpu.HiZ = 0; //depth buffer, clear HiZ AuxSurf.Flags.Gpu.IndirectClearColor = 0; //Clear fastClear from HiZ } else if(Surf.Flags.Gpu.SeparateStencil && Surf.Flags.Gpu.CCS) //Stencil compression { AuxSurf.Flags.Gpu.SeparateStencil = 0; Surf.Flags.Gpu.CCS = 0; if(GMM_SUCCESS != pTextureCalc->PreProcessTexSpecialCases(&Surf)) { return false; } Surf.Flags.Gpu.CCS = 1; AuxSurf.Type = GetGmmLibContext()->GetSkuTable().FtrFlatPhysCCS ? RESOURCE_INVALID : AuxSurf.Type; } else if(Surf.MSAA.NumSamples > 1 && Surf.Flags.Gpu.CCS) //MSAA+MCS+CCS { GMM_ASSERTDPF(Surf.Flags.Gpu.MCS, "Lossless MSAA supported when MSAA+MCS+CCS is unified"); AuxSecSurf = Surf; AuxSecSurf.Type = GetGmmLibContext()->GetSkuTable().FtrFlatPhysCCS ? RESOURCE_INVALID : AuxSecSurf.Type; AuxSecSurf.Flags.Gpu.MCS = 0; AuxSurf.Flags.Gpu.CCS = 0; AuxSurf.Flags.Info.RenderCompressed = AuxSurf.Flags.Info.MediaCompressed = 0; AuxSurf.Flags.Info.NotCompressed = 1; } else if(Surf.Flags.Gpu.CCS) { AuxSurf.Type = (GetGmmLibContext()->GetSkuTable().FtrFlatPhysCCS && !Surf.Flags.Gpu.ProceduralTexture) ? RESOURCE_INVALID : AuxSurf.Type; } if(AuxSurf.Type != RESOURCE_INVALID && GMM_SUCCESS != pTextureCalc->PreProcessTexSpecialCases(&AuxSurf)) { return false; } if(AuxSecSurf.Type != RESOURCE_INVALID && GMM_SUCCESS != pTextureCalc->PreProcessTexSpecialCases(&AuxSecSurf)) { return false; } } else { if(GMM_SUCCESS != pTextureCalc->PreProcessTexSpecialCases(&Surf)) { return false; } } RotateInfo = CreateParams.RotateInfo; if(GetGmmLibContext()->GetSkuTable().FtrMultiTileArch) { MultiTileArch = CreateParams.MultiTileArch; } // For Xe2 RenderCompressed and MediaCompressed to be unset if (GetGmmLibContext()->GetSkuTable().FtrXe2Compression) { //Deny compression Surf.Flags.Info.RenderCompressed = 0; Surf.Flags.Info.MediaCompressed = 0; } return true; } ///////////////////////////////////////////////////////////////////////////////////// /// Validates the parameters passed in by clients to make sure they do not /// conflict or ask for unsupporting combinations/features. /// /// @return 1 is validation passed. 0 otherwise. ///////////////////////////////////////////////////////////////////////////////////// uint8_t GMM_STDCALL GmmLib::GmmResourceInfoCommon::ValidateParams() { __GMM_BUFFER_TYPE Restrictions = {0}; const __GMM_PLATFORM_RESOURCE *pPlatformResource = NULL; GMM_TEXTURE_CALC * pTextureCalc = NULL; bool AllowMaxWidthViolations = false; bool AllowMaxHeightViolations = false; uint8_t Status = 0; GMM_DPF_ENTER; __GMM_ASSERTPTR(GetGmmLibContext(), 0); #if(defined(__GMM_KMD__) && (_DEBUG || _RELEASE_INTERNAL)) //KMD Debug and Release Internal Drivers only //if GMM_TEXTURE_INFO's platform type != native platform //then initialize the OverridePlatformInfo. //If GMM_TEXTURE_INFO's platform type == IGFX_UNKNOWN_CORE then it means that UMD driver is //in "Release" version and passes all zeros in Surf.Platform if(GFX_GET_CURRENT_RENDERCORE(Surf.Platform) == IGFX_UNKNOWN_CORE) { Surf.Platform = GetGmmLibContext()->GetPlatformInfo().Platform; // If this is a unified surface then make sure the AUX surface has the same platform info if(Surf.Flags.Gpu.UnifiedAuxSurface) { AuxSurf.Platform = Surf.Platform; AuxSecSurf.Platform = Surf.Platform; } } if(GetGmmLibContext()->GetPlatformInfoObj() != NULL && (GFX_GET_CURRENT_RENDERCORE(Surf.Platform) != GFX_GET_CURRENT_RENDERCORE(GetGmmLibContext()->GetPlatformInfo().Platform)) && (GetGmmLibContext()->GetOverridePlatformInfoObj() == NULL || (GFX_GET_CURRENT_RENDERCORE(Surf.Platform) != GFX_GET_CURRENT_RENDERCORE(GetGmmLibContext()->GetOverridePlatformInfo().Platform)))) { //Ensure override is a future platform. __GMM_ASSERT(GFX_GET_CURRENT_RENDERCORE(Surf.Platform) > GFX_GET_CURRENT_RENDERCORE(GetGmmLibContext()->GetPlatformInfo().Platform)); GetGmmLibContext()->SetOverridePlatformInfoObj(GetGmmLibContext()->CreatePlatformInfo(Surf.Platform, true)); if(GetGmmLibContext()->GetOverrideTextureCalc()) { delete(GetGmmLibContext()->GetOverrideTextureCalc()); GetGmmLibContext()->SetOverrideTextureCalc(NULL); } GetGmmLibContext()->SetOverrideTextureCalc(GetGmmLibContext()->CreateTextureCalc(Surf.Platform, true)); } #endif pPlatformResource = GMM_OVERRIDE_PLATFORM_INFO(&Surf, GetGmmLibContext()); pTextureCalc = GMM_OVERRIDE_TEXTURE_CALC(&Surf, GetGmmLibContext()); if (!pTextureCalc) { GMM_ASSERTDPF(0, "Texture Calculation pointer is NULL."); goto ERROR_CASE; } __GMM_ASSERT(!( Surf.Flags.Gpu.Query && !Surf.Flags.Info.Cacheable)); // Why query not set as cacheable? If not cacheable, what keeps from stolen memory (because STORE_DWORD/PIPE_CONTROL/etc. targets can't be in stolen)? if(Surf.Flags.Gpu.HiZ) { // HiZ checked in PreProcessTexSpecialCases before legal HZ_Width/Height expansion. AllowMaxWidthViolations = true; AllowMaxHeightViolations = true; } // check bpp if(((Surf.BitsPerPixel < 8) || (Surf.BitsPerPixel % GMM_BITS(8))) && !(Surf.BitsPerPixel == 1)) { GMM_ASSERTDPF(0, "Invalid BitsPerPixel!"); goto ERROR_CASE; } // Check at least one tile pref set. // Yf/Ys checked explicitly here, require one of Y or Linear depending on resource type (e.g 1D-->Linear) // that TODO: could be automatically promoted. if((Surf.Flags.Info.Linear == 0) && (Surf.Flags.Info.TiledX == 0) && (Surf.Flags.Info.TiledW == 0) && (Surf.Flags.Info.TiledYf == 0) && !GMM_IS_4KB_TILE(Surf.Flags) && !GMM_IS_64KB_TILE(Surf.Flags)) { GMM_ASSERTDPF(0, "No Tile or Linear preference specified!"); goto ERROR_CASE; } if(Surf.Flags.Info.Tile64 || Surf.Flags.Info.TiledYf || Surf.Flags.Info.TiledYs) { if(!GMM_IS_SUPPORTED_BPP_ON_TILE_64_YF_YS(Surf.BitsPerPixel)) { GMM_ASSERTDPF(0, "BPP not supported on selected Tile format!"); goto ERROR_CASE; } } if(!__CanSupportStdTiling(Surf, GetGmmLibContext())) { GMM_ASSERTDPF(0, "Invalid TileYf/TileYs usage!"); goto ERROR_CASE; } if(Surf.TileMode < TILE_NONE || Surf.TileMode >= GMM_TILE_MODES) { GMM_ASSERTDPF(0, "Invalid TileMode usage!"); goto ERROR_CASE; } if(!((Surf.Format > GMM_FORMAT_INVALID) && (Surf.Format < GMM_RESOURCE_FORMATS))) { GMM_ASSERTDPF(0, "Invalid Resource Format!"); goto ERROR_CASE; } // Check resource format is supported on running platform if(IsPresentableformat() == false) { GMM_ASSERTDPF(0, "Bad Format!"); goto ERROR_CASE; } if((Surf.Type == RESOURCE_PRIMARY) && !Surf.Flags.Gpu.FlipChain) { GMM_ASSERTDPF(0, "Primary does not have FlipChain flag set."); goto ERROR_CASE; } if(Surf.Flags.Gpu.Overlay && Surf.Flags.Gpu.FlipChain) { GMM_ASSERTDPF(0, "Overlay and FlipChain flags set. S3D logic may fail."); goto ERROR_CASE; } // Displayable surfaces must remain Tile4 if(((!GetGmmLibContext()->GetSkuTable().FtrDisplayDisabled) && (Surf.Flags.Gpu.Overlay || Surf.Flags.Gpu.FlipChain)) && (!(Surf.Flags.Info.Linear || Surf.Flags.Info.TiledX || GMM_IS_4KB_TILE(Surf.Flags)))) { GMM_ASSERTDPF(0, "Unsupported tiling format for displayable resource."); goto ERROR_CASE; } if(GetGmmLibContext()->GetSkuTable().FtrLocalMemory) { GMM_ASSERTDPF(((Surf.Flags.Info.NonLocalOnly && Surf.Flags.Info.LocalOnly) == 0), "Incorrect segment preference, cannot be both local and system memory."); // Before overriding the flags predetermine if compression request is deniable or not. if(!Surf.Flags.Info.LocalOnly && (!(Surf.Flags.Gpu.Overlay || Surf.Flags.Gpu.FlipChain)) && !(Surf.Flags.Info.HardwareProtected)) { Surf.Flags.Wa.DeniableLocalOnlyForCompression = 1; } if(Surf.Flags.Gpu.Overlay || Surf.Flags.Gpu.FlipChain) { if(Surf.Flags.Info.NonLocalOnly) { GMM_ASSERTDPF(0, "Overlay and FlipChain cannot be in system memory."); goto ERROR_CASE; } Surf.Flags.Info.LocalOnly = 1; Surf.Flags.Info.NonLocalOnly = 0; } if(GetGmmLibContext()->GetSkuTable().FtrFlatPhysCCS && !GetGmmLibContext()->GetSkuTable().FtrXe2Compression && (Surf.Flags.Info.RenderCompressed || Surf.Flags.Info.MediaCompressed)) { if(Surf.Flags.Info.NonLocalOnly) { GMM_ASSERTDPF(0, "Compressible surfaces cannot be in system memory."); goto ERROR_CASE; } Surf.Flags.Info.LocalOnly = 1; Surf.Flags.Info.NonLocalOnly = 0; } if(!Surf.Flags.Info.NotLockable && Surf.Flags.Info.Shared) { if(Surf.Flags.Info.LocalOnly) { GMM_ASSERTDPF(0, "Lockable Shared cannot be in local memory."); goto ERROR_CASE; } Surf.Flags.Info.LocalOnly = 0; Surf.Flags.Info.NonLocalOnly = 1; } if(Surf.Flags.Gpu.CameraCapture) { if(Surf.Flags.Info.LocalOnly) { GMM_ASSERTDPF(0, "CameraCapture cannot be in local memory."); } Surf.Flags.Info.LocalOnly = 0; Surf.Flags.Info.NonLocalOnly = 1; } if(GetGmmLibContext()->GetWaTable().Wa64kbMappingAt2mbGranularity && (!GetGmmLibContext()->GetSkuTable().FtrLocalMemoryAllows4KB) && !Surf.Flags.Info.NonLocalOnly) { Surf.Flags.Info.LocalOnly = true; } } else { Surf.Flags.Info.LocalOnly = false; //Zero out on iGPU if (GetGmmLibContext()->GetSkuTable().FtrXe2Compression && Surf.Flags.Info.XAdapter) { Surf.Flags.Info.NotCompressed = 1; // disable compression for XAdapter resources on iGPU, Surf.Flags.Gpu.CCS = 0; Surf.Flags.Gpu.UnifiedAuxSurface = 0; Surf.Flags.Gpu.IndirectClearColor = 0; Surf.Flags.Gpu.MCS = 0; } } if (GetGmmLibContext()->GetSkuTable().FtrXe2Compression) { if (Surf.Flags.Info.TiledX) { if (!(Surf.Flags.Gpu.FlipChain || Surf.Flags.Gpu.Overlay)) { GMM_ASSERTDPF(0, "TiledX request for non displayable"); } Surf.Flags.Info.NotCompressed = 1; // disable compression for TileX resources } if ((Surf.Flags.Gpu.FlipChain || Surf.Flags.Gpu.Overlay) && !Surf.Flags.Info.Tile4) { Surf.Flags.Info.NotCompressed = 1; //Disable compression if displayable are not tile4 } } if((GFX_GET_CURRENT_RENDERCORE(pPlatformResource->Platform) < IGFX_GEN8_CORE) && Surf.Flags.Info.TiledW) { GMM_ASSERTDPF(0, "Flag not supported on this platform."); goto ERROR_CASE; } if((GFX_GET_CURRENT_RENDERCORE(pPlatformResource->Platform) > IGFX_GEN11_CORE) && Surf.Flags.Info.TiledW) { GMM_ASSERTDPF(0, "Flag not supported on this platform."); goto ERROR_CASE; } if((GFX_GET_CURRENT_RENDERCORE(pPlatformResource->Platform) < IGFX_GEN9_CORE) && #if(_DEBUG || _RELEASE_INTERNAL) !GetGmmLibContext()->GetWaTable().WaDisregardPlatformChecks && #endif Surf.Flags.Gpu.MMC) { GMM_ASSERTDPF(0, "Flag not supported on this platform."); goto ERROR_CASE; } //For Media Memory Compression -- if((Status = GetGmmLibContext()->GetPlatformInfoObj()->ValidateMMC(Surf)) == 0) { GMM_ASSERTDPF(0, "Invalid flag or array size!"); goto ERROR_CASE; } if(!GetGmmLibContext()->GetSkuTable().FtrTileY) { if(Surf.Flags.Gpu.TiledResource && ((Surf.Flags.Info.Linear && !(Surf.Type == RESOURCE_BUFFER)) || Surf.Flags.Info.TiledYs || Surf.Flags.Info.TiledYf || Surf.Flags.Info.TiledY)) { GMM_ASSERTDPF(0, "Invalid Tile for TiledResource!"); goto ERROR_CASE; } if(GMM_IS_64KB_TILE(Surf.Flags) && (Surf.MSAA.NumSamples > 1) && (Surf.MaxLod != 0)) { GMM_ASSERTDPF(0, "Mipped MSAA not supported for Tile64!"); goto ERROR_CASE; } // Tile4 does not support MSAA. if(GMM_IS_4KB_TILE(Surf.Flags) && (Surf.MSAA.NumSamples > 1)) { GMM_ASSERTDPF(0, "No MSAA support for Tile4!"); goto ERROR_CASE; } } __GMM_ASSERT(!(GetGmmLibContext()->GetSkuTable().FtrTileY && (Surf.Flags.Info.Tile4 || Surf.Flags.Info.Tile64))); //GMM asserts that ExistingSysMem allocation (whose malloc is outside GmmLib) are either //SVM Buffer, Index Buffer, Vertex Buffers, Render Target, Texture if(Surf.Flags.Info.ExistingSysMem && !Surf.ExistingSysMem.IsGmmAllocated && !Surf.ExistingSysMem.IsPageAligned) { if(!(Surf.Flags.Gpu.RenderTarget || Surf.Flags.Gpu.Vertex || Surf.Flags.Gpu.Index || Surf.Flags.Gpu.Texture || Surf.Flags.Info.Linear || Surf.Flags.Info.SVM)) { GMM_ASSERTDPF(0, "Flag not supported by ExistingSysMem alloc!"); goto ERROR_CASE; } if(Surf.Type == RESOURCE_3D || Surf.Type == RESOURCE_CUBE || Surf.MaxLod || GmmIsYUVPlanar(Surf.Format)) { GMM_ASSERTDPF(0, "Invalid ExistingSysMem resource Type/Format"); goto ERROR_CASE; } } pTextureCalc->GetResRestrictions(&Surf, Restrictions); // Check array size to make sure it meets HW limits if((Surf.ArraySize > Restrictions.MaxArraySize) && ((RESOURCE_1D == Surf.Type) || (RESOURCE_2D == Surf.Type) || (RESOURCE_CUBE == Surf.Type))) { GMM_ASSERTDPF(0, "Invalid array size!"); goto ERROR_CASE; } // Check dimensions to make sure it meets HW max limits if(((Surf.BaseHeight > Restrictions.MaxHeight) && !AllowMaxHeightViolations) || ((Surf.BaseWidth > Restrictions.MaxWidth) && !AllowMaxWidthViolations) || (Surf.Depth > Restrictions.MaxDepth)) // Any reason why MaxDepth != 1 for Tex2D { GMM_ASSERTDPF(0, "Invalid Dimension. Greater than max!"); goto ERROR_CASE; } // Check width to make sure it meets Yx requirements if(((Surf.Format == GMM_FORMAT_Y8_UNORM_VA) && (Surf.BaseWidth % 4)) || ((Surf.Format == GMM_FORMAT_Y16_UNORM) && (Surf.BaseWidth % 2)) || ((Surf.Format == GMM_FORMAT_Y1_UNORM) && (Surf.BaseWidth % 32))) { GMM_ASSERTDPF(0, "Invalid width!"); goto ERROR_CASE; } // Check dimensions to make sure it meets HW min limits if((Surf.BaseHeight < Restrictions.MinHeight) || (Surf.BaseWidth < Restrictions.MinWidth) || (Surf.Depth < Restrictions.MinDepth)) { GMM_ASSERTDPF(0, "Invalid Dimension. Less than min!"); goto ERROR_CASE; } // check mip map if(Surf.MaxLod > pPlatformResource->MaxLod) { GMM_ASSERTDPF(0, "Invalid mip map chain specified!"); goto ERROR_CASE; } // MIPs are not supported for tiled Yf/Ys planar surfaces if((Surf.MaxLod) && GmmIsPlanar(Surf.Format) && (Surf.Flags.Info.TiledYf || GMM_IS_64KB_TILE(Surf.Flags))) { GMM_ASSERTDPF(0, "Invalid mip map chain specified!"); goto ERROR_CASE; } // check depth buffer tilings if((Surf.Flags.Gpu.Depth == 1) && (Surf.Flags.Info.TiledX == 1)) { GMM_ASSERTDPF(0, "Invalid Tiling for Depth Buffer!"); goto ERROR_CASE; } #if DBG // Check if stencil buffer gpu flag is set w/ other flags if(Surf.Flags.Gpu.SeparateStencil == 1) { GMM_RESOURCE_FLAG OnlySeparateStencilGpuFlag; memset(&OnlySeparateStencilGpuFlag.Gpu, 0, sizeof(OnlySeparateStencilGpuFlag.Gpu)); OnlySeparateStencilGpuFlag.Gpu.SeparateStencil = 1; if(memcmp(&Surf.Flags.Gpu, &OnlySeparateStencilGpuFlag.Gpu, sizeof(OnlySeparateStencilGpuFlag.Gpu))) { GMM_ASSERTDPF(0, "Should not set w/ other flags b/c vertical alignment is " "unique for separate stencil and incompatible w/ other " "usages such as render target."); goto ERROR_CASE; } } #endif // MSAA Restrictions if((Surf.MSAA.NumSamples > 1) && !( //--- Legitimate MSAA Case ------------------------------------------ (Surf.Type == RESOURCE_2D) && (Surf.Flags.Gpu.Depth || Surf.Flags.Gpu.HiZ || Surf.Flags.Gpu.RenderTarget || Surf.Flags.Gpu.SeparateStencil) && // Single-LOD (pre-SKL)... ((GFX_GET_CURRENT_RENDERCORE(pPlatformResource->Platform) >= IGFX_GEN9_CORE) || (Surf.MaxLod == 0)) && // TileYF cannot be MSAA'ed (pre-Gen10)... ((GFX_GET_CURRENT_RENDERCORE(pPlatformResource->Platform) >= IGFX_GEN10_CORE) || !Surf.Flags.Info.TiledYf) && // Tile64 MSAA (Xe_HP) (GetGmmLibContext()->GetSkuTable().FtrTileY || !GMM_IS_64KB_TILE(Surf.Flags) || (Surf.MaxLod == 0)) && // Tile4 does not support MSAA (GetGmmLibContext()->GetSkuTable().FtrTileY || !GMM_IS_4KB_TILE(Surf.Flags)) && // Non-Compressed/YUV... !GmmIsCompressed(GetGmmLibContext(), Surf.Format) && !GmmIsYUVPacked(Surf.Format) && !GmmIsPlanar(Surf.Format) && // Supported Sample Count for Platform... (((GFX_GET_CURRENT_RENDERCORE(pPlatformResource->Platform) >= IGFX_GEN7_CORE) && ((Surf.MSAA.NumSamples == 4) || (Surf.MSAA.NumSamples == 8))) || ((GFX_GET_CURRENT_RENDERCORE(pPlatformResource->Platform) >= IGFX_GEN8_CORE) && ((Surf.MSAA.NumSamples == 2))) || ((GFX_GET_CURRENT_RENDERCORE(pPlatformResource->Platform) >= IGFX_GEN9_CORE) && ((Surf.MSAA.NumSamples == 16)))))) { GMM_ASSERTDPF(0, "Invalid MSAA usage!"); goto ERROR_CASE; } // CCS Restrictions if(Surf.Flags.Gpu.CCS) { if((Status = GetGmmLibContext()->GetPlatformInfoObj()->ValidateCCS(Surf)) == 0) { GMM_ASSERTDPF(0, "Invalid CCS usage!"); goto ERROR_CASE; } if(Surf.Flags.Info.RenderCompressed && Surf.Flags.Info.MediaCompressed) { GMM_ASSERTDPF(0, "Invalid CCS usage - can't be both RC and MC!"); goto ERROR_CASE; } } // UnifiedAuxSurface Restrictions if((Status = GetGmmLibContext()->GetPlatformInfoObj()->ValidateUnifiedAuxSurface(Surf)) == 0) { GMM_ASSERTDPF(0, "Invalid UnifiedAuxSurface usage!"); goto ERROR_CASE; } // IndirectClearColor Restrictions if((Surf.Flags.Gpu.IndirectClearColor) && !( //--- Legitimate IndirectClearColor Case ------------------------------------------ (((GFX_GET_CURRENT_RENDERCORE(pPlatformResource->Platform) >= IGFX_GEN9_CORE) && Surf.Flags.Gpu.UnifiedAuxSurface) || ((GFX_GET_CURRENT_RENDERCORE(pPlatformResource->Platform) > IGFX_GEN11_CORE) && (Surf.Flags.Gpu.HiZ || Surf.Flags.Gpu.SeparateStencil))))) { GMM_ASSERTDPF(0, "Invalid IndirectClearColor usage!"); goto ERROR_CASE; } // CornerTexelMode Restrictions if(Surf.Flags.Info.CornerTexelMode && (!( //--- Legitimate CornerTexelMode Case ------------------------------------------- (GFX_GET_CURRENT_RENDERCORE(pPlatformResource->Platform) >= IGFX_GEN11_CORE) && (!GmmIsPlanar(Surf.Format)) && (!Surf.Flags.Info.StdSwizzle)))) { GMM_ASSERTDPF(0, "Flag.Info.CornerTexelMode not supported on this platform."); goto ERROR_CASE; } //MultiTileArch params if(GetGmmLibContext()->GetSkuTable().FtrMultiTileArch) { /* MultiTileArch validation criteria - MultiTileArch.Enable must be set. - NonLocalOnly alloc must have LocalEligibilitySet and LocalPreferenceSet both zero - LocalOnly alloc must have non-zero LocalEligibilitySet - GpuVaMappingSet/LocalEligibilitySet must be subset of GtSysInfo.TileMask - PreferredSet must be subset of EligibilitySet or zero */ if(!( // Legitimate cases MultiTileArch.Enable && (Surf.Flags.Info.NonLocalOnly || MultiTileArch.LocalMemEligibilitySet) && ((MultiTileArch.GpuVaMappingSet & GetGmmLibContext()->GetGtSysInfo()->MultiTileArchInfo.TileMask) == MultiTileArch.GpuVaMappingSet) && ((MultiTileArch.LocalMemEligibilitySet & GetGmmLibContext()->GetGtSysInfo()->MultiTileArchInfo.TileMask) == MultiTileArch.LocalMemEligibilitySet) && ((MultiTileArch.LocalMemEligibilitySet & MultiTileArch.LocalMemPreferredSet) == MultiTileArch.LocalMemPreferredSet))) { GMM_ASSERTDPF(0, "Invalid MultiTileArch allocation params"); goto ERROR_CASE; } } // check 2D, 3D & Cubemap dimensions switch(Surf.Type) { case RESOURCE_1D: case RESOURCE_2D: case RESOURCE_3D: { if(!Surf.BaseWidth || !Surf.BaseHeight) { GMM_ASSERTDPF(0, "Width or Height is 0!"); goto ERROR_CASE; } break; } case RESOURCE_CUBE: { if(!Surf.BaseWidth || !Surf.BaseHeight) { GMM_ASSERTDPF(0, "Cubemap Dimensions invalid!"); goto ERROR_CASE; } if(Surf.BaseWidth != Surf.BaseHeight) { GMM_ASSERTDPF(0, "Cubemap Dimensions invalid (width != Height)!"); goto ERROR_CASE; } break; } case RESOURCE_SCRATCH: case RESOURCE_BUFFER: { if(Surf.BaseHeight != 1) { GMM_ASSERTDPF(0, "Linear surface height not 1!"); goto ERROR_CASE; } break; } default: if (!Surf.BaseWidth || !Surf.BaseHeight) { GMM_ASSERTDPF(0, "Width or Height is 0!"); goto ERROR_CASE; } break; } GMM_DPF_EXIT; return 1; ERROR_CASE: __GMM_ASSERT(0); return 0; } //============================================================================= // // Function: GetDisplayCompressionSupport // // Desc: Returns true if display hw supports lossless render/media decompression // else returns false. // Umds can call it to decide if full resolve is required // // Parameters: // See function arguments. // // Returns: // uint8_t //----------------------------------------------------------------------------- uint8_t GMM_STDCALL GmmLib::GmmResourceInfoCommon::GetDisplayCompressionSupport() { uint8_t ComprSupported = 0; GMM_RESOURCE_FORMAT Format = Surf.Format; if(Surf.Flags.Gpu.UnifiedAuxSurface) { bool IsSupportedRGB64_16_16_16_16 = false; bool IsSupportedRGB32_8_8_8_8 = false; bool IsSupportedRGB32_2_10_10_10 = false; bool IsSupportedMediaFormats = false; switch(Format) //RGB64 16:16 : 16 : 16 FP16 { case GMM_FORMAT_R16G16B16A16_FLOAT: case GMM_FORMAT_R16G16B16X16_FLOAT: IsSupportedRGB64_16_16_16_16 = true; default: break; } switch(Format) //RGB32 8 : 8 : 8 : 8 { case GMM_FORMAT_B8G8R8A8_UNORM: case GMM_FORMAT_R8G8B8A8_UNORM: case GMM_FORMAT_B8G8R8X8_UNORM: case GMM_FORMAT_R8G8B8X8_UNORM: case GMM_FORMAT_R8G8B8A8_UNORM_SRGB: case GMM_FORMAT_B8X8_UNORM_G8R8_SNORM: case GMM_FORMAT_X8B8_UNORM_G8R8_SNORM: case GMM_FORMAT_A8X8_UNORM_G8R8_SNORM: case GMM_FORMAT_B8G8R8A8_UNORM_SRGB: case GMM_FORMAT_B8G8R8X8_UNORM_SRGB: case GMM_FORMAT_R8G8B8A8_SINT: case GMM_FORMAT_R8G8B8A8_SNORM: case GMM_FORMAT_R8G8B8A8_SSCALED: case GMM_FORMAT_R8G8B8A8_UINT: case GMM_FORMAT_R8G8B8A8_USCALED: case GMM_FORMAT_R8G8B8X8_UNORM_SRGB: IsSupportedRGB32_8_8_8_8 = true; default: break; } switch(Format) //RGB32 2 : 10 : 10 : 10 { case GMM_FORMAT_B10G10R10X2_UNORM: case GMM_FORMAT_R10G10B10A2_UNORM: case GMM_FORMAT_B10G10R10A2_UNORM: case GMM_FORMAT_B10G10R10A2_SINT: case GMM_FORMAT_B10G10R10A2_SNORM: case GMM_FORMAT_B10G10R10A2_SSCALED: case GMM_FORMAT_B10G10R10A2_UINT: case GMM_FORMAT_B10G10R10A2_UNORM_SRGB: case GMM_FORMAT_B10G10R10A2_USCALED: case GMM_FORMAT_R10G10B10_FLOAT_A2_UNORM: case GMM_FORMAT_R10G10B10_SNORM_A2_UNORM: case GMM_FORMAT_R10G10B10A2_SINT: case GMM_FORMAT_R10G10B10A2_SNORM: case GMM_FORMAT_R10G10B10A2_SSCALED: case GMM_FORMAT_R10G10B10A2_UINT: case GMM_FORMAT_R10G10B10A2_UNORM_SRGB: case GMM_FORMAT_R10G10B10A2_USCALED: case GMM_FORMAT_R10G10B10X2_USCALED: case GMM_FORMAT_R10G10B10_XR_BIAS_A2_UNORM: IsSupportedRGB32_2_10_10_10 = true; default: break; } switch(Format) { case GMM_FORMAT_YUY2: //YUV422 8 bpc case GMM_FORMAT_NV12: //YUV420 - NV12 case GMM_FORMAT_P010: //YUV420 - P0xx case GMM_FORMAT_P016: case GMM_FORMAT_Y210: //YUV422 - Y210, Y212, Y216 case GMM_FORMAT_Y216: case GMM_FORMAT_Y410: //YUV444 - Y410 case GMM_FORMAT_Y416: IsSupportedMediaFormats = true; //YUV444 - Y412, Y416 default: break; } //Check fmt is display decompressible ComprSupported = GetGmmLibContext()->GetPlatformInfoObj()->CheckFmtDisplayDecompressible(Surf, IsSupportedRGB64_16_16_16_16, IsSupportedRGB32_8_8_8_8, IsSupportedRGB32_2_10_10_10, IsSupportedMediaFormats); } return ComprSupported; } //============================================================================= // // Function: GetDisplayFastClearSupport // // Desc: Returns 1 if display hw supports fast clear else returns 0. // Umds can call it to decide if FC resolve is required // // Parameters: // See function arguments. // // Returns: // uint8_t //----------------------------------------------------------------------------- uint8_t GMM_STDCALL GmmLib::GmmResourceInfoCommon::GetDisplayFastClearSupport() { uint8_t FCSupported = 0; if(GFX_GET_CURRENT_RENDERCORE(GetGmmLibContext()->GetPlatformInfo().Platform) >= IGFX_GEN11_CORE) { FCSupported = GetDisplayCompressionSupport() && !GmmIsPlanar(Surf.Format); FCSupported &= Surf.Flags.Gpu.IndirectClearColor; } return FCSupported; } gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/Resource/GmmRestrictions.cpp000066400000000000000000000773601466655022700255140ustar00rootroot00000000000000/*============================================================================== Copyright(c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ============================================================================*/ #include "Internal/Common/GmmLibInc.h" ///////////////////////////////////////////////////////////////////////////////////// /// Checks that clients only set Presentable flag during a resource allocation, ONLY /// when a platform supported render target is selected in ::GMM_RESOURCE_FORMAT enum. /// /// @return true if displayable, false otherwise. ///////////////////////////////////////////////////////////////////////////////////// bool GmmLib::GmmResourceInfoCommon::IsPresentableformat() { const GMM_PLATFORM_INFO *pPlatform; const GMM_FORMAT_ENTRY * FormatTable = NULL; GMM_DPF_ENTER; __GMM_ASSERTPTR(GetGmmLibContext(), false); pPlatform = GMM_OVERRIDE_PLATFORM_INFO(&Surf, GetGmmLibContext()); FormatTable = &(pPlatform->FormatTable[0]); if(Surf.Flags.Gpu.Presentable == false) { // When Presentable flag is not set, no reason to check for valid RT // platform supported format. Safe to return true. return true; } if((Surf.Format > GMM_FORMAT_INVALID) && (Surf.Format < GMM_RESOURCE_FORMATS)) { if((FormatTable[Surf.Format].RenderTarget) && (FormatTable[Surf.Format].Supported)) { return true; } else { GMM_ASSERTDPF(0, "Present flag can only be set w/ a format!"); return false; } } return false; } ///////////////////////////////////////////////////////////////////////////////////// /// Returns the restrictions that a particular resource must follow on a particular /// OS or hardware. /// /// @param[out] Restrictions: restrictions that this resource must adhere to ///////////////////////////////////////////////////////////////////////////////////// void GmmLib::GmmResourceInfoCommon::GetRestrictions(__GMM_BUFFER_TYPE &Restrictions) { GMM_DPF_ENTER; GMM_TEXTURE_CALC *pTextureCalc = NULL; pTextureCalc = GMM_OVERRIDE_TEXTURE_CALC(&Surf, GetGmmLibContext()); if (pTextureCalc) { pTextureCalc->GetResRestrictions(&Surf, Restrictions); } GMM_DPF_EXIT; } //============================================================================= // // Function: GmmResGetRestrictions // // Desc: This routine returns resource restrictions // // Parameters: // pPlatform: ptr to HW_DEVICE_EXTENSION // pResourceInfo: ptr to GMM_RESOURCE_INFO // pRestrictions: ptr to restrictions // // Returns: // void // //----------------------------------------------------------------------------- void GMM_STDCALL GmmResGetRestrictions(GMM_RESOURCE_INFO *pResourceInfo, __GMM_BUFFER_TYPE *pRestrictions) { pResourceInfo->GetRestrictions(*pRestrictions); } ///////////////////////////////////////////////////////////////////////////////////// /// Returns the best restrictions by comparing two buffer types. Each buffer type /// carries alignment and size restrictions. /// /// @param[in] pFirstBuffer: Contains surface alignment and size restrictions /// @param[in] pSecondBuffer: Contains surface alignment and size restrictions /// /// @return Best Restrictions based on the two parameters passed ///////////////////////////////////////////////////////////////////////////////////// __GMM_BUFFER_TYPE *GmmLib::GmmTextureCalc::GetBestRestrictions(__GMM_BUFFER_TYPE * pFirstBuffer, const __GMM_BUFFER_TYPE *pSecondBuffer) { GMM_DPF_ENTER; if(IsRestrictionInvalid(pFirstBuffer)) //default { *pFirstBuffer = *pSecondBuffer; return pFirstBuffer; } pFirstBuffer->Alignment = GFX_MAX(pFirstBuffer->Alignment, pSecondBuffer->Alignment); pFirstBuffer->PitchAlignment = GFX_MAX(pFirstBuffer->PitchAlignment, pSecondBuffer->PitchAlignment); pFirstBuffer->RenderPitchAlignment = GFX_MAX(pFirstBuffer->RenderPitchAlignment, pSecondBuffer->RenderPitchAlignment); pFirstBuffer->LockPitchAlignment = GFX_MAX(pFirstBuffer->LockPitchAlignment, pSecondBuffer->LockPitchAlignment); pFirstBuffer->MinPitch = GFX_MAX(pFirstBuffer->MinPitch, pSecondBuffer->MinPitch); pFirstBuffer->MinAllocationSize = GFX_MAX(pFirstBuffer->MinAllocationSize, pSecondBuffer->MinAllocationSize); pFirstBuffer->MinDepth = GFX_MAX(pFirstBuffer->MinDepth, pSecondBuffer->MinDepth); pFirstBuffer->MinHeight = GFX_MAX(pFirstBuffer->MinHeight, pSecondBuffer->MinHeight); pFirstBuffer->MinWidth = GFX_MAX(pFirstBuffer->MinWidth, pSecondBuffer->MinWidth); pFirstBuffer->MaxDepth = GFX_MIN(pFirstBuffer->MaxDepth, pSecondBuffer->MaxDepth); pFirstBuffer->MaxHeight = GFX_MIN(pFirstBuffer->MaxHeight, pSecondBuffer->MaxHeight); pFirstBuffer->MaxWidth = GFX_MIN(pFirstBuffer->MaxWidth, pSecondBuffer->MaxWidth); pFirstBuffer->NeedPow2LockAlignment = pFirstBuffer->NeedPow2LockAlignment | pSecondBuffer->NeedPow2LockAlignment; GMM_DPF_EXIT; return pFirstBuffer; } ///////////////////////////////////////////////////////////////////////////////////// /// Returns restrictions for 1D, 2D, 3D textures depending on how the surface /// may possibliy be used. /// /// @param[out] pBuff: Restrictions filled in this struct ///////////////////////////////////////////////////////////////////////////////////// void GmmLib::GmmTextureCalc::GetGenericRestrictions(GMM_TEXTURE_INFO *pTexInfo, __GMM_BUFFER_TYPE *pBuff) { GMM_DPF_ENTER; const GMM_PLATFORM_INFO *pPlatformResource = GMM_OVERRIDE_PLATFORM_INFO(pTexInfo, pGmmLibContext); if(pTexInfo->Flags.Gpu.NoRestriction) { // Impose zero restrictions. Ignore any other GPU usage flags pBuff = GetBestRestrictions(pBuff, &pPlatformResource->NoRestriction); return; } if(pTexInfo->Flags.Gpu.Texture) { if(pTexInfo->Type == RESOURCE_BUFFER) { *pBuff = pPlatformResource->BufferType; } else if(pTexInfo->Type == RESOURCE_CUBE) { *pBuff = pPlatformResource->CubeSurface; } else if(pTexInfo->Type == RESOURCE_3D) { *pBuff = pPlatformResource->Texture3DSurface; } else { *pBuff = pPlatformResource->Texture2DSurface; if(pTexInfo->Flags.Info.Linear) { *pBuff = pPlatformResource->Texture2DLinearSurface; } if(GmmIsReconstructableSurface(pTexInfo->Format)) { pBuff->MaxHeight = pPlatformResource->ReconMaxHeight; pBuff->MaxWidth = pPlatformResource->ReconMaxWidth; } } } if(pTexInfo->Flags.Gpu.RenderTarget || pTexInfo->Flags.Gpu.CCS || pTexInfo->Flags.Gpu.MCS) { // Gen7 onwards, bound by SURFACE_STATE constraints. if(pTexInfo->Type == RESOURCE_BUFFER) { *pBuff = pPlatformResource->BufferType; } else if(pTexInfo->Type == RESOURCE_CUBE) { *pBuff = pPlatformResource->CubeSurface; } else if(pTexInfo->Type == RESOURCE_3D) { *pBuff = pPlatformResource->Texture3DSurface; } else { *pBuff = pPlatformResource->Texture2DSurface; if(pTexInfo->Flags.Info.Linear) { *pBuff = pPlatformResource->Texture2DLinearSurface; } if(GmmIsReconstructableSurface(pTexInfo->Format)) { pBuff->MaxHeight = pPlatformResource->ReconMaxHeight; pBuff->MaxWidth = pPlatformResource->ReconMaxWidth; } } } if(pTexInfo->Flags.Gpu.Depth) { // Z pBuff = GetBestRestrictions(pBuff, &pPlatformResource->Depth); } if(pTexInfo->Flags.Gpu.Vertex) { // VertexData pBuff = GetBestRestrictions(pBuff, &pPlatformResource->Vertex); } if(pTexInfo->Flags.Gpu.Index) { // Index buffer pBuff = GetBestRestrictions(pBuff, &pPlatformResource->Index); } if(pTexInfo->Flags.Gpu.FlipChain) { // Async Flip pBuff = GetBestRestrictions(pBuff, &pPlatformResource->ASyncFlipSurface); } if(pTexInfo->Flags.Gpu.MotionComp) { // Media buffer pBuff = GetBestRestrictions(pBuff, &pPlatformResource->MotionComp); } if(pTexInfo->Flags.Gpu.State || pTexInfo->Flags.Gpu.InstructionFlat || pTexInfo->Flags.Gpu.ScratchFlat) { // indirect state pBuff = GetBestRestrictions(pBuff, &pPlatformResource->Vertex); } if(pTexInfo->Flags.Gpu.Query || pTexInfo->Flags.Gpu.HistoryBuffer) { // Query pBuff = GetBestRestrictions(pBuff, &pPlatformResource->NoRestriction); } if(pTexInfo->Flags.Gpu.Constant) { // pBuff = GetBestRestrictions(pBuff, &pPlatformResource->Constant); } if(pTexInfo->Flags.Gpu.Stream) { // pBuff = GetBestRestrictions(pBuff, &pPlatformResource->Stream); } if(pTexInfo->Flags.Gpu.InterlacedScan) { // pBuff = GetBestRestrictions(pBuff, &pPlatformResource->InterlacedScan); } if(pTexInfo->Flags.Gpu.TextApi) { // pBuff = GetBestRestrictions(pBuff, &pPlatformResource->TextApi); } if(pTexInfo->Flags.Gpu.SeparateStencil) { // pBuff = GetBestRestrictions(pBuff, &pPlatformResource->Stencil); } if(pTexInfo->Flags.Gpu.HiZ) { // pBuff = GetBestRestrictions(pBuff, &pPlatformResource->HiZ); } if(pTexInfo->Flags.Gpu.Video) { // pBuff = GetBestRestrictions(pBuff, &pPlatformResource->Video); if(GmmIsReconstructableSurface(pTexInfo->Format)) { pBuff->MaxHeight = pPlatformResource->ReconMaxHeight; pBuff->MaxWidth = pPlatformResource->ReconMaxWidth; } } if(pTexInfo->Flags.Gpu.StateDx9ConstantBuffer) { // pBuff = GetBestRestrictions(pBuff, &pPlatformResource->StateDx9ConstantBuffer); } if(pTexInfo->Flags.Gpu.Overlay) { // Overlay buffer use Async Flip values pBuff = GetBestRestrictions(pBuff, &pPlatformResource->Overlay); if((pTexInfo->Format == GMM_FORMAT_YUY2) && (pTexInfo->BaseWidth == 640)) { // override the pitch alignment pBuff->PitchAlignment = 64; } } if(pTexInfo->Flags.Info.XAdapter) { //Add Cross Adapter resource restriction for hybrid graphics. pBuff = GetBestRestrictions(pBuff, &pPlatformResource->XAdapter); if(pTexInfo->Type == RESOURCE_BUFFER) { pBuff->MaxWidth = pPlatformResource->SurfaceMaxSize; pBuff->MaxPitch = pPlatformResource->BufferType.MaxPitch; pBuff->MaxHeight = 1; } } //Non Aligned ExistingSysMem Special cases. if((pTexInfo->Flags.Info.ExistingSysMem && (!pTexInfo->ExistingSysMem.IsGmmAllocated) && (!pTexInfo->ExistingSysMem.IsPageAligned))) { if(pTexInfo->Flags.Info.Linear || pTexInfo->Flags.Info.SVM) { if(pTexInfo->Type == RESOURCE_BUFFER) { //Use combination of BufferType, NoRestriction to support large buffer with minimal pitch alignment *pBuff = pPlatformResource->BufferType; pBuff->PitchAlignment = pPlatformResource->NoRestriction.PitchAlignment; pBuff->LockPitchAlignment = pPlatformResource->NoRestriction.LockPitchAlignment; pBuff->RenderPitchAlignment = pPlatformResource->NoRestriction.LockPitchAlignment; pBuff->MinPitch = pPlatformResource->NoRestriction.MinPitch; } //[To DO] Handle other types when needed! } /* else if(Surf.Flags.Gpu.Texture) { //Override as and when required } else if(Surf.Flags.Gpu.RenderTarget) { //Overide as and when Required }*/ } GMM_DPF_EXIT; } ///////////////////////////////////////////////////////////////////////////////////// /// Internal function resets the restrictions and puts the allocation in invalid state /// /// @param[in] pTexInfo: ptr to ::GMM_TEXTURE_INFO, /// @param[in] pRestrictions: reset the restrictions to invalid state. /// ///////////////////////////////////////////////////////////////////////////////////// void GmmLib::GmmTextureCalc::ResetRestrictions(__GMM_BUFFER_TYPE *pRestriction) { pRestriction->MinDepth = 0xffffffff; } ///////////////////////////////////////////////////////////////////////////////////// /// Internal function returns the best restrictions depending on how the surface may /// possibly be used. /// /// @param[in] pTexInfo: ptr to ::GMM_TEXTURE_INFO, /// @param[in] pRestrictions: Reference to surface alignment and size restrictions /// ///////////////////////////////////////////////////////////////////////////////////// void GmmLib::GmmTextureCalc::GetTexRestrictions(GMM_TEXTURE_INFO * pTexInfo, __GMM_BUFFER_TYPE *pRestrictions) { GMM_DPF_ENTER; GetResRestrictions(pTexInfo, *pRestrictions); GMM_DPF_EXIT; } ///////////////////////////////////////////////////////////////////////////////////// /// Returns the restrictions that a particular resource must follow on a particular /// OS or hardware. /// /// @param[out] Restrictions: restrictions that this resource must adhere to ///////////////////////////////////////////////////////////////////////////////////// void GmmLib::GmmTextureCalc::GetResRestrictions(GMM_TEXTURE_INFO * pTexinfo, __GMM_BUFFER_TYPE &Restrictions) { GMM_DPF_ENTER; const GMM_PLATFORM_INFO *pPlatform = NULL; GMM_RESOURCE_FLAG ZeroGpuFlags; __GMM_ASSERTPTR(pGmmLibContext, VOIDRETURN); pPlatform = GMM_OVERRIDE_PLATFORM_INFO(pTexinfo, pGmmLibContext); // Check that at least one usage flag is set for allocations other than // Primary/Shadow/Staging. memset(&ZeroGpuFlags.Gpu, 0, sizeof(ZeroGpuFlags.Gpu)); if((pTexinfo->Type <= RESOURCE_KMD_CHECK_START || pTexinfo->Type >= RESOURCE_KMD_CHECK_END) && !memcmp(&pTexinfo->Flags.Gpu, &ZeroGpuFlags.Gpu, sizeof(ZeroGpuFlags.Gpu))) { GMM_ASSERTDPF(0, "No GPU Usage specified!"); return; } ResetRestrictions(&Restrictions); //Set to Default // Get worst case restrictions that match GPU flags set in resource switch(pTexinfo->Type) { case RESOURCE_1D: case RESOURCE_2D: case RESOURCE_3D: case RESOURCE_CUBE: case RESOURCE_BUFFER: case RESOURCE_SCRATCH: case RESOURCE_GDI: GetGenericRestrictions(pTexinfo, &Restrictions); break; case RESOURCE_HW_CONTEXT: case RESOURCE_TAG_PAGE: if(pTexinfo->Flags.Info.TiledW || pTexinfo->Flags.Info.TiledX || GMM_IS_4KB_TILE(pTexinfo->Flags)) { GMM_ASSERTDPF(0, "Tiled Pref specified for RESOURCE_LINEAR!"); return; } GetLinearRestrictions(pTexinfo, &Restrictions); break; case RESOURCE_PRIMARY: case RESOURCE_SHADOW: case RESOURCE_STAGING: GetPrimaryRestrictions(pTexinfo, &Restrictions); break; case RESOURCE_NNDI: Restrictions = pPlatform->Nndi; break; case RESOURCE_HARDWARE_MBM: case RESOURCE_IFFS_MAPTOGTT: //Hardware MBM resource request can come for overlay allocation or normal //displayable allocation. So get the restrictions accordingly if(pTexinfo->Flags.Gpu.Overlay) { Restrictions = pPlatform->Overlay; } else { Restrictions = pPlatform->HardwareMBM; } break; case RESOURCE_CURSOR: case RESOURCE_PWR_CONTEXT: case RESOURCE_KMD_BUFFER: case RESOURCE_NULL_CONTEXT_INDIRECT_STATE: case RESOURCE_PERF_DATA_QUEUE: case RESOURCE_GLOBAL_BUFFER: case RESOURCE_FBC: case RESOURCE_GFX_CLIENT_BUFFER: Restrictions = pPlatform->Cursor; break; case RESOURCE_OVERLAY_DMA: Restrictions = pPlatform->NoRestriction; break; case RESOURCE_GTT_TRANSFER_REGION: GetGenericRestrictions(pTexinfo, &Restrictions); break; case RESOURCE_OVERLAY_INTERMEDIATE_SURFACE: Restrictions = pPlatform->Overlay; break; default: GetGenericRestrictions(pTexinfo, &Restrictions); GMM_ASSERTDPF(0, "Unkown Resource type"); } // Apply any specific WA if(((pTexinfo->Flags.Wa.ILKNeedAvcMprRowStore32KAlign)) || ((pTexinfo->Flags.Wa.ILKNeedAvcDmvBuffer32KAlign))) { Restrictions.Alignment = GFX_ALIGN(Restrictions.Alignment, GMM_KBYTE(32)); } if(pGmmLibContext->GetWaTable().WaAlignContextImage && (pTexinfo->Type == RESOURCE_HW_CONTEXT)) { Restrictions.Alignment = GFX_ALIGN(Restrictions.Alignment, GMM_KBYTE(64)); } if(pTexinfo->Flags.Gpu.S3d && pTexinfo->Flags.Info.Linear && !pGmmLibContext->GetSkuTable().FtrDisplayEngineS3d) { Restrictions.Alignment = PAGE_SIZE; Restrictions.PitchAlignment = PAGE_SIZE; } if(pTexinfo->Flags.Gpu.TiledResource) { // Need at least 64KB alignment to track tile mappings (h/w or s/w tracking). Restrictions.Alignment = GFX_ALIGN(Restrictions.Alignment, GMM_KBYTE(64)); // Buffer tiled resources are trivially divided into 64KB tiles => Pitch must divide into 64KB tiles if(pTexinfo->Type == RESOURCE_BUFFER) { Restrictions.PitchAlignment = GFX_ALIGN(Restrictions.PitchAlignment, GMM_KBYTE(64)); } } // SKL TileY Display needs 1MB alignment. if(((pTexinfo->Type == RESOURCE_PRIMARY) || pTexinfo->Flags.Gpu.FlipChain) && (GMM_IS_4KB_TILE(pTexinfo->Flags) || pTexinfo->Flags.Info.TiledYf)) { Restrictions.Alignment = GMM_MBYTE(1); } if(pTexinfo->Flags.Info.RenderCompressed || pTexinfo->Flags.Info.MediaCompressed || (pGmmLibContext->GetSkuTable().FtrXe2Compression && !pTexinfo->Flags.Info.NotCompressed)) { if(pGmmLibContext->GetSkuTable().FtrFlatPhysCCS) { Restrictions.Alignment = pGmmLibContext->GetSkuTable().FtrXe2Compression ? GFX_ALIGN(Restrictions.Alignment, GMM_BYTES(256)) : GFX_ALIGN(Restrictions.Alignment, GMM_BYTES(128)); } else // only for platforms having auxtable { Restrictions.Alignment = GFX_ALIGN(Restrictions.Alignment, (WA16K(pGmmLibContext) ? GMM_KBYTE(16) : WA64K(pGmmLibContext) ? GMM_KBYTE(64) : GMM_MBYTE(1))); } } GMM_DPF_EXIT; } ///////////////////////////////////////////////////////////////////////////////////// /// Calculates surface size based on Non Aligned ExistingSysMem restrictions. /// /// @return ::GMM_STATUS ///////////////////////////////////////////////////////////////////////////////////// GMM_STATUS GmmLib::GmmResourceInfoCommon::ApplyExistingSysMemRestrictions() { const GMM_PLATFORM_INFO *pPlatform; // Handle Minimal Restriction ExistingSysMem Requirements... GMM_GFX_SIZE_T AdditionalPaddingBytes = 0; GMM_GFX_SIZE_T AdditionalPaddingRows = 0; GMM_GFX_SIZE_T BaseAlignment = 1; // 1 = Byte Alignment GMM_GFX_SIZE_T EndAlignment = 1; // 1 = Byte Alignment GMM_GFX_SIZE_T SizePadding = 1; // 1 = Byte Padding uint32_t CompressHeight, CompressWidth, CompressDepth; GMM_GFX_SIZE_T Width, Height; GMM_TEXTURE_INFO *pTexInfo = &Surf; GMM_TEXTURE_CALC *pTextureCalc; GMM_DPF_ENTER; pPlatform = GMM_OVERRIDE_PLATFORM_INFO(pTexInfo, GetGmmLibContext()); pTextureCalc = GMM_OVERRIDE_TEXTURE_CALC(pTexInfo, GetGmmLibContext()); Height = pTexInfo->BaseHeight; Width = pTexInfo->BaseWidth; #define UPDATE_BASE_ALIGNMENT(a) \ { \ __GMM_ASSERT((GFX_MAX(BaseAlignment, a) % GFX_MIN(BaseAlignment, a)) == 0); /* Revisit if ever have to support complex alignments. */ \ BaseAlignment = GFX_MAX(BaseAlignment, a); \ } #define UPDATE_PADDING(p) \ { \ SizePadding = GFX_MAX(SizePadding, p); \ } #define UPDATE_ADDITIONAL_ROWS(r) \ { \ AdditionalPaddingRows = GFX_MAX(AdditionalPaddingRows, r); \ } #define UPDATE_ADDITIONAL_BYTES(b) \ { \ AdditionalPaddingBytes = GFX_MAX(AdditionalPaddingBytes, b); \ } #define UPDATE_END_ALIGNMENT(a) \ { \ __GMM_ASSERT((GFX_MAX(EndAlignment, a) % GFX_MIN(EndAlignment, a)) == 0); /* Revisit if ever have to support complex alignments. */ \ EndAlignment = GFX_MAX(EndAlignment, a); \ } if(!pTexInfo->Pitch) { __GMM_ASSERT(pTexInfo->Type == RESOURCE_1D); // Clients can leave pitch zero for 1D, and we'll fill-in... pTexInfo->Pitch = Width * (pTexInfo->BitsPerPixel >> 3); } __GMM_ASSERT( // Currently limiting our support... pTexInfo->Flags.Gpu.NoRestriction || pTexInfo->Flags.Gpu.Index || pTexInfo->Flags.Gpu.RenderTarget || pTexInfo->Flags.Gpu.Texture || pTexInfo->Flags.Gpu.Vertex); __GMM_ASSERT( // Trivial, Linear Surface... ((pTexInfo->Type == RESOURCE_BUFFER) || (pTexInfo->Type == RESOURCE_1D) || (pTexInfo->Type == RESOURCE_2D)) && (pTexInfo->MaxLod == 0) && !GMM_IS_TILED(pPlatform->TileInfo[pTexInfo->TileMode]) && !GmmIsPlanar(pTexInfo->Format) && ((pTexInfo->ArraySize <= 1) || (pTexInfo->Type == RESOURCE_BUFFER))); __GMM_ASSERT( // Valid Surface... (Width > 0) && !((pTexInfo->Type == RESOURCE_BUFFER) && GmmIsYUVPacked(pTexInfo->Format))); // Convert to compression blocks, if applicable... if(GmmIsCompressed(GetGmmLibContext(), pTexInfo->Format)) { pTextureCalc->GetCompressionBlockDimensions(pTexInfo->Format, &CompressWidth, &CompressHeight, &CompressDepth); Width = GFX_CEIL_DIV(Width, CompressWidth); Height = GFX_CEIL_DIV(Height, CompressHeight); } __GMM_ASSERT( // Valid Surface Follow-Up... (pTexInfo->Pitch >= (Width * (pTexInfo->BitsPerPixel >> 3)))); if(!pTexInfo->Flags.Gpu.NoRestriction && !pTexInfo->Flags.Info.SVM && !pTexInfo->Flags.Info.Linear) { if(pTexInfo->Flags.Gpu.Index) ///////////////////////////////////////////////////////// { __GMM_ASSERT(!( pTexInfo->Flags.Gpu.RenderTarget || pTexInfo->Flags.Gpu.Texture || pTexInfo->Flags.Gpu.Vertex)); // Can explore if needed what combo's make sense--and how req's should combine. // 3DSTATE_INDEX_BUFFER... UPDATE_BASE_ALIGNMENT(4); // 32-bit worst-case, since GMM doesn't receive element-size from clients. if(GetGmmLibContext()->GetWaTable().WaAlignIndexBuffer) { UPDATE_END_ALIGNMENT(64); } else { UPDATE_END_ALIGNMENT(1); } } if(pTexInfo->Flags.Gpu.Vertex) //////////////////////////////////////////////////////// { __GMM_ASSERT(!( pTexInfo->Flags.Gpu.Index || pTexInfo->Flags.Gpu.RenderTarget || pTexInfo->Flags.Gpu.Texture)); // Can explore if needed what combo's make sense--and how req's should combine. // VERTEX_BUFFER_STATE... UPDATE_BASE_ALIGNMENT(1); // VB's have member alignment requirements--but it's up to UMD to enforce. UPDATE_PADDING(1); } if(pTexInfo->Flags.Gpu.RenderTarget) ////////////////////////////////////////////////// { uint32_t ElementSize; // SURFACE_STATE... ElementSize = (pTexInfo->BitsPerPixel >> 3) * (GmmIsYUVPacked(pTexInfo->Format) ? 2 : 1); __GMM_ASSERT((pTexInfo->Pitch % ElementSize) == 0); UPDATE_BASE_ALIGNMENT(ElementSize); UPDATE_PADDING(pTexInfo->Pitch * 2); // "Surface Padding Requirements --> Render Target and Media Surfaces" } if(pTexInfo->Flags.Gpu.Texture) // (i.e. Sampler Surfaces) /////////////////////////// { UPDATE_BASE_ALIGNMENT(1); // Sampler supports byte alignment (with performance hit if misaligned). if(GetGmmLibContext()->GetWaTable().WaNoMinimizedTrivialSurfacePadding) { if(pTexInfo->Type == RESOURCE_BUFFER) { if(GetGmmLibContext()->GetWaTable().WaNoBufferSamplerPadding) { // Client agreeing to take responsibility for flushing L3 after sampling/etc. } else { // GMM currently receives GENERIC_8BIT for // RESOURCE_BUFFER creations, so we have to assume the // worst-case sample size of 128-bit (unless we alter // our interface meaning): uint32_t ElementSize = 16; // "Surface Padding Requirements --> Sampling Engine Surfaces" UPDATE_PADDING(ElementSize * ((GFX_GET_CURRENT_RENDERCORE(pPlatform->Platform) == IGFX_GEN8_CORE) ? 512 : 256)); UPDATE_ADDITIONAL_BYTES(16); } } else // RESOURCE_1D/2D... { /* Sampler needs Alignment Unit padding-- but sampler arch confirms that's overly conservative padding--and for trivial (linear, single-subresource) 2D's, even-row (quad-row on BDW.A0) plus additional 64B padding is sufficient. (E.g. pitch overfetch will be caught by subsequent rows or the additional 64B. */ __GMM_ASSERT((GFX_GET_CURRENT_RENDERCORE(pPlatform->Platform) <= IGFX_GEN8_CORE)); if(GmmIsCompressed(GetGmmLibContext(), pTexInfo->Format)) { // "For compressed textures...padding at the bottom of the surface is to an even compressed row." UPDATE_PADDING(pTexInfo->Pitch * 2); // (Sampler arch confirmed that even-row is sufficient on BDW despite BDW's 4x4 sampling, since this req is from L2 instead of L1.) } else { UPDATE_PADDING(pTexInfo->Pitch * ((GFX_GET_CURRENT_RENDERCORE(pPlatform->Platform) == IGFX_GEN8_CORE) ? 4 : 2)); // Sampler Fetch Rows: BDW ? 4 : 2 } // "For packed YUV, 96 bpt, 48 bpt, and 24 bpt surface formats, additional padding is required." if(GmmIsYUVPacked(pTexInfo->Format) || (pTexInfo->BitsPerPixel == 96) || (pTexInfo->BitsPerPixel == 48) || (pTexInfo->BitsPerPixel == 24)) { UPDATE_ADDITIONAL_BYTES(16); UPDATE_ADDITIONAL_ROWS(1); } /* "For linear surfaces, additional padding of 64 bytes is required at the bottom of the surface." (Sampler arch confirmed the 64 bytes can overlap with the other "additional 16 bytes" mentions in that section.) */ UPDATE_ADDITIONAL_BYTES(64); } } else { /* For SURFTYPE_BUFFER, SURFTYPE_1D, and SURFTYPE_2D non-array, non-MSAA, non-mip-mapped surfaces in linear memory, the only padding requirement is to the next aligned 64-byte boundary beyond the end of the surface. */ UPDATE_END_ALIGNMENT(64); } } } else // Gpu.NoRestriction... { // Clients specify NoRestriction at their own risk--e.g. it can be // appropriate when using IA-Coherent L3 combined with L3 being in // unified/"Rest" mode (where there won't be write-->read-only // collisions on unintentionally shared cachelines). } { //Finally calculate surf size GMM_GFX_SIZE_T OriginalEnd, RequiredSize; ExistingSysMem.pVirtAddress = (ExistingSysMem.pExistingSysMem & (PAGE_SIZE - 1)) ? ((uint64_t)GFX_ALIGN(ExistingSysMem.pExistingSysMem, BaseAlignment)) : ExistingSysMem.pExistingSysMem; ExistingSysMem.pGfxAlignedVirtAddress = (uint64_t)GFX_ALIGN( (uint64_t)ExistingSysMem.pVirtAddress, PAGE_SIZE); __GMM_ASSERT((ExistingSysMem.pVirtAddress % BaseAlignment) == 0); RequiredSize = pTexInfo->Pitch * Height; RequiredSize = GFX_ALIGN(RequiredSize, SizePadding) + (AdditionalPaddingRows * pTexInfo->Pitch) + AdditionalPaddingBytes; OriginalEnd = ExistingSysMem.pVirtAddress + RequiredSize; RequiredSize += GFX_ALIGN(OriginalEnd, EndAlignment) - OriginalEnd; //Ensure sufficient ExistingSysMem available. if(ExistingSysMem.Size < RequiredSize) { return GMM_ERROR; } Surf.Size = RequiredSize; } GMM_DPF_EXIT; return GMM_SUCCESS; } gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/Resource/Linux/000077500000000000000000000000001466655022700227415ustar00rootroot00000000000000gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/Resource/Linux/GmmResourceInfoLinCWrapper.cpp000066400000000000000000000152771466655022700306340ustar00rootroot00000000000000/*============================================================================== Copyright(c) 2019 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ============================================================================*/ #include "Internal/Common/GmmLibInc.h" #if defined(__linux__) && !LHDM #include "Internal/Linux/GmmResourceInfoLinInt.h" ///////////////////////////////////////////////////////////////////////////////////// /// This is an overloaded function to call DeviceCb Function for CreateAllocation /// /// @param[in] ClientType /// @param[in] pDeviceCb: Pointer to GMM_DEVICE_CALLBACKS_INT Struct /// @param[in] pAllocate: Pointer to GMM_DDI_ALLOCATE Union /// @return Status of CreateAllocation call. ///////////////////////////////////////////////////////////////////////////////////// int GmmDeviceCallback(GMM_CLIENT ClientType, GMM_DEVICE_CALLBACKS_INT *pDeviceCb, GMM_DDI_ALLOCATE *pAllocate) { int Status = 0; void * pBo = NULL; void * pCpuAddr = NULL; uint64_t gpuAddr = 0ULL; Status = pDeviceCb->DevCbPtrs_.pfnAllocate(pDeviceCb->pBufMgr, pAllocate->size, pAllocate->alignment, &pBo, &pCpuAddr, &gpuAddr); pAllocate->bo = pBo; pAllocate->cpuAddr = pCpuAddr; pAllocate->gfxAddr = gpuAddr; return Status; } ///////////////////////////////////////////////////////////////////////////////////// /// This is an overloaded function to call DeviceCb Function for DestroyAllocation /// /// @param[in] ClientType /// @param[in] pDeviceCb: Pointer to GMM_DEVICE_CALLBACKS_INT Struct /// @param[in] pAllocate: Pointer to GMM_DDI_DEALLOCATE Union /// @return Status of DestroyAllocation call. ///////////////////////////////////////////////////////////////////////////////////// int GmmDeviceCallback(GMM_CLIENT ClientType, GMM_DEVICE_CALLBACKS_INT *pDeviceCb, GMM_DDI_DEALLOCATE *pDeallocate) { int Status = 0; pDeviceCb->DevCbPtrs_.pfnDeallocate(pDeallocate->bo); return Status; } ///////////////////////////////////////////////////////////////////////////////////// /// This is an overloaded function to call DeviceCb Function for WaitForSyncObjFromCpu /// /// @param[in] ClientType /// @param[in] pDeviceCb: Pointer to GMM_DEVICE_CALLBACKS_INT Struct /// @param[in] pAllocate: Pointer to GMM_DDI_WAITFORSYNCHRONIZATIONOBJECTFROMCPU Union /// @return Status of WaitForSyncObjFromCpu call. ///////////////////////////////////////////////////////////////////////////////////// int GmmDeviceCallback(GMM_CLIENT ClientType, GMM_DEVICE_CALLBACKS_INT *pDeviceCb, GMM_DDI_WAITFORSYNCHRONIZATIONOBJECTFROMCPU *pWait) { int Status = 0; pDeviceCb->DevCbPtrs_.pfnWaitFromCpu(pWait->bo); return Status; } ///////////////////////////////////////////////////////////////////////////////////// /// This function checks for Null DeviceCb Function pointer /// /// @param[in] ClientType /// @param[in] pDeviceCb: Pointer to GMM_DEVICE_CALLBACKS_INT Struct /// @param[in] CallBackType Enum @GMM_DEVICE_CALLBACKS_TYPE /// @return True if not Null. ///////////////////////////////////////////////////////////////////////////////////// int GmmCheckForNullDevCbPfn(GMM_CLIENT ClientType, GMM_DEVICE_CALLBACKS_INT *pDeviceCb, GMM_DEVICE_CALLBACKS_TYPE CallBackType) { int Status = 0; switch(CallBackType) { case GMM_DEV_CB_ALLOC: Status = (pDeviceCb->DevCbPtrs_.pfnAllocate != 0); break; case GMM_DEV_CB_DEALLOC: Status = (pDeviceCb->DevCbPtrs_.pfnDeallocate != 0); break; case GMM_DEV_CB_WAIT_FROM_CPU: Status = (pDeviceCb->DevCbPtrs_.pfnWaitFromCpu != 0); break; default: Status = 0; break; } return Status; } // Dummy Translation Table Callback for reusing .. static inline int DummyPrologTranslationTable(void *pDeviceHandle) { return 0; } static inline int DummyWriteL1Entries(void * pDeviceHandle, const uint32_t NumEntries, GMM_GFX_ADDRESS GfxAddress, uint32_t * Data) { return 0; } static inline int DummyWriteL2L3Entry(void * pDeviceHandle, GMM_GFX_ADDRESS GfxAddress, uint64_t Data) { return 0; } static inline int DummyWriteFenceID(void * pDeviceHandle, GMM_GFX_ADDRESS GfxAddress, uint64_t Data) { return 0; } static inline int DummyEpilogTranslationTable(void * pDeviceHandle, uint8_t ForceFlush) { return 0; } static inline int DummyCopyL1Entry(void * pDeviceHandle, GMM_GFX_ADDRESS DstGfxAddress, GMM_GFX_ADDRESS SrcGfxAddress) { return 0; } static inline int DummyWriteL3Adr(void * pDeviceHandle, GMM_GFX_ADDRESS L3GfxAddress, uint64_t RegOffset) { return 0; } GMM_TRANSLATIONTABLE_CALLBACKS DummyTTCB = { .pfPrologTranslationTable = DummyPrologTranslationTable, .pfWriteL1Entries = DummyWriteL1Entries, .pfWriteL2L3Entry = DummyWriteL2L3Entry, .pfWriteFenceID = DummyWriteFenceID, .pfEpilogTranslationTable = DummyEpilogTranslationTable, .pfCopyL1Entry = DummyCopyL1Entry, .pfWriteL3Adr = DummyWriteL3Adr, }; #endif /*__linux__*/ gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/Scripts/000077500000000000000000000000001466655022700215025ustar00rootroot00000000000000gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/Scripts/GmmCheckCodingStandard.bat000066400000000000000000000022651466655022700264620ustar00rootroot00000000000000@echo off REM Copyright(c) 2017 Intel Corporation REM REM Permission is hereby granted, free of charge, to any person obtaining a REM copy of this software and associated documentation files(the "Software"), REM to deal in the Software without restriction, including without limitation REM the rights to use, copy, modify, merge, publish, distribute, sublicense, REM and / or sell copies of the Software, and to permit persons to whom the REM Software is furnished to do so, subject to the following conditions: REM REM The above copyright notice and this permission notice shall be included REM in all copies or substantial portions of the Software. REM REM THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS REM OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, REM FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL REM THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR REM OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, REM ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR REM OTHER DEALINGS IN THE SOFTWARE. cscript //nologo %~dp0\GmmCheckCodingStandard.wsf %~dp0\.. gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/Scripts/GmmCheckCodingStandard.wsf000066400000000000000000000111671466655022700265140ustar00rootroot00000000000000//============================================================================ // Copyright(c) 2017 Intel Corporation // // Permission is hereby granted, free of charge, to any person obtaining a // copy of this software and associated documentation files(the "Software"), // to deal in the Software without restriction, including without limitation // the rights to use, copy, modify, merge, publish, distribute, sublicense, // and / or sell copies of the Software, and to permit persons to whom the // Software is furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included // in all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR // OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, // ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR // OTHER DEALINGS IN THE SOFTWARE. //============================================================================ gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/Texture/000077500000000000000000000000001466655022700215135ustar00rootroot00000000000000gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/Texture/GmmGen10Texture.cpp000066400000000000000000001112121466655022700251110ustar00rootroot00000000000000/*============================================================================== Copyright(c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ============================================================================*/ #include "Internal/Common/GmmLibInc.h" #include "Internal/Common/Texture/GmmGen10TextureCalc.h" ///////////////////////////////////////////////////////////////////////////////////// /// Returns the mip offset of given LOD in Mip Tail /// /// @param[in] pTexInfo: ptr to ::GMM_TEXTURE_INFO, /// MipLevel: given LOD # /// /// @return offset value of LOD in bytes ///////////////////////////////////////////////////////////////////////////////////// uint32_t GmmLib::GmmGen10TextureCalc::GetMipTailByteOffset(GMM_TEXTURE_INFO *pTexInfo, uint32_t MipLevel) { uint32_t ByteOffset = 0, Slot = 0xff; GMM_DPF_ENTER; // 3D textures follow the Gen9 mip tail format if(!pGmmLibContext->GetSkuTable().FtrStandardMipTailFormat || pTexInfo->Type == RESOURCE_3D) { return GmmGen9TextureCalc::GetMipTailByteOffset(pTexInfo, MipLevel); } if(pTexInfo->Type == RESOURCE_1D) { Slot = MipLevel - pTexInfo->Alignment.MipTailStartLod + (pTexInfo->Flags.Info.TiledYf ? 4 : 0); } else if(pTexInfo->Type == RESOURCE_2D || pTexInfo->Type == RESOURCE_CUBE) { // clang-format off Slot = MipLevel - pTexInfo->Alignment.MipTailStartLod + // TileYs ((pTexInfo->Flags.Info.TiledYs && pTexInfo->MSAA.NumSamples == 16) ? 4 : (pTexInfo->Flags.Info.TiledYs && pTexInfo->MSAA.NumSamples == 8) ? 3 : (pTexInfo->Flags.Info.TiledYs && pTexInfo->MSAA.NumSamples == 4) ? 2 : (pTexInfo->Flags.Info.TiledYs && pTexInfo->MSAA.NumSamples == 2) ? 1 : (pTexInfo->Flags.Info.TiledYs ) ? 0 : // TileYf (pTexInfo->Flags.Info.TiledYf && pTexInfo->MSAA.NumSamples == 16) ? 11: (pTexInfo->Flags.Info.TiledYf && pTexInfo->MSAA.NumSamples == 8) ? 10: (pTexInfo->Flags.Info.TiledYf && pTexInfo->MSAA.NumSamples == 4) ? 8: (pTexInfo->Flags.Info.TiledYf && pTexInfo->MSAA.NumSamples == 2) ? 5: (pTexInfo->Flags.Info.TiledYf ) ? 4: 0); // clang-format on } switch(Slot) { case 0: ByteOffset = GMM_KBYTE(32); break; case 1: ByteOffset = GMM_KBYTE(16); break; case 2: ByteOffset = GMM_KBYTE(8); break; case 3: ByteOffset = GMM_KBYTE(4); break; case 4: ByteOffset = GMM_KBYTE(2); break; case 5: ByteOffset = GMM_BYTES(1536); break; case 6: ByteOffset = GMM_BYTES(1280); break; case 7: ByteOffset = GMM_BYTES(1024); break; case 8: ByteOffset = GMM_BYTES(768); break; case 9: ByteOffset = GMM_BYTES(512); break; case 10: ByteOffset = GMM_BYTES(256); break; case 11: ByteOffset = GMM_BYTES(192); break; case 12: ByteOffset = GMM_BYTES(128); break; case 13: ByteOffset = GMM_BYTES(64); break; case 14: ByteOffset = GMM_BYTES(0); break; default: __GMM_ASSERT(0); } GMM_DPF_EXIT; return (ByteOffset); } GMM_MIPTAIL_SLOT_OFFSET Gen10MipTailSlotOffset1DSurface[15][5] = GEN10_MIPTAIL_SLOT_OFFSET_1D_SURFACE; GMM_MIPTAIL_SLOT_OFFSET Gen10MipTailSlotOffset2DSurface[15][5] = GEN10_MIPTAIL_SLOT_OFFSET_2D_SURFACE; GMM_MIPTAIL_SLOT_OFFSET Gen10MipTailSlotOffset3DSurface[15][5] = GEN10_MIPTAIL_SLOT_OFFSET_3D_SURFACE; ///////////////////////////////////////////////////////////////////////////////////// /// Returns the mip-map offset in geometric OffsetX, Y, Z for a given LOD in Mip Tail. /// /// @param[in] pTexInfo: ptr to ::GMM_TEXTURE_INFO, /// MipLevel: mip-map level /// OffsetX: ptr to Offset in X direction (in bytes) /// OffsetY: ptr to Offset in Y direction (in pixels) /// OffsetZ: ptr to Offset in Z direction (in pixels) /// ///////////////////////////////////////////////////////////////////////////////////// void GmmLib::GmmGen10TextureCalc::GetMipTailGeometryOffset(GMM_TEXTURE_INFO *pTexInfo, uint32_t MipLevel, uint32_t * OffsetX, uint32_t * OffsetY, uint32_t * OffsetZ) { uint32_t ArrayIndex = 0; uint32_t Slot = 0; GMM_DPF_ENTER; // 3D textures follow the Gen9 mip tail format if(!pGmmLibContext->GetSkuTable().FtrStandardMipTailFormat || pTexInfo->Type == RESOURCE_3D) { return GmmGen9TextureCalc::GetMipTailGeometryOffset(pTexInfo, MipLevel, OffsetX, OffsetY, OffsetZ); } switch(pTexInfo->BitsPerPixel) { case 128: ArrayIndex = 0; break; case 64: ArrayIndex = 1; break; case 32: ArrayIndex = 2; break; case 16: ArrayIndex = 3; break; case 8: ArrayIndex = 4; break; default: __GMM_ASSERT(0); break; } if(pTexInfo->Type == RESOURCE_1D) { Slot = MipLevel - pTexInfo->Alignment.MipTailStartLod + (pTexInfo->Flags.Info.TiledYf ? 4 : 0); *OffsetX = Gen10MipTailSlotOffset1DSurface[Slot][ArrayIndex].X * pTexInfo->BitsPerPixel / 8; *OffsetY = Gen10MipTailSlotOffset1DSurface[Slot][ArrayIndex].Y; *OffsetZ = Gen10MipTailSlotOffset1DSurface[Slot][ArrayIndex].Z; } else if(pTexInfo->Type == RESOURCE_2D || pTexInfo->Type == RESOURCE_CUBE) { // clang-format off Slot = MipLevel - pTexInfo->Alignment.MipTailStartLod + // TileYs ((pTexInfo->Flags.Info.TiledYs && pTexInfo->MSAA.NumSamples == 16) ? 4 : (pTexInfo->Flags.Info.TiledYs && pTexInfo->MSAA.NumSamples == 8) ? 3 : (pTexInfo->Flags.Info.TiledYs && pTexInfo->MSAA.NumSamples == 4) ? 2 : (pTexInfo->Flags.Info.TiledYs && pTexInfo->MSAA.NumSamples == 2) ? 1 : (pTexInfo->Flags.Info.TiledYs) ? 0 : // TileYf (pTexInfo->Flags.Info.TiledYf && pTexInfo->MSAA.NumSamples == 16) ? 11 : (pTexInfo->Flags.Info.TiledYf && pTexInfo->MSAA.NumSamples == 8) ? 10 : (pTexInfo->Flags.Info.TiledYf && pTexInfo->MSAA.NumSamples == 4) ? 8 : (pTexInfo->Flags.Info.TiledYf && pTexInfo->MSAA.NumSamples == 2) ? 5 : (pTexInfo->Flags.Info.TiledYf) ? 4 : 0); // clang-format on *OffsetX = Gen10MipTailSlotOffset2DSurface[Slot][ArrayIndex].X * pTexInfo->BitsPerPixel / 8; *OffsetY = Gen10MipTailSlotOffset2DSurface[Slot][ArrayIndex].Y; *OffsetZ = Gen10MipTailSlotOffset2DSurface[Slot][ArrayIndex].Z; } GMM_DPF_EXIT; return; } ///////////////////////////////////////////////////////////////////////////////////// /// Returns the aligned block height of the 3D surface on Gen9 /// /// @param[in] pTexInfo: ptr to ::GMM_TEXTURE_INFO, /// BlockHeight: /// ExpandedArraySize: adjusted array size for MSAA, cube faces, etc. /// /// @return BlockHeight ///////////////////////////////////////////////////////////////////////////////////// uint32_t GmmLib::GmmGen10TextureCalc::GetAligned3DBlockHeight(GMM_TEXTURE_INFO *pTexInfo, uint32_t BlockHeight, uint32_t ExpandedArraySize) { uint32_t DAlign, CompressHeight, CompressWidth, CompressDepth; GMM_DPF_ENTER; __GMM_ASSERTPTR(pTexInfo, 0); const GMM_PLATFORM_INFO *pPlatform = GMM_OVERRIDE_PLATFORM_INFO(pTexInfo, pGmmLibContext); DAlign = pTexInfo->Alignment.DAlign; GetCompressionBlockDimensions(pTexInfo->Format, &CompressWidth, &CompressHeight, &CompressDepth); if(pTexInfo->Type == RESOURCE_3D) { ExpandedArraySize = GFX_ALIGN_NP2(ExpandedArraySize, DAlign) / CompressDepth; if(!pTexInfo->Flags.Info.Linear) { BlockHeight = GFX_ALIGN(BlockHeight, pPlatform->TileInfo[pTexInfo->TileMode].LogicalTileHeight); } } GMM_DPF_EXIT; return BlockHeight; } ///////////////////////////////////////////////////////////////////////////////////// /// Allocates the 2D mip layout for surface state programming. /// /// @param[in] pTexInfo: ptr to ::GMM_TEXTURE_INFO, /// @param[in] pRestrictions: ptr to surface alignment and size restrictions /// /// @return ::GMM_STATUS ///////////////////////////////////////////////////////////////////////////////////// GMM_STATUS GMM_STDCALL GmmLib::GmmGen10TextureCalc::FillTex2D(GMM_TEXTURE_INFO * pTexInfo, __GMM_BUFFER_TYPE *pRestrictions) { uint32_t Width, Height, BitsPerPixel; uint32_t HAlign, VAlign, DAlign, CompressHeight, CompressWidth, CompressDepth; uint32_t AlignedWidth, BlockHeight, ExpandedArraySize, Pitch; uint8_t Compress = 0; GMM_STATUS Status; GMM_DPF_ENTER; __GMM_ASSERTPTR(pTexInfo, GMM_ERROR); __GMM_ASSERTPTR(pRestrictions, GMM_ERROR); const GMM_PLATFORM_INFO *pPlatform = GMM_OVERRIDE_PLATFORM_INFO(pTexInfo, pGmmLibContext); BitsPerPixel = pTexInfo->BitsPerPixel; if(pTexInfo->Flags.Gpu.CCS && pTexInfo->Flags.Gpu.__NonMsaaTileYCcs) { // Aux Surfaces are 8bpp. BitsPerPixel = 8; } Height = pTexInfo->BaseHeight; Width = GFX_ULONG_CAST(pTexInfo->BaseWidth); pTexInfo->MSAA.NumSamples = GFX_MAX(pTexInfo->MSAA.NumSamples, 1); if(pTexInfo->Flags.Info.TiledYf || pTexInfo->Flags.Info.TiledYs) { FindMipTailStartLod(pTexInfo); } ExpandedArraySize = GFX_MAX(pTexInfo->ArraySize, 1) * ((pTexInfo->Type == RESOURCE_CUBE) ? 6 : 1) * // Cubemaps simply 6-element, 2D arrays. ((pTexInfo->Type == RESOURCE_3D) ? pTexInfo->Depth : 1) * // 3D's simply 2D arrays. ((pTexInfo->Flags.Gpu.Depth || pTexInfo->Flags.Gpu.SeparateStencil || (pTexInfo->Flags.Info.TiledYs || pTexInfo->Flags.Info.TiledYf)) ? // MSAA Ys samples are NOT stored as array planes. 1 : pTexInfo->MSAA.NumSamples); // MSAA (non-Depth/Stencil) RT samples stored as array planes. if(pTexInfo->Flags.Info.TiledYs || pTexInfo->Flags.Info.TiledYf) { ExpandedArraySize = GFX_CEIL_DIV(ExpandedArraySize, pPlatform->TileInfo[pTexInfo->TileMode].LogicalTileDepth); } // // Check for color separation // if(pTexInfo->Flags.Gpu.ColorSeparation || pTexInfo->Flags.Gpu.ColorSeparationRGBX) { bool csRestrictionsMet = (((ExpandedArraySize <= 2) && (ExpandedArraySize == pTexInfo->ArraySize) && ((pTexInfo->Format == GMM_FORMAT_R8G8B8A8_UNORM) || (pTexInfo->Format == GMM_FORMAT_R8G8B8A8_UNORM_SRGB) || (pTexInfo->Format == GMM_FORMAT_B8G8R8A8_UNORM) || (pTexInfo->Format == GMM_FORMAT_B8G8R8A8_UNORM_SRGB) || (pTexInfo->Format == GMM_FORMAT_B8G8R8X8_UNORM) || (pTexInfo->Format == GMM_FORMAT_B8G8R8X8_UNORM_SRGB)) && ((pTexInfo->Flags.Gpu.ColorSeparation && (Width % 16) == 0) || (pTexInfo->Flags.Gpu.ColorSeparationRGBX && (Width % 12) == 0)))); if(csRestrictionsMet) { ExpandedArraySize = GMM_COLOR_SEPARATION_ARRAY_SIZE; } else { pTexInfo->Flags.Gpu.ColorSeparation = false; pTexInfo->Flags.Gpu.ColorSeparationRGBX = false; } } HAlign = pTexInfo->Alignment.HAlign; VAlign = pTexInfo->Alignment.VAlign; DAlign = pTexInfo->Alignment.DAlign; GetCompressionBlockDimensions(pTexInfo->Format, &CompressWidth, &CompressHeight, &CompressDepth); Compress = GmmIsCompressed(pGmmLibContext, pTexInfo->Format); ///////////////////////////////// // Calculate Block Surface Height ///////////////////////////////// if(ExpandedArraySize > 1) { uint32_t Alignment = VAlign; if((pTexInfo->Type == RESOURCE_3D && !pTexInfo->Flags.Info.Linear) || (pTexInfo->Flags.Gpu.S3dDx && pGmmLibContext->GetSkuTable().FtrDisplayEngineS3d) || (pTexInfo->Flags.Wa.MediaPipeUsage)) { Alignment = pPlatform->TileInfo[pTexInfo->TileMode].LogicalTileHeight; //Gmm uses TileY for Stencil allocations, having half TileW height (TileY width compensates) if(pTexInfo->Flags.Gpu.SeparateStencil && pTexInfo->Flags.Info.TiledW) { Alignment *= 2; } } // Calculate the overall Block height...Mip0Height + Max(Mip1Height, Sum of Mip2Height..MipnHeight) BlockHeight = Get2DMipMapTotalHeight(pTexInfo); BlockHeight = GFX_ALIGN_NP2(BlockHeight, Alignment); // GMM internally uses QPitch as the logical distance between slices, but translates // as appropriate to service client queries in GmmResGetQPitch. pTexInfo->Alignment.QPitch = BlockHeight; if(Compress) { BlockHeight = GFX_CEIL_DIV(BlockHeight, CompressHeight); BlockHeight = GetAligned3DBlockHeight(pTexInfo, BlockHeight, ExpandedArraySize); } else if(pTexInfo->Flags.Gpu.SeparateStencil && pTexInfo->Flags.Info.TiledW) { BlockHeight /= 2; } else if(pTexInfo->Flags.Gpu.CCS && pTexInfo->Flags.Gpu.__NonMsaaTileYCcs) { BlockHeight /= 16; } BlockHeight *= ExpandedArraySize; } else { pTexInfo->Alignment.QPitch = 0; BlockHeight = Get2DMipMapHeight(pTexInfo); } /////////////////////////////////// // Calculate Pitch /////////////////////////////////// AlignedWidth = __GMM_EXPAND_WIDTH(this, Width, HAlign, pTexInfo); // For Non - planar surfaces, the alignment is done on the entire height of the allocation if(pGmmLibContext->GetWaTable().WaAlignYUVResourceToLCU && GmmIsYUVFormatLCUAligned(pTexInfo->Format)) { AlignedWidth = GFX_ALIGN(AlignedWidth, GMM_SCANLINES(GMM_MAX_LCU_SIZE)); } // Calculate special pitch case of small dimensions where LOD1 + LOD2 widths // are greater than LOD0. e.g. dimensions 4x4 and MinPitch == 1 if((pTexInfo->Flags.Info.TiledYf || pTexInfo->Flags.Info.TiledYs) && (pTexInfo->Alignment.MipTailStartLod < 2)) { // Do nothing -- all mips are in LOD0/LOD1, which is already width aligned. } else if(pTexInfo->MaxLod >= 2) { uint32_t AlignedWidthLod1, AlignedWidthLod2; AlignedWidthLod1 = __GMM_EXPAND_WIDTH(this, Width >> 1, HAlign, pTexInfo); AlignedWidthLod2 = __GMM_EXPAND_WIDTH(this, Width >> 2, HAlign, pTexInfo); AlignedWidth = GFX_MAX(AlignedWidth, AlignedWidthLod1 + AlignedWidthLod2); } if(Compress) { AlignedWidth = GFX_CEIL_DIV(AlignedWidth, CompressWidth); } else if(pTexInfo->Flags.Gpu.SeparateStencil && pTexInfo->Flags.Info.TiledW) { AlignedWidth *= 2; } else if(pTexInfo->Flags.Gpu.CCS && pTexInfo->Flags.Gpu.__NonMsaaTileYCcs) { switch(pTexInfo->BitsPerPixel) { case 32: AlignedWidth /= 8; break; case 64: AlignedWidth /= 4; break; case 128: AlignedWidth /= 2; break; default: __GMM_ASSERT(0); } } else if(pTexInfo->Flags.Gpu.ColorSeparation) { AlignedWidth *= pTexInfo->ArraySize; __GMM_ASSERT(0 == (AlignedWidth % GMM_COLOR_SEPARATION_WIDTH_DIVISION)); AlignedWidth /= GMM_COLOR_SEPARATION_WIDTH_DIVISION; } else if(pTexInfo->Flags.Gpu.ColorSeparationRGBX) { AlignedWidth *= pTexInfo->ArraySize; __GMM_ASSERT(0 == (AlignedWidth % GMM_COLOR_SEPARATION_RGBX_WIDTH_DIVISION)); AlignedWidth /= GMM_COLOR_SEPARATION_RGBX_WIDTH_DIVISION; } // Default pitch Pitch = AlignedWidth * BitsPerPixel >> 3; // Make sure the pitch satisfy linear min pitch requirment Pitch = GFX_MAX(Pitch, pRestrictions->MinPitch); // Make sure pitch satisfy alignment restriction Pitch = GFX_ALIGN(Pitch, pRestrictions->PitchAlignment); //////////////////// // Adjust for Tiling //////////////////// if(GMM_IS_TILED(pPlatform->TileInfo[pTexInfo->TileMode])) { Pitch = GFX_ALIGN(Pitch, pPlatform->TileInfo[pTexInfo->TileMode].LogicalTileWidth); BlockHeight = GFX_ALIGN(BlockHeight, pPlatform->TileInfo[pTexInfo->TileMode].LogicalTileHeight); } GMM_ASSERTDPF(pTexInfo->Flags.Info.LayoutBelow || !pTexInfo->Flags.Info.LayoutRight, "MIPLAYOUT_RIGHT not supported after Gen6!"); pTexInfo->Flags.Info.LayoutBelow = 1; pTexInfo->Flags.Info.LayoutRight = 0; // If a texture is YUV packed, 96, or 48 bpp then one row plus 16 bytes of // padding needs to be added. Since this will create a none pitch aligned // surface the padding is aligned to the next row if(GmmIsYUVPacked(pTexInfo->Format) || (pTexInfo->BitsPerPixel == GMM_BITS(96)) || (pTexInfo->BitsPerPixel == GMM_BITS(48))) { BlockHeight += GMM_SCANLINES(1) + GFX_CEIL_DIV(GMM_BYTES(16), Pitch); } // For Non-planar surfaces, the alignment is done on the entire height of the allocation if(pGmmLibContext->GetWaTable().WaAlignYUVResourceToLCU && GmmIsYUVFormatLCUAligned(pTexInfo->Format) && !GmmIsPlanar(pTexInfo->Format)) { BlockHeight = GFX_ALIGN(BlockHeight, GMM_SCANLINES(GMM_MAX_LCU_SIZE)); } // Align height to even row to cover for HW over-fetch BlockHeight = GFX_ALIGN(BlockHeight, __GMM_EVEN_ROW); if((Status = // <-- Note assignment. FillTexPitchAndSize( pTexInfo, Pitch, BlockHeight, pRestrictions)) == GMM_SUCCESS) { Fill2DTexOffsetAddress(pTexInfo); } GMM_DPF_EXIT; return (Status); } ///////////////////////////////////////////////////////////////////////////////////// /// This function will Setup a planar surface allocation. /// /// @param[in] pTexInfo: Reference to ::GMM_TEXTURE_INFO /// @param[in] pRestrictions: Reference to surface alignment and size restrictions. /// /// @return ::GMM_STATUS ///////////////////////////////////////////////////////////////////////////////////// GMM_STATUS GMM_STDCALL GmmLib::GmmGen10TextureCalc::FillTexPlanar(GMM_TEXTURE_INFO * pTexInfo, __GMM_BUFFER_TYPE *pRestrictions) { uint32_t WidthBytesPhysical, Height, YHeight, VHeight; uint32_t AdjustedVHeight = 0; GMM_STATUS Status; bool UVPacked = false; GMM_DPF_ENTER; __GMM_ASSERTPTR(pTexInfo, GMM_ERROR); __GMM_ASSERTPTR(pRestrictions, GMM_ERROR); __GMM_ASSERT(!pTexInfo->Flags.Info.TiledW); pTexInfo->TileMode = TILE_NONE; const GMM_PLATFORM_INFO *pPlatform = GMM_OVERRIDE_PLATFORM_INFO(pTexInfo, pGmmLibContext); WidthBytesPhysical = GFX_ULONG_CAST(pTexInfo->BaseWidth) * pTexInfo->BitsPerPixel >> 3; Height = VHeight = 0; YHeight = pTexInfo->BaseHeight; switch(pTexInfo->Format) { case GMM_FORMAT_IMC1: // IMC1 = IMC3 with Swapped U/V case GMM_FORMAT_IMC3: case GMM_FORMAT_MFX_JPEG_YUV420: // Same as IMC3. // YYYYYYYY // YYYYYYYY // YYYYYYYY // YYYYYYYY // UUUU // UUUU // VVVV // VVVV case GMM_FORMAT_MFX_JPEG_YUV422V: // Similar to IMC3 but U/V are full width. // YYYYYYYY // YYYYYYYY // YYYYYYYY // YYYYYYYY // UUUUUUUU // UUUUUUUU // VVVVVVVV // VVVVVVVV { VHeight = GFX_ALIGN(GFX_CEIL_DIV(YHeight, 2), GMM_IMCx_PLANE_ROW_ALIGNMENT); YHeight = GFX_ALIGN(YHeight, GMM_IMCx_PLANE_ROW_ALIGNMENT); Height = YHeight + 2 * VHeight; // One VHeight for V and one for U. pTexInfo->OffsetInfo.Plane.NoOfPlanes = 3; break; } case GMM_FORMAT_MFX_JPEG_YUV411R_TYPE: //Similar to IMC3 but U/V are quarther height and full width. //YYYYYYYY //YYYYYYYY //YYYYYYYY //YYYYYYYY //UUUUUUUU //VVVVVVVV { VHeight = GFX_ALIGN(GFX_CEIL_DIV(YHeight, 4), GMM_IMCx_PLANE_ROW_ALIGNMENT); YHeight = GFX_ALIGN(YHeight, GMM_IMCx_PLANE_ROW_ALIGNMENT); Height = YHeight + 2 * VHeight; pTexInfo->OffsetInfo.Plane.NoOfPlanes = 3; break; } case GMM_FORMAT_MFX_JPEG_YUV411: // Similar to IMC3 but U/V are quarter width and full height. // YYYYYYYY // YYYYYYYY // YYYYYYYY // YYYYYYYY // UU // UU // UU // UU // VV // VV // VV // VV case GMM_FORMAT_MFX_JPEG_YUV422H: // Similar to IMC3 but U/V are full height. // YYYYYYYY // YYYYYYYY // YYYYYYYY // YYYYYYYY // UUUU // UUUU // UUUU // UUUU // VVVV // VVVV // VVVV // VVVV case GMM_FORMAT_BGRP: case GMM_FORMAT_RGBP: case GMM_FORMAT_MFX_JPEG_YUV444: // Similar to IMC3 but U/V are full size. // YYYYYYYY // YYYYYYYY // YYYYYYYY // YYYYYYYY // UUUUUUUU // UUUUUUUU // UUUUUUUU // UUUUUUUU // VVVVVVVV // VVVVVVVV // VVVVVVVV // VVVVVVVV { YHeight = GFX_ALIGN(YHeight, GMM_IMCx_PLANE_ROW_ALIGNMENT); VHeight = YHeight; Height = YHeight + 2 * VHeight; pTexInfo->OffsetInfo.Plane.NoOfPlanes = 3; break; } case GMM_FORMAT_IMC2: // IMC2 = IMC4 with Swapped U/V case GMM_FORMAT_IMC4: { // YYYYYYYY // YYYYYYYY // YYYYYYYY // YYYYYYYY // UUUUVVVV // UUUUVVVV YHeight = GFX_ALIGN(YHeight, GMM_IMCx_PLANE_ROW_ALIGNMENT); VHeight = GFX_CEIL_DIV(YHeight, 2); WidthBytesPhysical = GFX_ALIGN(WidthBytesPhysical, 2); // If odd YWidth, pitch bumps-up to fit rounded-up U/V planes. Height = YHeight + VHeight; // With SURFACE_STATE.XOffset support, the U-V interface has // much lighter restrictions--which will be naturally met by // surface pitch restrictions (i.e. dividing an IMC2/4 pitch // by 2--to get the U/V interface--will always produce a safe // XOffset value). // Not technically UV packed but sizing works out the same // if the resource is std swizzled UVPacked = true; pTexInfo->OffsetInfo.Plane.NoOfPlanes = 2; break; } case GMM_FORMAT_NV12: case GMM_FORMAT_NV21: case GMM_FORMAT_NV11: case GMM_FORMAT_P010: case GMM_FORMAT_P012: case GMM_FORMAT_P016: case GMM_FORMAT_P208: case GMM_FORMAT_P216: { // YYYYYYYY // YYYYYYYY // YYYYYYYY // YYYYYYYY // [UV-Packing] if((pTexInfo->Format == GMM_FORMAT_NV12) || (pTexInfo->Format == GMM_FORMAT_NV21) || (pTexInfo->Format == GMM_FORMAT_P010) || (pTexInfo->Format == GMM_FORMAT_P012) || (pTexInfo->Format == GMM_FORMAT_P016)) { VHeight = GFX_CEIL_DIV(YHeight, 2); // U/V plane half of Y Height = YHeight + VHeight; } else { VHeight = YHeight; // U/V plane is same as Y Height = YHeight + VHeight; } if((pTexInfo->Format == GMM_FORMAT_NV12) || (pTexInfo->Format == GMM_FORMAT_NV21) || (pTexInfo->Format == GMM_FORMAT_P010) || (pTexInfo->Format == GMM_FORMAT_P012) || (pTexInfo->Format == GMM_FORMAT_P016) || (pTexInfo->Format == GMM_FORMAT_P208) || (pTexInfo->Format == GMM_FORMAT_P216)) { WidthBytesPhysical = GFX_ALIGN(WidthBytesPhysical, 2); // If odd YWidth, pitch bumps-up to fit rounded-up U/V planes. } else //if(pTexInfo->Format == GMM_FORMAT_NV11) { // Tiling not supported, since YPitch != UVPitch... pTexInfo->Flags.Info.TiledY = 0; pTexInfo->Flags.Info.TiledYf = 0; pTexInfo->Flags.Info.TiledYs = 0; pTexInfo->Flags.Info.TiledX = 0; pTexInfo->Flags.Info.Linear = 1; } UVPacked = true; pTexInfo->OffsetInfo.Plane.NoOfPlanes = 2; break; } case GMM_FORMAT_I420: // IYUV & I420: are identical to YV12 except, case GMM_FORMAT_IYUV: // U & V pl.s are reversed. case GMM_FORMAT_YV12: case GMM_FORMAT_YVU9: { // YYYYYYYY // YYYYYYYY // YYYYYYYY // YYYYYYYY // VVVVVV.. <-- V and U planes follow the Y plane, as linear // ..UUUUUU arrays--without respect to pitch. uint32_t YSize, UVSize, YVSizeRShift; uint32_t YSizeForUVPurposes, YSizeForUVPurposesDimensionalAlignment; YSize = WidthBytesPhysical * YHeight; // YVU9 has one U/V pixel for each 4x4 Y block. // The others have one U/V pixel for each 2x2 Y block. // YVU9 has a Y:V size ratio of 16 (4x4 --> 1). // The others have a ratio of 4 (2x2 --> 1). YVSizeRShift = (pTexInfo->Format != GMM_FORMAT_YVU9) ? 2 : 4; // If a Y plane isn't fully-aligned to its Y-->U/V block size, the // extra/unaligned Y pixels still need corresponding U/V pixels--So // for the purpose of computing the UVSize, we must consider a // dimensionally "rounded-up" YSize. (E.g. a 13x5 YVU9 Y plane would // require 4x2 U/V planes--the same UVSize as a fully-aligned 16x8 Y.) YSizeForUVPurposesDimensionalAlignment = (pTexInfo->Format != GMM_FORMAT_YVU9) ? 2 : 4; YSizeForUVPurposes = GFX_ALIGN(WidthBytesPhysical, YSizeForUVPurposesDimensionalAlignment) * GFX_ALIGN(YHeight, YSizeForUVPurposesDimensionalAlignment); UVSize = 2 * // <-- U + V (YSizeForUVPurposes >> YVSizeRShift); Height = GFX_CEIL_DIV(YSize + UVSize, WidthBytesPhysical); // Tiling not supported, since YPitch != UVPitch... pTexInfo->Flags.Info.TiledY = 0; pTexInfo->Flags.Info.TiledYf = 0; pTexInfo->Flags.Info.TiledYs = 0; pTexInfo->Flags.Info.TiledX = 0; pTexInfo->Flags.Info.Linear = 1; pTexInfo->OffsetInfo.Plane.NoOfPlanes = 1; break; } default: { GMM_ASSERTDPF(0, "Unexpected format"); return GMM_ERROR; } } // Align Height to even row to avoid hang if HW over-fetch Height = GFX_ALIGN(Height, __GMM_EVEN_ROW); SetTileMode(pTexInfo); // MMC is not supported for linear formats. if(pTexInfo->Flags.Gpu.MMC) { if(!(pTexInfo->Flags.Info.TiledY || pTexInfo->Flags.Info.TiledYf || pTexInfo->Flags.Info.TiledYs)) { pTexInfo->Flags.Gpu.MMC = 0; } } // Legacy Planar "Linear Video" Restrictions... if(pTexInfo->Flags.Info.Linear && !pTexInfo->Flags.Wa.NoLegacyPlanarLinearVideoRestrictions) { pRestrictions->LockPitchAlignment = GFX_MAX(pRestrictions->LockPitchAlignment, GMM_BYTES(64)); pRestrictions->MinPitch = GFX_MAX(pRestrictions->MinPitch, GMM_BYTES(64)); pRestrictions->PitchAlignment = GFX_MAX(pRestrictions->PitchAlignment, GMM_BYTES(64)); pRestrictions->RenderPitchAlignment = GFX_MAX(pRestrictions->RenderPitchAlignment, GMM_BYTES(64)); } // Multiply overall pitch alignment for surfaces whose U/V planes have a // pitch down-scaled from that of Y--Since the U/V pitches must meet the // original restriction, the Y pitch must meet a scaled-up multiple. if((pTexInfo->Format == GMM_FORMAT_I420) || (pTexInfo->Format == GMM_FORMAT_IYUV) || (pTexInfo->Format == GMM_FORMAT_NV11) || (pTexInfo->Format == GMM_FORMAT_YV12) || (pTexInfo->Format == GMM_FORMAT_YVU9)) { uint32_t LShift = (pTexInfo->Format != GMM_FORMAT_YVU9) ? 1 : // UVPitch = 1/2 YPitch 2; // UVPitch = 1/4 YPitch pRestrictions->LockPitchAlignment <<= LShift; pRestrictions->MinPitch <<= LShift; pRestrictions->PitchAlignment <<= LShift; pRestrictions->RenderPitchAlignment <<= LShift; } AdjustedVHeight = VHeight; // In case of Planar surfaces, only the last Plane has to be aligned to 64 for LCU access if(pGmmLibContext->GetWaTable().WaAlignYUVResourceToLCU && GmmIsYUVFormatLCUAligned(pTexInfo->Format) && VHeight > 0) { AdjustedVHeight = GFX_ALIGN(VHeight, GMM_SCANLINES(GMM_MAX_LCU_SIZE)); Height += AdjustedVHeight - VHeight; } // For Tiled Planar surfaces, the planes must be tile-boundary aligned. // Actual alignment is handled in FillPlanarOffsetAddress, but height // and width must be adjusted for correct size calculation if(GMM_IS_TILED(pPlatform->TileInfo[pTexInfo->TileMode])) { uint32_t TileHeight = pGmmLibContext->GetPlatformInfo().TileInfo[pTexInfo->TileMode].LogicalTileHeight; uint32_t TileWidth = pGmmLibContext->GetPlatformInfo().TileInfo[pTexInfo->TileMode].LogicalTileWidth; pTexInfo->OffsetInfo.Plane.IsTileAlignedPlanes = true; //for separate U and V planes, use U plane unaligned and V plane aligned Height = GFX_ALIGN(YHeight, TileHeight) + (UVPacked ? GFX_ALIGN(AdjustedVHeight, TileHeight) : (GFX_ALIGN(VHeight, TileHeight) + GFX_ALIGN(AdjustedVHeight, TileHeight))); if(pTexInfo->Format == GMM_FORMAT_IMC2 || // IMC2, IMC4 needs even tile columns pTexInfo->Format == GMM_FORMAT_IMC4) { // If the U & V planes are side-by-side then the surface pitch must be // padded out so that U and V planes will being on a tile boundary. // This means that an odd Y plane width must be padded out // with an additional tile. Even widths do not need padding uint32_t TileCols = GFX_CEIL_DIV(WidthBytesPhysical, TileWidth); if(TileCols % 2) { WidthBytesPhysical = (TileCols + 1) * TileWidth; } } if(pTexInfo->Flags.Info.TiledYs || pTexInfo->Flags.Info.TiledYf) { pTexInfo->Flags.Info.RedecribedPlanes = true; } } // Vary wide planar tiled planar formats do not support MMC pre gen11. All formats do not support //Special case LKF MMC compressed surfaces if(pTexInfo->Flags.Gpu.MMC && pTexInfo->Flags.Gpu.UnifiedAuxSurface && pTexInfo->Flags.Info.TiledY) { uint32_t TileHeight = pGmmLibContext->GetPlatformInfo().TileInfo[pTexInfo->TileMode].LogicalTileHeight; Height = GFX_ALIGN(YHeight, TileHeight) + GFX_ALIGN(AdjustedVHeight, TileHeight); } // Vary wide planar tiled planar formats do not support MMC pre gen11. All formats do not support // MMC above 16k bytes wide, while Yf NV12 does not support above 8k - 128 bytes. if((GFX_GET_CURRENT_RENDERCORE(pPlatform->Platform) <= IGFX_GEN10_CORE) && (pTexInfo->Flags.Info.TiledY || pTexInfo->Flags.Info.TiledYf || pTexInfo->Flags.Info.TiledYs)) { if(((pTexInfo->BaseWidth * pTexInfo->BitsPerPixel / 8) >= GMM_KBYTE(16)) || (pTexInfo->Format == GMM_FORMAT_NV12 && pTexInfo->Flags.Info.TiledYf && (pTexInfo->BaseWidth * pTexInfo->BitsPerPixel / 8) >= (GMM_KBYTE(8) - 128))) { pTexInfo->Flags.Gpu.MMC = 0; } } if(pTexInfo->Flags.Info.RedecribedPlanes) { if(false == RedescribeTexturePlanes(pTexInfo, &WidthBytesPhysical)) { __GMM_ASSERT(false); } } if((Status = // <-- Note assignment. FillTexPitchAndSize( pTexInfo, WidthBytesPhysical, Height, pRestrictions)) == GMM_SUCCESS) { FillPlanarOffsetAddress(pTexInfo); } // Planar & hybrid 2D arrays supported in DX11.1+ spec but not HW. Memory layout // is defined by SW requirements; Y plane must be 4KB aligned. if(pTexInfo->ArraySize > 1) { GMM_GFX_SIZE_T ElementSizeBytes = pTexInfo->Size; int64_t LargeSize; // Size should always be page aligned. __GMM_ASSERT((pTexInfo->Size % PAGE_SIZE) == 0); if((LargeSize = (int64_t)ElementSizeBytes * pTexInfo->ArraySize) <= pPlatform->SurfaceMaxSize) { pTexInfo->OffsetInfo.Plane.ArrayQPitch = ElementSizeBytes; pTexInfo->Size = LargeSize; } else { GMM_ASSERTDPF(0, "Surface too large!"); Status = GMM_ERROR; } } GMM_DPF_EXIT; return (Status); } // FillTexPlanar gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/Texture/GmmGen11Texture.cpp000066400000000000000000001400321466655022700251140ustar00rootroot00000000000000/*============================================================================== Copyright(c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ============================================================================*/ #include "Internal/Common/GmmLibInc.h" #include "Internal/Common/Texture/GmmGen10TextureCalc.h" #include "Internal/Common/Texture/GmmGen11TextureCalc.h" ///////////////////////////////////////////////////////////////////////////////////// /// This function calculates the (X,Y) address of each given plane. X is in bytes /// and Y is in scanlines. /// /// @param[in] pTexInfo: ptr to ::GMM_TEXTURE_INFO /// ///////////////////////////////////////////////////////////////////////////////////// void GmmLib::GmmGen11TextureCalc::FillPlanarOffsetAddress(GMM_TEXTURE_INFO *pTexInfo) { GMM_GFX_SIZE_T *pUOffsetX, *pUOffsetY; GMM_GFX_SIZE_T *pVOffsetX, *pVOffsetY; uint32_t YHeight = 0, VHeight = 0; bool UVPacked = false; uint32_t Height; uint32_t WidthBytesPhysical = GFX_ULONG_CAST(pTexInfo->BaseWidth) * pTexInfo->BitsPerPixel >> 3; #define SWAP_UV() \ { \ GMM_GFX_SIZE_T *pTemp; \ \ pTemp = pUOffsetX; \ pUOffsetX = pVOffsetX; \ pVOffsetX = pTemp; \ \ pTemp = pUOffsetY; \ pUOffsetY = pVOffsetY; \ pVOffsetY = pTemp; \ } __GMM_ASSERTPTR(pTexInfo, VOIDRETURN); __GMM_ASSERTPTR(((pTexInfo->TileMode < GMM_TILE_MODES) && (pTexInfo->TileMode >= TILE_NONE)), VOIDRETURN); GMM_DPF_ENTER; const GMM_PLATFORM_INFO *pPlatform = GMM_OVERRIDE_PLATFORM_INFO(pTexInfo, pGmmLibContext); // GMM_PLANE_Y always at (0, 0)... pTexInfo->OffsetInfo.Plane.X[GMM_PLANE_Y] = 0; pTexInfo->OffsetInfo.Plane.Y[GMM_PLANE_Y] = 0; pTexInfo->OffsetInfo.Plane.UnAligned.Height[GMM_PLANE_Y] = 0; pTexInfo->OffsetInfo.Plane.UnAligned.Height[GMM_PLANE_Y] = 0; Height = pTexInfo->BaseHeight; if(pTexInfo->Flags.Gpu.__NonMsaaTileYCcs) { Height = __GMM_EXPAND_HEIGHT(this, Height, pTexInfo->Alignment.VAlign, pTexInfo); Height = ScaleTextureHeight(pTexInfo, Height); if(pTexInfo->Flags.Gpu.UnifiedAuxSurface) { pTexInfo->OffsetInfo.Plane.Y[GMM_PLANE_Y] = 0; } } // GMM_PLANE_U/V Planes... pUOffsetX = &pTexInfo->OffsetInfo.Plane.X[GMM_PLANE_U]; pUOffsetY = &pTexInfo->OffsetInfo.Plane.Y[GMM_PLANE_U]; pVOffsetX = &pTexInfo->OffsetInfo.Plane.X[GMM_PLANE_V]; pVOffsetY = &pTexInfo->OffsetInfo.Plane.Y[GMM_PLANE_V]; switch(pTexInfo->Format) { case GMM_FORMAT_IMC1: SWAP_UV(); // IMC1 = IMC3 with Swapped U/V case GMM_FORMAT_IMC3: case GMM_FORMAT_MFX_JPEG_YUV420: // Same as IMC3. // YYYYYYYY // YYYYYYYY // YYYYYYYY // YYYYYYYY // UUUU // UUUU // VVVV // VVVV case GMM_FORMAT_MFX_JPEG_YUV422V: // Similar to IMC3 but U/V are full width. // YYYYYYYY // YYYYYYYY // YYYYYYYY // YYYYYYYY // UUUUUUUU // UUUUUUUU // VVVVVVVV // VVVVVVVV { *pUOffsetX = 0; YHeight = GFX_ALIGN(pTexInfo->BaseHeight, GMM_IMCx_PLANE_ROW_ALIGNMENT); *pUOffsetY = GFX_ALIGN(pTexInfo->BaseHeight, GMM_IMCx_PLANE_ROW_ALIGNMENT); *pVOffsetX = 0; VHeight = GFX_ALIGN(GFX_CEIL_DIV(pTexInfo->BaseHeight, 2), GMM_IMCx_PLANE_ROW_ALIGNMENT); *pVOffsetY = GFX_ALIGN(pTexInfo->BaseHeight, GMM_IMCx_PLANE_ROW_ALIGNMENT) + GFX_ALIGN(GFX_CEIL_DIV(pTexInfo->BaseHeight, 2), GMM_IMCx_PLANE_ROW_ALIGNMENT); break; } case GMM_FORMAT_MFX_JPEG_YUV411R_TYPE: //Similar to IMC3 but U/V are quarther height and full width. //YYYYYYYY //YYYYYYYY //YYYYYYYY //YYYYYYYY //UUUUUUUU //VVVVVVVV { *pUOffsetX = 0; YHeight = GFX_ALIGN(pTexInfo->BaseHeight, GMM_IMCx_PLANE_ROW_ALIGNMENT); *pUOffsetY = GFX_ALIGN(pTexInfo->BaseHeight, GMM_IMCx_PLANE_ROW_ALIGNMENT); *pVOffsetX = 0; VHeight = GFX_ALIGN(GFX_CEIL_DIV(pTexInfo->BaseHeight, 4), GMM_IMCx_PLANE_ROW_ALIGNMENT); *pVOffsetY = GFX_ALIGN(pTexInfo->BaseHeight, GMM_IMCx_PLANE_ROW_ALIGNMENT) + GFX_ALIGN(GFX_CEIL_DIV(pTexInfo->BaseHeight, 4), GMM_IMCx_PLANE_ROW_ALIGNMENT); break; } case GMM_FORMAT_MFX_JPEG_YUV411: // Similar to IMC3 but U/V are quarter width and full height. // YYYYYYYY // YYYYYYYY // YYYYYYYY // YYYYYYYY // UU // UU // UU // UU // VV // VV // VV // VV case GMM_FORMAT_MFX_JPEG_YUV422H: // Similar to IMC3 but U/V are full height. // YYYYYYYY // YYYYYYYY // YYYYYYYY // YYYYYYYY // UUUU // UUUU // UUUU // UUUU // VVVV // VVVV // VVVV // VVVV case GMM_FORMAT_MFX_JPEG_YUV444: // Similar to IMC3 but U/V are full size. // YYYYYYYY // YYYYYYYY // YYYYYYYY // YYYYYYYY // UUUUUUUU // UUUUUUUU // UUUUUUUU // UUUUUUUU // VVVVVVVV // VVVVVVVV // VVVVVVVV // VVVVVVVV { *pUOffsetX = 0; YHeight = GFX_ALIGN(pTexInfo->BaseHeight, GMM_IMCx_PLANE_ROW_ALIGNMENT); *pUOffsetY = GFX_ALIGN(pTexInfo->BaseHeight, GMM_IMCx_PLANE_ROW_ALIGNMENT); *pVOffsetX = 0; VHeight = GFX_ALIGN(pTexInfo->BaseHeight, GMM_IMCx_PLANE_ROW_ALIGNMENT); *pVOffsetY = GFX_ALIGN(pTexInfo->BaseHeight, GMM_IMCx_PLANE_ROW_ALIGNMENT) * 2; break; } case GMM_FORMAT_BGRP: case GMM_FORMAT_RGBP: { //For RGBP linear Tile keep resource Offset non aligned and for other Tile format to be 16-bit aligned if(pTexInfo->Flags.Info.Linear) { *pUOffsetX = 0; YHeight = pTexInfo->BaseHeight; *pUOffsetY = pTexInfo->BaseHeight; *pVOffsetX = 0; VHeight = pTexInfo->BaseHeight; *pVOffsetY = (GMM_GFX_SIZE_T)pTexInfo->BaseHeight * 2; } else //Tiled { *pUOffsetX = 0; YHeight = GFX_ALIGN(pTexInfo->BaseHeight, GMM_IMCx_PLANE_ROW_ALIGNMENT); *pUOffsetY = GFX_ALIGN(pTexInfo->BaseHeight, GMM_IMCx_PLANE_ROW_ALIGNMENT); *pVOffsetX = 0; VHeight = GFX_ALIGN(pTexInfo->BaseHeight, GMM_IMCx_PLANE_ROW_ALIGNMENT); *pVOffsetY = (GMM_GFX_SIZE_T)GFX_ALIGN(pTexInfo->BaseHeight, GMM_IMCx_PLANE_ROW_ALIGNMENT) * 2; } break; } case GMM_FORMAT_IMC2: SWAP_UV(); // IMC2 = IMC4 with Swapped U/V case GMM_FORMAT_IMC4: { // YYYYYYYY // YYYYYYYY // YYYYYYYY // YYYYYYYY // UUUUVVVV // UUUUVVVV __GMM_ASSERT((pTexInfo->Pitch & 1) == 0); *pUOffsetX = 0; YHeight = GFX_ALIGN(pTexInfo->BaseHeight, GMM_IMCx_PLANE_ROW_ALIGNMENT); *pUOffsetY = GFX_ALIGN(pTexInfo->BaseHeight, GMM_IMCx_PLANE_ROW_ALIGNMENT); *pVOffsetX = pTexInfo->Pitch / 2; VHeight = GFX_CEIL_DIV(YHeight, 2); *pVOffsetY = GFX_ALIGN(pTexInfo->BaseHeight, GMM_IMCx_PLANE_ROW_ALIGNMENT); // Not technically UV packed but sizing works out the same UVPacked = true; break; } case GMM_FORMAT_I420: // I420 = IYUV case GMM_FORMAT_IYUV: SWAP_UV(); // I420/IYUV = YV12 with Swapped U/V case GMM_FORMAT_YV12: case GMM_FORMAT_YVU9: { // YYYYYYYY // YYYYYYYY // YYYYYYYY // YYYYYYYY // VVVVVV.. <-- V and U planes follow the Y plane, as linear // ..UUUUUU arrays--without respect to pitch. uint32_t YSize, YVSizeRShift, VSize, UOffset; uint32_t YSizeForUVPurposes, YSizeForUVPurposesDimensionalAlignment; YSize = GFX_ULONG_CAST(pTexInfo->Pitch) * pTexInfo->BaseHeight; // YVU9 has one U/V pixel for each 4x4 Y block. // The others have one U/V pixel for each 2x2 Y block. // YVU9 has a Y:V size ratio of 16 (4x4 --> 1). // The others have a ratio of 4 (2x2 --> 1). YVSizeRShift = (pTexInfo->Format != GMM_FORMAT_YVU9) ? 2 : 4; // If a Y plane isn't fully-aligned to its Y-->U/V block size, the // extra/unaligned Y pixels still need corresponding U/V pixels--So // for the purpose of computing the UVSize, we must consider a // dimensionally "rounded-up" YSize. (E.g. a 13x5 YVU9 Y plane would // require 4x2 U/V planes--the same UVSize as a fully-aligned 16x8 Y.) YSizeForUVPurposesDimensionalAlignment = (pTexInfo->Format != GMM_FORMAT_YVU9) ? 2 : 4; YSizeForUVPurposes = GFX_ALIGN(GFX_ULONG_CAST(pTexInfo->Pitch), YSizeForUVPurposesDimensionalAlignment) * GFX_ALIGN(pTexInfo->BaseHeight, YSizeForUVPurposesDimensionalAlignment); VSize = (YSizeForUVPurposes >> YVSizeRShift); UOffset = YSize + VSize; *pVOffsetX = 0; *pVOffsetY = pTexInfo->BaseHeight; *pUOffsetX = UOffset % pTexInfo->Pitch; *pUOffsetY = UOffset / pTexInfo->Pitch; YHeight = GFX_CEIL_DIV(YSize + 2 * VSize, WidthBytesPhysical); break; } case GMM_FORMAT_NV12: case GMM_FORMAT_NV21: case GMM_FORMAT_NV11: case GMM_FORMAT_P010: case GMM_FORMAT_P012: case GMM_FORMAT_P016: case GMM_FORMAT_P208: case GMM_FORMAT_P216: { // YYYYYYYY // YYYYYYYY // YYYYYYYY // YYYYYYYY // [UV-Packing] *pUOffsetX = *pVOffsetX = 0; YHeight = GFX_ALIGN(Height, __GMM_EVEN_ROW); *pUOffsetY = *pVOffsetY = YHeight; if((pTexInfo->Format == GMM_FORMAT_NV12) || (pTexInfo->Format == GMM_FORMAT_NV21) || (pTexInfo->Format == GMM_FORMAT_P010) || (pTexInfo->Format == GMM_FORMAT_P012) || (pTexInfo->Format == GMM_FORMAT_P016)) { VHeight = GFX_CEIL_DIV(Height, 2); } else { VHeight = YHeight; // U/V plane is same as Y } UVPacked = true; break; } default: { GMM_ASSERTDPF(0, "Unknown Video Format U\n"); break; } } pTexInfo->OffsetInfo.Plane.UnAligned.Height[GMM_PLANE_Y] = YHeight; if(pTexInfo->OffsetInfo.Plane.NoOfPlanes == 2) { pTexInfo->OffsetInfo.Plane.UnAligned.Height[GMM_PLANE_U] = VHeight; } else if(pTexInfo->OffsetInfo.Plane.NoOfPlanes == 3) { pTexInfo->OffsetInfo.Plane.UnAligned.Height[GMM_PLANE_U] = pTexInfo->OffsetInfo.Plane.UnAligned.Height[GMM_PLANE_V] = VHeight; } if(GMM_IS_TILED(pPlatform->TileInfo[pTexInfo->TileMode]) || pTexInfo->Flags.Gpu.__NonMsaaTileYCcs) { GMM_GFX_SIZE_T TileHeight = pPlatform->TileInfo[pTexInfo->TileMode].LogicalTileHeight; GMM_GFX_SIZE_T TileWidth = pPlatform->TileInfo[pTexInfo->TileMode].LogicalTileWidth; GMM_GFX_SIZE_T PhysicalTileHeight = TileHeight; if(GFX_GET_CURRENT_RENDERCORE(pPlatform->Platform) > IGFX_GEN11LP_CORE) { if(pTexInfo->Flags.Gpu.CCS && !pGmmLibContext->GetSkuTable().FtrFlatPhysCCS) { //U/V must be aligned to AuxT granularity, 4x pitchalign enforces 16K-align for 4KB tile, //add extra padding for 64K AuxT, 1MB AuxT if(GMM_IS_64KB_TILE(pTexInfo->Flags)) { TileHeight *= (!WA64K(pGmmLibContext) && !WA16K(pGmmLibContext)) ? 16 : 1; // For 64Kb Tile mode: Multiply TileHeight by 16 for 1 MB alignment } else { PhysicalTileHeight *= (WA16K(pGmmLibContext) ? 1 : WA64K(pGmmLibContext) ? 4 : 1); // for 1 MB AuxT granularity, we do 1 MB alignment only in VA space and not in physical space, so do not multiply PhysicalTileHeight with 64 here TileHeight *= (WA16K(pGmmLibContext) ? 1 : WA64K(pGmmLibContext) ? 4 : 64); // For 4k Tile: Multiply TileHeight by 4 and Pitch by 4 for 64kb alignment, multiply TileHeight by 64 and Pitch by 4 for 1 MB alignment } } } *pUOffsetX = GFX_ALIGN(*pUOffsetX, TileWidth); *pUOffsetY = GFX_ALIGN(*pUOffsetY, TileHeight); *pVOffsetX = GFX_ALIGN(*pVOffsetX, TileWidth); *pVOffsetY = UVPacked ? GFX_ALIGN(*pVOffsetY, TileHeight) : GFX_ALIGN(YHeight, TileHeight) + GFX_ALIGN(VHeight, TileHeight); if(pTexInfo->Flags.Gpu.UnifiedAuxSurface && pTexInfo->Flags.Gpu.__NonMsaaTileYCcs) { *pUOffsetY += pTexInfo->OffsetInfo.Plane.Y[GMM_PLANE_Y]; *pVOffsetY = *pUOffsetY; } // This is needed for FtrDisplayPageTables if(pGmmLibContext->GetSkuTable().FtrDisplayPageTables) { pTexInfo->OffsetInfo.Plane.Aligned.Height[GMM_PLANE_Y] = GFX_ALIGN(YHeight, TileHeight); if(pTexInfo->OffsetInfo.Plane.NoOfPlanes == 2) { pTexInfo->OffsetInfo.Plane.Aligned.Height[GMM_PLANE_U] = GFX_ALIGN(VHeight, TileHeight); } else if(pTexInfo->OffsetInfo.Plane.NoOfPlanes == 3) { pTexInfo->OffsetInfo.Plane.Aligned.Height[GMM_PLANE_U] = pTexInfo->OffsetInfo.Plane.Aligned.Height[GMM_PLANE_V] = GFX_ALIGN(VHeight, TileHeight); } } } //Special case LKF MMC compressed surfaces if(pTexInfo->Flags.Gpu.MMC && pTexInfo->Flags.Gpu.UnifiedAuxSurface && pTexInfo->Flags.Info.TiledY) { GMM_GFX_SIZE_T TileHeight = pGmmLibContext->GetPlatformInfo().TileInfo[pTexInfo->TileMode].LogicalTileHeight; GMM_GFX_SIZE_T TileWidth = pGmmLibContext->GetPlatformInfo().TileInfo[pTexInfo->TileMode].LogicalTileWidth; *pUOffsetX = GFX_ALIGN(*pUOffsetX, TileWidth); *pUOffsetY = GFX_ALIGN(*pUOffsetY, TileHeight); *pVOffsetX = GFX_ALIGN(*pVOffsetX, TileWidth); *pVOffsetY = GFX_ALIGN(*pVOffsetY, TileHeight); } GMM_DPF_EXIT; #undef SWAP_UV } ///////////////////////////////////////////////////////////////////////////////////// /// Returns the mip offset of given LOD in Mip Tail /// /// @param[in] pTexInfo: ptr to ::GMM_TEXTURE_INFO, /// MipLevel: mip-map level /// /// @return offset value of LOD in bytes ///////////////////////////////////////////////////////////////////////////////////// uint32_t GmmLib::GmmGen11TextureCalc::GetMipTailByteOffset(GMM_TEXTURE_INFO *pTexInfo, uint32_t MipLevel) { uint32_t ByteOffset = 0, Slot = 0xff; GMM_DPF_ENTER; // 3D textures follow the Gen10 mip tail format if(!pGmmLibContext->GetSkuTable().FtrStandardMipTailFormat) { return GmmGen9TextureCalc::GetMipTailByteOffset(pTexInfo, MipLevel); } if((pTexInfo->Type == RESOURCE_1D) || (pTexInfo->Type == RESOURCE_3D)) { Slot = MipLevel - pTexInfo->Alignment.MipTailStartLod + (pTexInfo->Flags.Info.TiledYf ? 4 : 0); } else if(pTexInfo->Type == RESOURCE_2D || pTexInfo->Type == RESOURCE_CUBE) { // clang-format off Slot = MipLevel - pTexInfo->Alignment.MipTailStartLod + // TileYs ((pTexInfo->Flags.Info.TiledYs && pTexInfo->MSAA.NumSamples == 16) ? 4 : (pTexInfo->Flags.Info.TiledYs && pTexInfo->MSAA.NumSamples == 8) ? 3 : (pTexInfo->Flags.Info.TiledYs && pTexInfo->MSAA.NumSamples == 4) ? 2 : (pTexInfo->Flags.Info.TiledYs && pTexInfo->MSAA.NumSamples == 2) ? 1 : (pTexInfo->Flags.Info.TiledYs ) ? 0 : // TileYf (pTexInfo->Flags.Info.TiledYf && pTexInfo->MSAA.NumSamples == 16) ? 11: (pTexInfo->Flags.Info.TiledYf && pTexInfo->MSAA.NumSamples == 8) ? 10: (pTexInfo->Flags.Info.TiledYf && pTexInfo->MSAA.NumSamples == 4) ? 8: (pTexInfo->Flags.Info.TiledYf && pTexInfo->MSAA.NumSamples == 2) ? 5: (pTexInfo->Flags.Info.TiledYf ) ? 4: 0); // clang-format on } switch(Slot) { case 0: ByteOffset = GMM_KBYTE(32); break; case 1: ByteOffset = GMM_KBYTE(16); break; case 2: ByteOffset = GMM_KBYTE(8); break; case 3: ByteOffset = GMM_KBYTE(4); break; case 4: ByteOffset = GMM_KBYTE(2); break; case 5: ByteOffset = GMM_BYTES(1536); break; case 6: ByteOffset = GMM_BYTES(1280); break; case 7: ByteOffset = GMM_BYTES(1024); break; case 8: ByteOffset = GMM_BYTES(768); break; case 9: ByteOffset = GMM_BYTES(512); break; case 10: ByteOffset = GMM_BYTES(256); break; case 11: ByteOffset = GMM_BYTES(0); break; case 12: ByteOffset = GMM_BYTES(64); break; case 13: ByteOffset = GMM_BYTES(128); break; case 14: ByteOffset = GMM_BYTES(196); break; default: __GMM_ASSERT(0); } GMM_DPF_EXIT; return (ByteOffset); } ///////////////////////////////////////////////////////////////////////////////////// /// Returns the mip-map offset in geometric OffsetX, Y, Z for a given LOD in Mip Tail on Gen11. /// /// @param[in] pTexInfo: ptr to ::GMM_TEXTURE_INFO, /// MipLevel: mip-map level /// OffsetX: ptr to Offset in X direction (in bytes) /// OffsetY: ptr to Offset in Y direction (in pixels) /// OffsetZ: ptr to Offset in Z direction (in pixels) /// ///////////////////////////////////////////////////////////////////////////////////// GMM_MIPTAIL_SLOT_OFFSET Gen11MipTailSlotOffset1DSurface[15][5] = GEN11_MIPTAIL_SLOT_OFFSET_1D_SURFACE; GMM_MIPTAIL_SLOT_OFFSET Gen11MipTailSlotOffset2DSurface[15][5] = GEN11_MIPTAIL_SLOT_OFFSET_2D_SURFACE; GMM_MIPTAIL_SLOT_OFFSET Gen11MipTailSlotOffset3DSurface[15][5] = GEN11_MIPTAIL_SLOT_OFFSET_3D_SURFACE; void GmmLib::GmmGen11TextureCalc::GetMipTailGeometryOffset(GMM_TEXTURE_INFO *pTexInfo, uint32_t MipLevel, uint32_t * OffsetX, uint32_t * OffsetY, uint32_t * OffsetZ) { uint32_t ArrayIndex = 0; uint32_t Slot = 0; GMM_DPF_ENTER; switch(pTexInfo->BitsPerPixel) { case 128: ArrayIndex = 0; break; case 64: ArrayIndex = 1; break; case 32: ArrayIndex = 2; break; case 16: ArrayIndex = 3; break; case 8: ArrayIndex = 4; break; default: __GMM_ASSERT(0); break; } if(pTexInfo->Type == RESOURCE_1D) { Slot = MipLevel - pTexInfo->Alignment.MipTailStartLod; *OffsetX = Gen11MipTailSlotOffset1DSurface[Slot][ArrayIndex].X * pTexInfo->BitsPerPixel / 8; *OffsetY = Gen11MipTailSlotOffset1DSurface[Slot][ArrayIndex].Y; *OffsetZ = Gen11MipTailSlotOffset1DSurface[Slot][ArrayIndex].Z; } else if(pTexInfo->Type == RESOURCE_2D || pTexInfo->Type == RESOURCE_CUBE) { // clang-format off Slot = MipLevel - pTexInfo->Alignment.MipTailStartLod + // TileYs ((pTexInfo->Flags.Info.TiledYs && pTexInfo->MSAA.NumSamples == 16) ? 4 : (pTexInfo->Flags.Info.TiledYs && pTexInfo->MSAA.NumSamples == 8) ? 3 : (pTexInfo->Flags.Info.TiledYs && pTexInfo->MSAA.NumSamples == 4) ? 2 : (pTexInfo->Flags.Info.TiledYs && pTexInfo->MSAA.NumSamples == 2) ? 1 : (pTexInfo->Flags.Info.TiledYs) ? 0 : // TileYf (pTexInfo->Flags.Info.TiledYf && pTexInfo->MSAA.NumSamples == 16) ? 11 : (pTexInfo->Flags.Info.TiledYf && pTexInfo->MSAA.NumSamples == 8) ? 10 : (pTexInfo->Flags.Info.TiledYf && pTexInfo->MSAA.NumSamples == 4) ? 8 : (pTexInfo->Flags.Info.TiledYf && pTexInfo->MSAA.NumSamples == 2) ? 5 : (pTexInfo->Flags.Info.TiledYf) ? 4 : 0); // clang-format on *OffsetX = Gen11MipTailSlotOffset2DSurface[Slot][ArrayIndex].X * pTexInfo->BitsPerPixel / 8; *OffsetY = Gen11MipTailSlotOffset2DSurface[Slot][ArrayIndex].Y; *OffsetZ = Gen11MipTailSlotOffset2DSurface[Slot][ArrayIndex].Z; } else if(pTexInfo->Type == RESOURCE_3D) { Slot = MipLevel - pTexInfo->Alignment.MipTailStartLod; *OffsetX = Gen11MipTailSlotOffset3DSurface[Slot][ArrayIndex].X * pTexInfo->BitsPerPixel / 8; *OffsetY = Gen11MipTailSlotOffset3DSurface[Slot][ArrayIndex].Y; *OffsetZ = Gen11MipTailSlotOffset3DSurface[Slot][ArrayIndex].Z; } GMM_DPF_EXIT; return; } GMM_STATUS GmmLib::GmmGen11TextureCalc::FillLinearCCS(GMM_TEXTURE_INFO * pTexInfo, __GMM_BUFFER_TYPE *pRestrictions) { GMM_GFX_SIZE_T PaddedSize; uint32_t TileHeight; GMM_GFX_SIZE_T YCcsSize = 0; GMM_GFX_SIZE_T UVCcsSize = 0; GMM_GFX_SIZE_T TotalHeight = 0; const GMM_PLATFORM_INFO *pPlatform = GMM_OVERRIDE_PLATFORM_INFO(pTexInfo, pGmmLibContext); GMM_DPF_ENTER; __GMM_ASSERT(pTexInfo->Flags.Gpu.MMC && pTexInfo->Flags.Gpu.UnifiedAuxSurface && pTexInfo->Flags.Gpu.__NonMsaaLinearCCS); __GMM_ASSERT(pTexInfo->OffsetInfo.Plane.Y[GMM_PLANE_U] > 0); TileHeight = pPlatform->TileInfo[pTexInfo->TileMode].LogicalTileHeight; // Vinante : CCS or Tile status buffer is computed by giving 2bit for every 256bytes of origional pixel data. // For YUV Planar surfaces, UV Plane follow immediately after Y plane. Y and UV surfaces have their own // control surfaces. So AuxSurf will be linear buffer with CCS for Y plane followed by CCS for UV plane. // Y and UV control surface must be 4kb base aligned and they store the control data for full tiles covering Y and UV // planes respectively. // GMM will also allocate cacheline aligned 64-byte to hold the LKF's software controlled media compression state. // GMM will calculate YAuxOffset, UVAuxOffset and MediaCompression State offset on the fly. Refer GmmResGetAuxSurfaceOffset(). YCcsSize = pTexInfo->OffsetInfo.Plane.Y[GMM_PLANE_U] * pTexInfo->Pitch / 1024; YCcsSize = GFX_ALIGN(YCcsSize, PAGE_SIZE); if(pTexInfo->ArraySize > 1) { TotalHeight = pTexInfo->OffsetInfo.Plane.ArrayQPitch / pTexInfo->Pitch; } else { TotalHeight = pTexInfo->Size / pTexInfo->Pitch; } UVCcsSize = (TotalHeight - pTexInfo->OffsetInfo.Plane.Y[GMM_PLANE_U]) * pTexInfo->Pitch / 1024; UVCcsSize = GFX_ALIGN(UVCcsSize, PAGE_SIZE); pTexInfo->Size = GFX_ALIGN(YCcsSize + UVCcsSize + GMM_MEDIA_COMPRESSION_STATE_SIZE, pRestrictions->MinAllocationSize); pTexInfo->Pitch = 0; //Store the dimension of linear surface in OffsetInfo.Plane.X. pTexInfo->OffsetInfo.Plane.X[GMM_PLANE_Y] = YCcsSize; pTexInfo->OffsetInfo.Plane.X[GMM_PLANE_U] = pTexInfo->OffsetInfo.Plane.X[GMM_PLANE_V] = UVCcsSize; pTexInfo->OffsetInfo.Plane.Y[GMM_PLANE_Y] = pTexInfo->OffsetInfo.Plane.Y[GMM_PLANE_U] = pTexInfo->OffsetInfo.Plane.Y[GMM_PLANE_V] = 0; // Planar & hybrid 2D arrays supported in DX11.1+ spec but not HW. Memory layout // is defined by SW requirements; Y plane must be 4KB aligned. if(pTexInfo->ArraySize > 1) { GMM_GFX_SIZE_T ElementSizeBytes = pTexInfo->Size; int64_t LargeSize; // Size should always be page aligned. __GMM_ASSERT((pTexInfo->Size % PAGE_SIZE) == 0); if((LargeSize = (int64_t)ElementSizeBytes * pTexInfo->ArraySize) <= pPlatform->SurfaceMaxSize) { pTexInfo->OffsetInfo.Plane.ArrayQPitch = ElementSizeBytes; pTexInfo->Size = LargeSize; } else { GMM_ASSERTDPF(0, "Surface too large!"); return GMM_ERROR; } } return GMM_SUCCESS; GMM_DPF_EXIT; } ///////////////////////////////////////////////////////////////////////////////////// /// This function will Setup a planar surface allocation. /// /// @param[in] pTexInfo: Reference to ::GMM_TEXTURE_INFO /// @param[in] pRestrictions: Reference to surface alignment and size restrictions. /// /// @return ::GMM_STATUS ///////////////////////////////////////////////////////////////////////////////////// GMM_STATUS GMM_STDCALL GmmLib::GmmGen11TextureCalc::FillTexPlanar(GMM_TEXTURE_INFO * pTexInfo, __GMM_BUFFER_TYPE *pRestrictions) { const GMM_PLATFORM_INFO *pPlatform = GMM_OVERRIDE_PLATFORM_INFO(pTexInfo, pGmmLibContext); GMM_DPF_ENTER; uint32_t WidthBytesPhysical, Height, YHeight, VHeight; uint32_t AdjustedVHeight = 0; GMM_STATUS Status; bool UVPacked = false; GMM_DPF_ENTER; __GMM_ASSERTPTR(pTexInfo, GMM_ERROR); __GMM_ASSERTPTR(pRestrictions, GMM_ERROR); __GMM_ASSERT(!pTexInfo->Flags.Info.TiledW); pTexInfo->TileMode = TILE_NONE; WidthBytesPhysical = GFX_ULONG_CAST(pTexInfo->BaseWidth) * pTexInfo->BitsPerPixel >> 3; Height = VHeight = 0; YHeight = pTexInfo->BaseHeight; //[History] // When planar surfaces are tiled, there are HW alignment // restrictions about where the U and V planes can be located. // Prior to SURFACE_STATE.X/YOffset support, planes needed to start // on tile boundaries; with X/YOffset support, the alignment // restrictions were reduced (but not eliminated). // // Horizontal alignment is only an issue for IMC2/4 surfaces, since // the planes of all other formats are always on the left-edge. // // For IMC1/3 surfaces, we must ensure that both the U/V planes are // properly aligned--That is, both the YHeight and VHeight must be // properly aligned. For all other surfaces (since the U/V data // starts at a common vertical location) only YHeight must be // properly aligned. // [Current] : // For Tiled surfaces, even though h/w supports U and V plane alignment // at lower granularities GMM will align all the planes at Tiled boundary // to unify the implementation across all platforms and GMM will add // handling for removing the extra padding when UMDs request for ResCpuBlt // operations. // For Linear surfaces, GMM will continue to support minimal aligment restrictions switch(pTexInfo->Format) { case GMM_FORMAT_IMC1: // IMC1 = IMC3 with Swapped U/V case GMM_FORMAT_IMC3: case GMM_FORMAT_MFX_JPEG_YUV420: // Same as IMC3. // YYYYYYYY // YYYYYYYY // YYYYYYYY // YYYYYYYY // UUUU // UUUU // VVVV // VVVV case GMM_FORMAT_MFX_JPEG_YUV422V: // Similar to IMC3 but U/V are full width. // YYYYYYYY // YYYYYYYY // YYYYYYYY // YYYYYYYY // UUUUUUUU // UUUUUUUU // VVVVVVVV // VVVVVVVV { VHeight = GFX_ALIGN(GFX_CEIL_DIV(YHeight, 2), GMM_IMCx_PLANE_ROW_ALIGNMENT); YHeight = GFX_ALIGN(YHeight, GMM_IMCx_PLANE_ROW_ALIGNMENT); Height = YHeight + 2 * VHeight; // One VHeight for V and one for U. pTexInfo->OffsetInfo.Plane.NoOfPlanes = 3; break; } case GMM_FORMAT_MFX_JPEG_YUV411R_TYPE: //Similar to IMC3 but U/V are quarther height and full width. //YYYYYYYY //YYYYYYYY //YYYYYYYY //YYYYYYYY //UUUUUUUU //VVVVVVVV { VHeight = GFX_ALIGN(GFX_CEIL_DIV(YHeight, 4), GMM_IMCx_PLANE_ROW_ALIGNMENT); YHeight = GFX_ALIGN(YHeight, GMM_IMCx_PLANE_ROW_ALIGNMENT); Height = YHeight + 2 * VHeight; pTexInfo->OffsetInfo.Plane.NoOfPlanes = 3; break; } case GMM_FORMAT_MFX_JPEG_YUV411: // Similar to IMC3 but U/V are quarter width and full height. // YYYYYYYY // YYYYYYYY // YYYYYYYY // YYYYYYYY // UU // UU // UU // UU // VV // VV // VV // VV case GMM_FORMAT_MFX_JPEG_YUV422H: // Similar to IMC3 but U/V are full height. // YYYYYYYY // YYYYYYYY // YYYYYYYY // YYYYYYYY // UUUU // UUUU // UUUU // UUUU // VVVV // VVVV // VVVV // VVVV case GMM_FORMAT_MFX_JPEG_YUV444: // Similar to IMC3 but U/V are full size. #if _WIN32 case GMM_FORMAT_WGBOX_YUV444: case GMM_FORMAT_WGBOX_PLANAR_YUV444: #endif // YYYYYYYY // YYYYYYYY // YYYYYYYY // YYYYYYYY // UUUUUUUU // UUUUUUUU // UUUUUUUU // UUUUUUUU // VVVVVVVV // VVVVVVVV // VVVVVVVV // VVVVVVVV { YHeight = GFX_ALIGN(YHeight, GMM_IMCx_PLANE_ROW_ALIGNMENT); VHeight = YHeight; Height = YHeight + 2 * VHeight; pTexInfo->OffsetInfo.Plane.NoOfPlanes = 3; break; } case GMM_FORMAT_BGRP: case GMM_FORMAT_RGBP: { //For RGBP linear Tile keep resource Offset non aligned and for other Tile format to be 16-bit aligned if(pTexInfo->Flags.Info.Linear) { VHeight = YHeight; Height = YHeight + 2 * VHeight; pTexInfo->OffsetInfo.Plane.NoOfPlanes = 3; } else //Tiled { YHeight = GFX_ALIGN(YHeight, GMM_IMCx_PLANE_ROW_ALIGNMENT); VHeight = YHeight; Height = YHeight + 2 * VHeight; pTexInfo->OffsetInfo.Plane.NoOfPlanes = 3; } break; } case GMM_FORMAT_IMC2: // IMC2 = IMC4 with Swapped U/V case GMM_FORMAT_IMC4: { // YYYYYYYY // YYYYYYYY // YYYYYYYY // YYYYYYYY // UUUUVVVV // UUUUVVVV YHeight = GFX_ALIGN(YHeight, GMM_IMCx_PLANE_ROW_ALIGNMENT); VHeight = GFX_CEIL_DIV(YHeight, 2); WidthBytesPhysical = GFX_ALIGN(WidthBytesPhysical, 2); // If odd YWidth, pitch bumps-up to fit rounded-up U/V planes. Height = YHeight + VHeight; // With SURFACE_STATE.XOffset support, the U-V interface has // much lighter restrictions--which will be naturally met by // surface pitch restrictions (i.e. dividing an IMC2/4 pitch // by 2--to get the U/V interface--will always produce a safe // XOffset value). // Not technically UV packed but sizing works out the same // if the resource is std swizzled UVPacked = true; pTexInfo->OffsetInfo.Plane.NoOfPlanes = 2; break; } case GMM_FORMAT_NV12: case GMM_FORMAT_NV21: case GMM_FORMAT_NV11: case GMM_FORMAT_P010: case GMM_FORMAT_P012: case GMM_FORMAT_P016: case GMM_FORMAT_P208: case GMM_FORMAT_P216: { // YYYYYYYY // YYYYYYYY // YYYYYYYY // YYYYYYYY // [UV-Packing] if((pTexInfo->Format == GMM_FORMAT_NV12) || (pTexInfo->Format == GMM_FORMAT_NV21) || (pTexInfo->Format == GMM_FORMAT_P010) || (pTexInfo->Format == GMM_FORMAT_P012) || (pTexInfo->Format == GMM_FORMAT_P016)) { VHeight = GFX_CEIL_DIV(YHeight, 2); // U/V plane half of Y Height = YHeight + VHeight; } else { VHeight = YHeight; // U/V plane is same as Y Height = YHeight + VHeight; } if((pTexInfo->Format == GMM_FORMAT_NV12) || (pTexInfo->Format == GMM_FORMAT_NV21) || (pTexInfo->Format == GMM_FORMAT_P010) || (pTexInfo->Format == GMM_FORMAT_P012) || (pTexInfo->Format == GMM_FORMAT_P016) || (pTexInfo->Format == GMM_FORMAT_P208) || (pTexInfo->Format == GMM_FORMAT_P216)) { WidthBytesPhysical = GFX_ALIGN(WidthBytesPhysical, 2); // If odd YWidth, pitch bumps-up to fit rounded-up U/V planes. pTexInfo->OffsetInfo.Plane.NoOfPlanes = 2; } else //if(pTexInfo->Format == GMM_FORMAT_NV11) { // Tiling not supported, since YPitch != UVPitch... pTexInfo->Flags.Info.TiledY = 0; pTexInfo->Flags.Info.TiledYf = 0; pTexInfo->Flags.Info.TiledYs = 0; pTexInfo->Flags.Info.TiledX = 0; pTexInfo->Flags.Info.Linear = 1; } UVPacked = true; break; } case GMM_FORMAT_I420: // IYUV & I420: are identical to YV12 except, case GMM_FORMAT_IYUV: // U & V pl.s are reversed. case GMM_FORMAT_YV12: case GMM_FORMAT_YVU9: { // YYYYYYYY // YYYYYYYY // YYYYYYYY // YYYYYYYY // VVVVVV.. <-- V and U planes follow the Y plane, as linear // ..UUUUUU arrays--without respect to pitch. uint32_t YSize, UVSize, YVSizeRShift; uint32_t YSizeForUVPurposes, YSizeForUVPurposesDimensionalAlignment; YSize = WidthBytesPhysical * YHeight; // YVU9 has one U/V pixel for each 4x4 Y block. // The others have one U/V pixel for each 2x2 Y block. // YVU9 has a Y:V size ratio of 16 (4x4 --> 1). // The others have a ratio of 4 (2x2 --> 1). YVSizeRShift = (pTexInfo->Format != GMM_FORMAT_YVU9) ? 2 : 4; // If a Y plane isn't fully-aligned to its Y-->U/V block size, the // extra/unaligned Y pixels still need corresponding U/V pixels--So // for the purpose of computing the UVSize, we must consider a // dimensionally "rounded-up" YSize. (E.g. a 13x5 YVU9 Y plane would // require 4x2 U/V planes--the same UVSize as a fully-aligned 16x8 Y.) YSizeForUVPurposesDimensionalAlignment = (pTexInfo->Format != GMM_FORMAT_YVU9) ? 2 : 4; YSizeForUVPurposes = GFX_ALIGN(WidthBytesPhysical, YSizeForUVPurposesDimensionalAlignment) * GFX_ALIGN(YHeight, YSizeForUVPurposesDimensionalAlignment); UVSize = 2 * // <-- U + V (YSizeForUVPurposes >> YVSizeRShift); Height = GFX_CEIL_DIV(YSize + UVSize, WidthBytesPhysical); // Tiling not supported, since YPitch != UVPitch... pTexInfo->Flags.Info.TiledY = 0; pTexInfo->Flags.Info.TiledYf = 0; pTexInfo->Flags.Info.TiledYs = 0; pTexInfo->Flags.Info.TiledX = 0; pTexInfo->Flags.Info.Linear = 1; pTexInfo->OffsetInfo.Plane.NoOfPlanes = 1; break; } default: { GMM_ASSERTDPF(0, "Unexpected format"); return GMM_ERROR; } } // Align Height to even row to avoid hang if HW over-fetch Height = GFX_ALIGN(Height, __GMM_EVEN_ROW); SetTileMode(pTexInfo); // MMC is not supported for linear formats. if(pTexInfo->Flags.Gpu.MMC) { if(!(pTexInfo->Flags.Info.TiledY || pTexInfo->Flags.Info.TiledYf || pTexInfo->Flags.Info.TiledYs)) { pTexInfo->Flags.Gpu.MMC = 0; } } // Legacy Planar "Linear Video" Restrictions... if(pTexInfo->Flags.Info.Linear && !pTexInfo->Flags.Wa.NoLegacyPlanarLinearVideoRestrictions) { pRestrictions->LockPitchAlignment = GFX_MAX(pRestrictions->LockPitchAlignment, GMM_BYTES(64)); pRestrictions->MinPitch = GFX_MAX(pRestrictions->MinPitch, GMM_BYTES(64)); pRestrictions->PitchAlignment = GFX_MAX(pRestrictions->PitchAlignment, GMM_BYTES(64)); pRestrictions->RenderPitchAlignment = GFX_MAX(pRestrictions->RenderPitchAlignment, GMM_BYTES(64)); } // Multiply overall pitch alignment for surfaces whose U/V planes have a // pitch down-scaled from that of Y--Since the U/V pitches must meet the // original restriction, the Y pitch must meet a scaled-up multiple. if((pTexInfo->Format == GMM_FORMAT_I420) || (pTexInfo->Format == GMM_FORMAT_IYUV) || (pTexInfo->Format == GMM_FORMAT_NV11) || (pTexInfo->Format == GMM_FORMAT_YV12) || (pTexInfo->Format == GMM_FORMAT_YVU9)) { uint32_t LShift = (pTexInfo->Format != GMM_FORMAT_YVU9) ? 1 : // UVPitch = 1/2 YPitch 2; // UVPitch = 1/4 YPitch pRestrictions->LockPitchAlignment <<= LShift; pRestrictions->MinPitch <<= LShift; pRestrictions->PitchAlignment <<= LShift; pRestrictions->RenderPitchAlignment <<= LShift; } AdjustedVHeight = VHeight; // In case of Planar surfaces, only the last Plane has to be aligned to 64 for LCU access if(pGmmLibContext->GetWaTable().WaAlignYUVResourceToLCU && GmmIsYUVFormatLCUAligned(pTexInfo->Format) && VHeight > 0) { AdjustedVHeight = GFX_ALIGN(VHeight, GMM_SCANLINES(GMM_MAX_LCU_SIZE)); Height += AdjustedVHeight - VHeight; } // For Tiled Planar surfaces, the planes must be tile-boundary aligned. // Actual alignment is handled in FillPlanarOffsetAddress, but height // and width must be adjusted for correct size calculation if(GMM_IS_TILED(pPlatform->TileInfo[pTexInfo->TileMode])) { uint32_t TileHeight = pPlatform->TileInfo[pTexInfo->TileMode].LogicalTileHeight; uint32_t TileWidth = pPlatform->TileInfo[pTexInfo->TileMode].LogicalTileWidth; pTexInfo->OffsetInfo.Plane.IsTileAlignedPlanes = true; //for separate U and V planes, use U plane unaligned and V plane aligned Height = GFX_ALIGN(YHeight, TileHeight) + (UVPacked ? GFX_ALIGN(AdjustedVHeight, TileHeight) : (GFX_ALIGN(VHeight, TileHeight) + GFX_ALIGN(AdjustedVHeight, TileHeight))); if(pTexInfo->Format == GMM_FORMAT_IMC2 || // IMC2, IMC4 needs even tile columns pTexInfo->Format == GMM_FORMAT_IMC4) { // If the U & V planes are side-by-side then the surface pitch must be // padded out so that U and V planes will being on a tile boundary. // This means that an odd Y plane width must be padded out // with an additional tile. Even widths do not need padding uint32_t TileCols = GFX_CEIL_DIV(WidthBytesPhysical, TileWidth); if(TileCols % 2) { WidthBytesPhysical = (TileCols + 1) * TileWidth; } } if(pTexInfo->Flags.Info.TiledYs || pTexInfo->Flags.Info.TiledYf) { pTexInfo->Flags.Info.RedecribedPlanes = 1; } } // Vary wide planar tiled planar formats do not support MMC pre gen11. All formats do not support //Special case LKF MMC compressed surfaces if(pTexInfo->Flags.Gpu.MMC && pTexInfo->Flags.Gpu.UnifiedAuxSurface && pTexInfo->Flags.Info.TiledY) { uint32_t TileHeight = pGmmLibContext->GetPlatformInfo().TileInfo[pTexInfo->TileMode].LogicalTileHeight; Height = GFX_ALIGN(YHeight, TileHeight) + GFX_ALIGN(AdjustedVHeight, TileHeight); } // Vary wide planar tiled planar formats do not support MMC pre gen11. All formats do not support // Very wide planar tiled planar formats do not support MMC pre gen11. All formats do not support // MMC above 16k bytes wide, while Yf NV12 does not support above 8k - 128 bytes. if((GFX_GET_CURRENT_RENDERCORE(pPlatform->Platform) <= IGFX_GEN10_CORE) && (pTexInfo->Flags.Info.TiledY || pTexInfo->Flags.Info.TiledYf || pTexInfo->Flags.Info.TiledYs)) { if(((pTexInfo->BaseWidth * pTexInfo->BitsPerPixel / 8) >= GMM_KBYTE(16)) || (pTexInfo->Format == GMM_FORMAT_NV12 && pTexInfo->Flags.Info.TiledYf && (pTexInfo->BaseWidth * pTexInfo->BitsPerPixel / 8) >= (GMM_KBYTE(8) - 128))) { pTexInfo->Flags.Gpu.MMC = 0; } } if(pTexInfo->Flags.Info.RedecribedPlanes) { if(false == RedescribeTexturePlanes(pTexInfo, &WidthBytesPhysical)) { __GMM_ASSERT(false); } } if((Status = // <-- Note assignment. FillTexPitchAndSize( pTexInfo, WidthBytesPhysical, Height, pRestrictions)) == GMM_SUCCESS) { FillPlanarOffsetAddress(pTexInfo); } // Planar & hybrid 2D arrays supported in DX11.1+ spec but not HW. Memory layout // is defined by SW requirements; Y plane must be 4KB aligned. if(pTexInfo->ArraySize > 1) { GMM_GFX_SIZE_T ElementSizeBytes = pTexInfo->Size; int64_t LargeSize; // Size should always be page aligned. __GMM_ASSERT((pTexInfo->Size % PAGE_SIZE) == 0); if((LargeSize = (int64_t)ElementSizeBytes * pTexInfo->ArraySize) <= pPlatform->SurfaceMaxSize) { pTexInfo->OffsetInfo.Plane.ArrayQPitch = ElementSizeBytes; pTexInfo->Size = LargeSize; } else { GMM_ASSERTDPF(0, "Surface too large!"); Status = GMM_ERROR; } } //LKF specific Restrictions if(GFX_GET_CURRENT_PRODUCT(pPlatform->Platform) == IGFX_LAKEFIELD) { // If GMM fall backs TileY to Linear then reset the UnifiedAuxSurface flag. if(!pTexInfo->Flags.Gpu.MMC && pTexInfo->Flags.Gpu.UnifiedAuxSurface && !pTexInfo->Flags.Gpu.__NonMsaaLinearCCS) { GMM_ASSERTDPF(0, "MMC TileY is fallback to Linear surface!"); pTexInfo->Flags.Gpu.UnifiedAuxSurface = 0; } if(pTexInfo->Flags.Gpu.MMC && pTexInfo->Flags.Gpu.UnifiedAuxSurface && pTexInfo->Flags.Gpu.__NonMsaaLinearCCS) { FillLinearCCS(pTexInfo, pRestrictions); } } GMM_DPF_EXIT; return GMM_SUCCESS; } gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/Texture/GmmGen12Texture.cpp000066400000000000000000001575641466655022700251370ustar00rootroot00000000000000/*============================================================================== Copyright(c) 2019 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ============================================================================*/ #include "Internal/Common/GmmLibInc.h" #include "Internal/Common/Texture/GmmGen10TextureCalc.h" #include "Internal/Common/Texture/GmmGen11TextureCalc.h" #include "Internal/Common/Texture/GmmGen12TextureCalc.h" GMM_MIPTAIL_SLOT_OFFSET MipTailSlotOffset1DSurface[15][5] = GEN11_MIPTAIL_SLOT_OFFSET_1D_SURFACE; GMM_MIPTAIL_SLOT_OFFSET MipTailSlotOffset2DSurface[15][5] = GEN11_MIPTAIL_SLOT_OFFSET_2D_SURFACE; GMM_MIPTAIL_SLOT_OFFSET MipTailSlotOffset3DSurface[15][5] = GEN11_MIPTAIL_SLOT_OFFSET_3D_SURFACE; ///////////////////////////////////////////////////////////////////////////////////// /// Calculates height of the 2D mip layout on Gen9 /// /// @param[in] pTexInfo: ptr to ::GMM_TEXTURE_INFO, /// /// @return height of 2D mip layout ///////////////////////////////////////////////////////////////////////////////////// uint32_t GmmLib::GmmGen12TextureCalc::Get2DMipMapHeight(GMM_TEXTURE_INFO *pTexInfo) { uint32_t BlockHeight, MipHeight; uint32_t HeightLinesLevel0, HeightLinesLevel1, HeightLinesLevel2; uint32_t i, MipLevel, VAlign, CompressHeight, CompressWidth, CompressDepth; uint8_t Compressed; GMM_DPF_ENTER; const GMM_PLATFORM_INFO *pPlatform = GMM_OVERRIDE_PLATFORM_INFO(pTexInfo, pGmmLibContext); Compressed = GmmIsCompressed(pGmmLibContext, pTexInfo->Format); MipHeight = pTexInfo->BaseHeight; MipLevel = pTexInfo->MaxLod; VAlign = pTexInfo->Alignment.VAlign; GetCompressionBlockDimensions(pTexInfo->Format, &CompressWidth, &CompressHeight, &CompressDepth); HeightLinesLevel0 = __GMM_EXPAND_HEIGHT(this, MipHeight, VAlign, pTexInfo); if(Compressed) { HeightLinesLevel0 /= CompressHeight; } // Mip0 height... BlockHeight = HeightLinesLevel0; if((pTexInfo->Flags.Info.TiledYf || GMM_IS_64KB_TILE(pTexInfo->Flags)) && ((pTexInfo->Alignment.MipTailStartLod == 0) || (pTexInfo->MaxLod == 0))) { // Do nothing. Height is already aligned. } else { // Height of Mip1 and Mip2..n needed later... HeightLinesLevel1 = HeightLinesLevel2 = 0; for(i = 1; i <= MipLevel; i++) { uint32_t AlignedHeightLines; if((pTexInfo->Flags.Info.TiledYf || GMM_IS_64KB_TILE(pTexInfo->Flags)) && (i == pTexInfo->Alignment.MipTailStartLod)) { AlignedHeightLines = pPlatform->TileInfo[pTexInfo->TileMode].LogicalTileHeight; if(i == 1) { HeightLinesLevel1 = AlignedHeightLines; } else { HeightLinesLevel2 += AlignedHeightLines; } break; } else { MipHeight = GmmTexGetMipHeight(pTexInfo, i); AlignedHeightLines = __GMM_EXPAND_HEIGHT(this, MipHeight, VAlign, pTexInfo); if(Compressed) { AlignedHeightLines /= CompressHeight; } if(i == 1) { HeightLinesLevel1 = AlignedHeightLines; } else { HeightLinesLevel2 += AlignedHeightLines; } } } // If Mip1 height covers all others, then that is all we need... if(!(pTexInfo->Flags.Info.TiledYf || GMM_IS_64KB_TILE(pTexInfo->Flags))) { if(HeightLinesLevel1 >= HeightLinesLevel2) { BlockHeight += GFX_ALIGN(HeightLinesLevel1, VAlign); } else { BlockHeight += GFX_ALIGN(HeightLinesLevel2, VAlign); } } else { //TR mode- requires TileMode height alignment BlockHeight += (HeightLinesLevel1 >= HeightLinesLevel2) ? HeightLinesLevel1 : HeightLinesLevel2; BlockHeight = GFX_ALIGN(BlockHeight, pPlatform->TileInfo[pTexInfo->TileMode].LogicalTileHeight); } } GMM_DPF_EXIT; return (BlockHeight); } ///////////////////////////////////////////////////////////////////////////////////// /// Calculates Linear CCS size from main surface size /// /// @param[in] pSurf: ptr to ::GMM_TEXTURE_INFO of main surface /// @param[in] pAuxTexInfo: ptr to ::GMM_TEXTURE_INFO of Aux surface /// ///////////////////////////////////////////////////////////////////////////////////// GMM_STATUS GmmLib::GmmGen12TextureCalc::FillTexCCS(GMM_TEXTURE_INFO *pSurf, GMM_TEXTURE_INFO *pAuxTexInfo) { if(pGmmLibContext->GetSkuTable().FtrFlatPhysCCS && !pSurf->Flags.Gpu.ProceduralTexture) { //No CCS allocation for lossless compression (exclude AMFS CCS). return GMM_SUCCESS; } else if(pAuxTexInfo->Flags.Gpu.__NonMsaaLinearCCS) { GMM_TEXTURE_INFO Surf = *pSurf; uint32_t Depth; const GMM_PLATFORM_INFO *pPlatform = GMM_OVERRIDE_PLATFORM_INFO(pSurf, pGmmLibContext); pAuxTexInfo->Flags.Info.TiledW = 0; pAuxTexInfo->Flags.Info.TiledYf = 0; pAuxTexInfo->Flags.Info.TiledX = 0; pAuxTexInfo->Flags.Info.Linear = 1; GMM_SET_64KB_TILE(pAuxTexInfo->Flags, 0, pGmmLibContext); GMM_SET_4KB_TILE(pAuxTexInfo->Flags, 0, pGmmLibContext); pAuxTexInfo->ArraySize = Surf.ArraySize; pAuxTexInfo->Alignment = {0}; pAuxTexInfo->BitsPerPixel = 8; Depth = (Surf.Depth > 0) ? Surf.Depth : 1; // Depth = 0 needs to be handled gracefully uint32_t ExpandedArraySize = GFX_MAX(Surf.ArraySize, 1) * ((Surf.Type == RESOURCE_CUBE) ? 6 : 1) * // Cubemaps simply 6-element, 2D arrays. ((Surf.Type == RESOURCE_3D) ? Depth : 1) * // 3D's simply 2D arrays for sizing. ((Surf.Flags.Gpu.Depth || Surf.Flags.Gpu.SeparateStencil || GMM_IS_64KB_TILE(Surf.Flags) || Surf.Flags.Info.TiledYf) ? 1 : Surf.MSAA.NumSamples) * // MSAA (non-Depth/Stencil) RT samples stored as array planes. ((GMM_IS_64KB_TILE(Surf.Flags) && !pGmmLibContext->GetSkuTable().FtrTileY && !pGmmLibContext->GetSkuTable().FtrXe2PlusTiling && (Surf.MSAA.NumSamples == 16)) ? 4 : // MSAA x8/x16 stored as pseudo array planes each with 4x samples (GMM_IS_64KB_TILE(Surf.Flags) && !pGmmLibContext->GetSkuTable().FtrTileY && !pGmmLibContext->GetSkuTable().FtrXe2PlusTiling && (Surf.MSAA.NumSamples == 8)) ? 2 : 1); if(GMM_IS_64KB_TILE(Surf.Flags) || Surf.Flags.Info.TiledYf) { ExpandedArraySize = GFX_ALIGN(ExpandedArraySize, pPlatform->TileInfo[Surf.TileMode].LogicalTileDepth); } if(GmmIsUVPacked(Surf.Format)) { uint64_t YCcsSize = GFX_ALIGN((Surf.OffsetInfo.Plane.Y[GMM_PLANE_U] * Surf.Pitch), GMM_KBYTE(16)) >> 8; YCcsSize = GFX_ALIGN(YCcsSize, PAGE_SIZE); uint64_t PlanarSize = (Surf.ArraySize > 1) ? (Surf.OffsetInfo.Plane.ArrayQPitch) : Surf.Size; uint64_t UVCcsSize = GFX_ALIGN(PlanarSize - (Surf.OffsetInfo.Plane.Y[GMM_PLANE_U] * Surf.Pitch), GMM_KBYTE(16)) >> 8; if(UVCcsSize == 0) { //GMM_ASSERTDPF(UVCcsSize != 0, "Incorrect Planar Surface Size"); //Redescription of Yf/Ys planar surface P010 hits it (debug required?) UVCcsSize = 1; } UVCcsSize = GFX_ALIGN_NP2(UVCcsSize, PAGE_SIZE); pAuxTexInfo->OffsetInfo.Plane.X[GMM_PLANE_Y] = 0; pAuxTexInfo->OffsetInfo.Plane.Y[GMM_PLANE_Y] = 0; pAuxTexInfo->OffsetInfo.Plane.X[GMM_PLANE_U] = YCcsSize; //Being Linear CCS, fill X-offset - Test GetAuxOffset UV_CCS is proper pAuxTexInfo->OffsetInfo.Plane.Y[GMM_PLANE_U] = 0; pAuxTexInfo->OffsetInfo.Plane.X[GMM_PLANE_V] = YCcsSize; //Being Linear CCS, fill X-offset pAuxTexInfo->OffsetInfo.Plane.Y[GMM_PLANE_V] = 0; pAuxTexInfo->OffsetInfo.Plane.ArrayQPitch = YCcsSize + UVCcsSize; pAuxTexInfo->Size = pAuxTexInfo->OffsetInfo.Plane.ArrayQPitch * ((Surf.ArraySize > 1) ? (Surf.ArraySize) : 1); pAuxTexInfo->Alignment.QPitch = GFX_ULONG_CAST(pAuxTexInfo->Size) / ExpandedArraySize; } else if(GmmIsPlanar(Surf.Format)) { //Doesn't require separate Aux surfaces since not displayable. Page-alignment ensures //each hybrid plane is 4k-aligned, hence gets unique AuxT.L1e uint64_t PlanarSize = (Surf.ArraySize > 1) ? (Surf.OffsetInfo.Plane.ArrayQPitch) : Surf.Size; uint64_t CcsSize = GFX_ALIGN(PlanarSize, GMM_KBYTE(16)) >> 8; CcsSize = GFX_ALIGN(CcsSize, PAGE_SIZE); pAuxTexInfo->OffsetInfo.Plane.X[GMM_PLANE_Y] = 0; pAuxTexInfo->OffsetInfo.Plane.Y[GMM_PLANE_Y] = 0; pAuxTexInfo->OffsetInfo.Plane.X[GMM_PLANE_U] = GFX_ALIGN(Surf.OffsetInfo.Plane.Y[GMM_PLANE_U] * Surf.Pitch, GMM_KBYTE(16)) >> 8; //Being Linear CCS, fill X-offset - Test GetAuxOffset UV_CCS is proper pAuxTexInfo->OffsetInfo.Plane.Y[GMM_PLANE_U] = 0; pAuxTexInfo->OffsetInfo.Plane.X[GMM_PLANE_V] = GFX_ALIGN(Surf.OffsetInfo.Plane.Y[GMM_PLANE_V] * Surf.Pitch, GMM_KBYTE(16)) >> 8; //Being Linear CCS, fill X-offset pAuxTexInfo->OffsetInfo.Plane.Y[GMM_PLANE_V] = 0; pAuxTexInfo->OffsetInfo.Plane.ArrayQPitch = CcsSize; pAuxTexInfo->Size = pAuxTexInfo->OffsetInfo.Plane.ArrayQPitch * ((Surf.ArraySize > 1) ? (Surf.ArraySize) : 1); pAuxTexInfo->Alignment.QPitch = GFX_ULONG_CAST(pAuxTexInfo->Size) / ExpandedArraySize; } else { pAuxTexInfo->Size = (GFX_ALIGN(Surf.Size, GMM_KBYTE(16)) >> 8); uint32_t qPitch; if(ExpandedArraySize > 1) { uint64_t sliceSize = ((GFX_ALIGN(Surf.Pitch * Surf.Alignment.QPitch, GMM_KBYTE(16)) >> 8)); qPitch = GFX_ULONG_CAST(sliceSize); //HW doesn't use QPitch for Aux except MCS, how'd AMFS get sw-filled non-zero QPitch? if(Surf.MSAA.NumSamples && !pGmmLibContext->GetSkuTable().FtrTileY) { //MSAA Qpitch is sample-distance, multiply NumSamples in a tile qPitch *= (pGmmLibContext->GetSkuTable().FtrXe2PlusTiling ? Surf.MSAA.NumSamples : GFX_MIN(Surf.MSAA.NumSamples, 4)); } } else { qPitch = GFX_ULONG_CAST(pAuxTexInfo->Size); } pAuxTexInfo->Alignment.QPitch = qPitch; } __GMM_ASSERT(ExpandedArraySize || (pAuxTexInfo->Size == 0)); pAuxTexInfo->Pitch = 0; pAuxTexInfo->Type = RESOURCE_BUFFER; pAuxTexInfo->Alignment.BaseAlignment = GMM_KBYTE(4); //TODO: TiledResource? pAuxTexInfo->Size = GFX_ALIGN(pAuxTexInfo->Size, PAGE_SIZE); //page-align final size if(pAuxTexInfo->Flags.Gpu.TiledResource) { pAuxTexInfo->Alignment.BaseAlignment = GMM_KBYTE(64); //TODO: TiledResource? pAuxTexInfo->Size = GFX_ALIGN(pAuxTexInfo->Size, GMM_KBYTE(64)); //page-align final size } //Clear compression request in CCS pAuxTexInfo->Flags.Info.RenderCompressed = 0; pAuxTexInfo->Flags.Info.MediaCompressed = 0; pAuxTexInfo->Flags.Info.NotCompressed = 1; pAuxTexInfo->Flags.Info.RedecribedPlanes = 0; SetTileMode(pAuxTexInfo); return GMM_SUCCESS; } return GMM_SUCCESS; } ///////////////////////////////////////////////////////////////////////////////////// /// Allocates the 2D mip layout for surface state programming. /// /// @param[in] pTexInfo: ptr to ::GMM_TEXTURE_INFO, /// @param[in] pRestrictions: ptr to surface alignment and size restrictions /// /// @return ::GMM_STATUS ///////////////////////////////////////////////////////////////////////////////////// GMM_STATUS GMM_STDCALL GmmLib::GmmGen12TextureCalc::FillTex2D(GMM_TEXTURE_INFO * pTexInfo, __GMM_BUFFER_TYPE *pRestrictions) { uint32_t Width, Height, BitsPerPixel; uint32_t HAlign, VAlign, DAlign, CompressHeight, CompressWidth, CompressDepth; uint32_t AlignedWidth, BlockHeight, ExpandedArraySize, Pitch; uint8_t Compress = 0; GMM_STATUS Status; GMM_DPF_ENTER; __GMM_ASSERTPTR(pTexInfo, GMM_ERROR); __GMM_ASSERTPTR(pRestrictions, GMM_ERROR); const GMM_PLATFORM_INFO *pPlatform = GMM_OVERRIDE_PLATFORM_INFO(pTexInfo, pGmmLibContext); BitsPerPixel = pTexInfo->BitsPerPixel; //TODO: Deprecate TileY usage if((pTexInfo->Flags.Gpu.CCS && pTexInfo->Flags.Gpu.__NonMsaaTileYCcs)) { // Aux Surfaces are 8bpp. BitsPerPixel = 8; } Height = pTexInfo->BaseHeight; Width = GFX_ULONG_CAST(pTexInfo->BaseWidth); pTexInfo->MSAA.NumSamples = GFX_MAX(pTexInfo->MSAA.NumSamples, 1); if(pTexInfo->Flags.Info.TiledYf || GMM_IS_64KB_TILE(pTexInfo->Flags)) { FindMipTailStartLod(pTexInfo); } ExpandedArraySize = GFX_MAX(pTexInfo->ArraySize, 1) * ((pTexInfo->Type == RESOURCE_CUBE) ? 6 : 1) * // Cubemaps simply 6-element, 2D arrays. ((pTexInfo->Type == RESOURCE_3D) ? pTexInfo->Depth : 1) * // 3D's simply 2D arrays for sizing. ((pTexInfo->Flags.Gpu.Depth || pTexInfo->Flags.Gpu.SeparateStencil || (GMM_IS_64KB_TILE(pTexInfo->Flags) || pTexInfo->Flags.Info.TiledYf)) ? // MSAA Ys/Yf samples are ALSO stored as array planes, calculate size for single sample and expand it later. 1 : pTexInfo->MSAA.NumSamples) * // MSAA (non-Depth/Stencil) RT samples stored as array planes. ((pTexInfo->Flags.Gpu.Depth || pTexInfo->Flags.Gpu.SeparateStencil) ? // Depth/Stencil MSAA surface is expanded through Width and Depth 1 : ((GMM_IS_64KB_TILE(pTexInfo->Flags) && !pGmmLibContext->GetSkuTable().FtrTileY && !pGmmLibContext->GetSkuTable().FtrXe2PlusTiling && (pTexInfo->MSAA.NumSamples == 16)) ? 4 : // MSAA x8/x16 stored as pseudo array planes each with 4x samples (GMM_IS_64KB_TILE(pTexInfo->Flags) && !pGmmLibContext->GetSkuTable().FtrTileY && !pGmmLibContext->GetSkuTable().FtrXe2PlusTiling && (pTexInfo->MSAA.NumSamples == 8)) ? 2 : 1)); if(GMM_IS_64KB_TILE(pTexInfo->Flags) || pTexInfo->Flags.Info.TiledYf) { ExpandedArraySize = GFX_CEIL_DIV(ExpandedArraySize, pPlatform->TileInfo[pTexInfo->TileMode].LogicalTileDepth); } // // Check for color separation // if(pTexInfo->Flags.Gpu.ColorSeparation || pTexInfo->Flags.Gpu.ColorSeparationRGBX) { bool csRestrictionsMet = (((ExpandedArraySize <= 2) && (ExpandedArraySize == pTexInfo->ArraySize) && ((pTexInfo->Format == GMM_FORMAT_R8G8B8A8_UNORM) || (pTexInfo->Format == GMM_FORMAT_R8G8B8A8_UNORM_SRGB) || (pTexInfo->Format == GMM_FORMAT_B8G8R8A8_UNORM) || (pTexInfo->Format == GMM_FORMAT_B8G8R8A8_UNORM_SRGB) || (pTexInfo->Format == GMM_FORMAT_B8G8R8X8_UNORM) || (pTexInfo->Format == GMM_FORMAT_B8G8R8X8_UNORM_SRGB)) && ((pTexInfo->Flags.Gpu.ColorSeparation && (Width % 16) == 0) || (pTexInfo->Flags.Gpu.ColorSeparationRGBX && (Width % 12) == 0)))); if(csRestrictionsMet) { ExpandedArraySize = GMM_COLOR_SEPARATION_ARRAY_SIZE; } else { pTexInfo->Flags.Gpu.ColorSeparation = 0; pTexInfo->Flags.Gpu.ColorSeparationRGBX = 0; } } HAlign = pTexInfo->Alignment.HAlign; VAlign = pTexInfo->Alignment.VAlign; DAlign = pTexInfo->Alignment.DAlign; GetCompressionBlockDimensions(pTexInfo->Format, &CompressWidth, &CompressHeight, &CompressDepth); Compress = GmmIsCompressed(pGmmLibContext, pTexInfo->Format); ///////////////////////////////// // Calculate Block Surface Height ///////////////////////////////// if(ExpandedArraySize > 1) { uint32_t Alignment = VAlign; if((pTexInfo->Type == RESOURCE_3D && !pTexInfo->Flags.Info.Linear) || (pTexInfo->Flags.Gpu.S3dDx && pGmmLibContext->GetSkuTable().FtrDisplayEngineS3d) || (pTexInfo->Flags.Wa.MediaPipeUsage)) { Alignment = pPlatform->TileInfo[pTexInfo->TileMode].LogicalTileHeight; } // Calculate the overall Block height...Mip0Height + Max(Mip1Height, Sum of Mip2Height..MipnHeight) BlockHeight = Get2DMipMapTotalHeight(pTexInfo); BlockHeight = GFX_ALIGN_NP2(BlockHeight, Alignment); // GMM internally uses QPitch as the logical distance between slices, but translates // as appropriate to service client queries in GmmResGetQPitch. pTexInfo->Alignment.QPitch = BlockHeight; if(Compress) { BlockHeight = GFX_CEIL_DIV(BlockHeight, CompressHeight); BlockHeight = GetAligned3DBlockHeight(pTexInfo, BlockHeight, ExpandedArraySize); } else { BlockHeight = ScaleTextureHeight(pTexInfo, BlockHeight); } BlockHeight *= ExpandedArraySize; } else { pTexInfo->Alignment.QPitch = 0; BlockHeight = Get2DMipMapHeight(pTexInfo); BlockHeight = ScaleTextureHeight(pTexInfo, BlockHeight); } /////////////////////////////////// // Calculate Pitch /////////////////////////////////// AlignedWidth = __GMM_EXPAND_WIDTH(this, Width, HAlign, pTexInfo); // Calculate special pitch case of small dimensions where LOD1 + LOD2 widths // are greater than LOD0. e.g. dimensions 4x4 and MinPitch == 1 if((pTexInfo->Flags.Info.TiledYf || GMM_IS_64KB_TILE(pTexInfo->Flags)) && (pTexInfo->Alignment.MipTailStartLod < 2)) { // Do nothing -- all mips are in LOD0/LOD1, which is already width aligned. } else if(pTexInfo->MaxLod >= 2) { uint32_t AlignedWidthLod1, AlignedWidthLod2; AlignedWidthLod1 = __GMM_EXPAND_WIDTH(this, Width >> 1, HAlign, pTexInfo); AlignedWidthLod2 = __GMM_EXPAND_WIDTH(this, Width >> 2, HAlign, pTexInfo); AlignedWidth = GFX_MAX(AlignedWidth, AlignedWidthLod1 + AlignedWidthLod2); } if(Compress) { AlignedWidth = GFX_CEIL_DIV(AlignedWidth, CompressWidth); } else { AlignedWidth = ScaleTextureWidth(pTexInfo, AlignedWidth); } // Default pitch Pitch = AlignedWidth * BitsPerPixel >> 3; // Make sure the pitch satisfy linear min pitch requirment Pitch = GFX_MAX(Pitch, pRestrictions->MinPitch); // Make sure pitch satisfy alignment restriction Pitch = GFX_ALIGN(Pitch, pRestrictions->PitchAlignment); //////////////////// // Adjust for Tiling //////////////////// if(GMM_IS_TILED(pPlatform->TileInfo[pTexInfo->TileMode])) { Pitch = GFX_ALIGN(Pitch, pPlatform->TileInfo[pTexInfo->TileMode].LogicalTileWidth); BlockHeight = GFX_ALIGN(BlockHeight, pPlatform->TileInfo[pTexInfo->TileMode].LogicalTileHeight); } GMM_ASSERTDPF(pTexInfo->Flags.Info.LayoutBelow || !pTexInfo->Flags.Info.LayoutRight, "MIPLAYOUT_RIGHT not supported after Gen6!"); pTexInfo->Flags.Info.LayoutBelow = 1; pTexInfo->Flags.Info.LayoutRight = 0; // If a texture is YUV packed, 96, or 48 bpp then one row plus 16 bytes of // padding needs to be added. Since this will create a none pitch aligned // surface the padding is aligned to the next row if(GmmIsYUVPacked(pTexInfo->Format) || (pTexInfo->BitsPerPixel == GMM_BITS(96)) || (pTexInfo->BitsPerPixel == GMM_BITS(48))) { BlockHeight += GMM_SCANLINES(1) + GFX_CEIL_DIV(GMM_BYTES(16), Pitch); } // For Non-planar surfaces, the alignment is done on the entire height of the allocation if(pGmmLibContext->GetWaTable().WaAlignYUVResourceToLCU && GmmIsYUVFormatLCUAligned(pTexInfo->Format) && !GmmIsPlanar(pTexInfo->Format)) { BlockHeight = GFX_ALIGN(BlockHeight, GMM_SCANLINES(GMM_MAX_LCU_SIZE)); } // Align height to even row to avoid hang if HW over-fetch BlockHeight = GFX_ALIGN(BlockHeight, __GMM_EVEN_ROW); if((Status = // <-- Note assignment. FillTexPitchAndSize( pTexInfo, Pitch, BlockHeight, pRestrictions)) == GMM_SUCCESS) { Fill2DTexOffsetAddress(pTexInfo); } GMM_DPF_EXIT; return (Status); } ///////////////////////////////////////////////////////////////////////////////////// /// This function will Setup a planar surface allocation. /// /// @param[in] pTexInfo: Reference to ::GMM_TEXTURE_INFO /// @param[in] pRestrictions: Reference to surface alignment and size restrictions. /// /// @return ::GMM_STATUS ///////////////////////////////////////////////////////////////////////////////////// GMM_STATUS GMM_STDCALL GmmLib::GmmGen12TextureCalc::FillTexPlanar(GMM_TEXTURE_INFO * pTexInfo, __GMM_BUFFER_TYPE *pRestrictions) { uint32_t WidthBytesPhysical, Height, YHeight, VHeight; uint32_t AdjustedVHeight = 0; GMM_STATUS Status; bool UVPacked = false; uint32_t BitsPerPixel, AlignedWidth; GMM_DPF_ENTER; __GMM_ASSERTPTR(pTexInfo, GMM_ERROR); __GMM_ASSERTPTR(pRestrictions, GMM_ERROR); __GMM_ASSERT(!pTexInfo->Flags.Info.TiledW); const GMM_PLATFORM_INFO *pPlatform = GMM_OVERRIDE_PLATFORM_INFO(pTexInfo, pGmmLibContext); BitsPerPixel = pTexInfo->BitsPerPixel; AlignedWidth = GFX_ULONG_CAST(pTexInfo->BaseWidth); if(!pTexInfo->Flags.Gpu.__NonMsaaTileYCcs) { pTexInfo->TileMode = TILE_NONE; } else { pTexInfo->TileMode = LEGACY_TILE_Y; } WidthBytesPhysical = AlignedWidth * BitsPerPixel >> 3; Height = VHeight = 0; YHeight = pTexInfo->BaseHeight; switch(pTexInfo->Format) { case GMM_FORMAT_IMC1: // IMC1 = IMC3 with Swapped U/V case GMM_FORMAT_IMC3: case GMM_FORMAT_MFX_JPEG_YUV420: // Same as IMC3. // YYYYYYYY // YYYYYYYY // YYYYYYYY // YYYYYYYY // UUUU // UUUU // VVVV // VVVV case GMM_FORMAT_MFX_JPEG_YUV422V: // Similar to IMC3 but U/V are full width. // YYYYYYYY // YYYYYYYY // YYYYYYYY // YYYYYYYY // UUUUUUUU // UUUUUUUU // VVVVVVVV // VVVVVVVV { VHeight = GFX_ALIGN(GFX_CEIL_DIV(YHeight, 2), GMM_IMCx_PLANE_ROW_ALIGNMENT); YHeight = GFX_ALIGN(YHeight, GMM_IMCx_PLANE_ROW_ALIGNMENT); Height = YHeight + 2 * VHeight; // One VHeight for V and one for U. pTexInfo->OffsetInfo.Plane.NoOfPlanes = 3; break; } case GMM_FORMAT_MFX_JPEG_YUV411R_TYPE: //Similar to IMC3 but U/V are quarther height and full width. //YYYYYYYY //YYYYYYYY //YYYYYYYY //YYYYYYYY //UUUUUUUU //VVVVVVVV { VHeight = GFX_ALIGN(GFX_CEIL_DIV(YHeight, 4), GMM_IMCx_PLANE_ROW_ALIGNMENT); YHeight = GFX_ALIGN(YHeight, GMM_IMCx_PLANE_ROW_ALIGNMENT); Height = YHeight + 2 * VHeight; pTexInfo->OffsetInfo.Plane.NoOfPlanes = 3; break; } case GMM_FORMAT_MFX_JPEG_YUV411: // Similar to IMC3 but U/V are quarter width and full height. // YYYYYYYY // YYYYYYYY // YYYYYYYY // YYYYYYYY // UU // UU // UU // UU // VV // VV // VV // VV case GMM_FORMAT_MFX_JPEG_YUV422H: // Similar to IMC3 but U/V are full height. // YYYYYYYY // YYYYYYYY // YYYYYYYY // YYYYYYYY // UUUU // UUUU // UUUU // UUUU // VVVV // VVVV // VVVV // VVVV case GMM_FORMAT_MFX_JPEG_YUV444: // Similar to IMC3 but U/V are full size. #if _WIN32 case GMM_FORMAT_WGBOX_YUV444: case GMM_FORMAT_WGBOX_PLANAR_YUV444: #endif // YYYYYYYY // YYYYYYYY // YYYYYYYY // YYYYYYYY // UUUUUUUU // UUUUUUUU // UUUUUUUU // UUUUUUUU // VVVVVVVV // VVVVVVVV // VVVVVVVV // VVVVVVVV { YHeight = GFX_ALIGN(YHeight, GMM_IMCx_PLANE_ROW_ALIGNMENT); VHeight = YHeight; Height = YHeight + 2 * VHeight; pTexInfo->OffsetInfo.Plane.NoOfPlanes = 3; break; } case GMM_FORMAT_BGRP: case GMM_FORMAT_RGBP: { //For RGBP linear Tile keep resource Offset non aligned and for other Tile format to be 16-bit aligned if(pTexInfo->Flags.Info.Linear) { VHeight = YHeight; Height = YHeight + 2 * VHeight; pTexInfo->OffsetInfo.Plane.NoOfPlanes = 3; } else { YHeight = GFX_ALIGN(YHeight, GMM_IMCx_PLANE_ROW_ALIGNMENT); VHeight = YHeight; Height = YHeight + 2 * VHeight; pTexInfo->OffsetInfo.Plane.NoOfPlanes = 3; } break; } case GMM_FORMAT_IMC2: // IMC2 = IMC4 with Swapped U/V case GMM_FORMAT_IMC4: { // YYYYYYYY // YYYYYYYY // YYYYYYYY // YYYYYYYY // UUUUVVVV // UUUUVVVV YHeight = GFX_ALIGN(YHeight, GMM_IMCx_PLANE_ROW_ALIGNMENT); VHeight = GFX_CEIL_DIV(YHeight, 2); WidthBytesPhysical = GFX_ALIGN(WidthBytesPhysical, 2); // If odd YWidth, pitch bumps-up to fit rounded-up U/V planes. Height = YHeight + VHeight; // With SURFACE_STATE.XOffset support, the U-V interface has // much lighter restrictions--which will be naturally met by // surface pitch restrictions (i.e. dividing an IMC2/4 pitch // by 2--to get the U/V interface--will always produce a safe // XOffset value). // Not technically UV packed but sizing works out the same // if the resource is std swizzled UVPacked = true; pTexInfo->OffsetInfo.Plane.NoOfPlanes = 2; break; } case GMM_FORMAT_NV12: case GMM_FORMAT_NV21: case GMM_FORMAT_NV11: case GMM_FORMAT_P010: case GMM_FORMAT_P012: case GMM_FORMAT_P016: case GMM_FORMAT_P208: case GMM_FORMAT_P216: { // YYYYYYYY // YYYYYYYY // YYYYYYYY // YYYYYYYY // [UV-Packing] if((pTexInfo->Format == GMM_FORMAT_NV12) || (pTexInfo->Format == GMM_FORMAT_NV21) || (pTexInfo->Format == GMM_FORMAT_P010) || (pTexInfo->Format == GMM_FORMAT_P012) || (pTexInfo->Format == GMM_FORMAT_P016)) { VHeight = GFX_CEIL_DIV(YHeight, 2); // U/V plane half of Y Height = YHeight + VHeight; } else { VHeight = YHeight; // U/V plane is same as Y Height = YHeight + VHeight; } if((pTexInfo->Format == GMM_FORMAT_NV12) || (pTexInfo->Format == GMM_FORMAT_NV21) || (pTexInfo->Format == GMM_FORMAT_P010) || (pTexInfo->Format == GMM_FORMAT_P012) || (pTexInfo->Format == GMM_FORMAT_P016) || (pTexInfo->Format == GMM_FORMAT_P208) || (pTexInfo->Format == GMM_FORMAT_P216)) { WidthBytesPhysical = GFX_ALIGN(WidthBytesPhysical, 2); // If odd YWidth, pitch bumps-up to fit rounded-up U/V planes. pTexInfo->OffsetInfo.Plane.NoOfPlanes = 2; } else //if(pTexInfo->Format == GMM_FORMAT_NV11) { // Tiling not supported, since YPitch != UVPitch... pTexInfo->Flags.Info.TiledYf = 0; pTexInfo->Flags.Info.TiledX = 0; pTexInfo->Flags.Info.Linear = 1; GMM_SET_64KB_TILE(pTexInfo->Flags, 0, pGmmLibContext); GMM_SET_4KB_TILE(pTexInfo->Flags, 0, pGmmLibContext); } UVPacked = true; break; } case GMM_FORMAT_I420: // IYUV & I420: are identical to YV12 except, case GMM_FORMAT_IYUV: // U & V pl.s are reversed. case GMM_FORMAT_YV12: case GMM_FORMAT_YVU9: { // YYYYYYYY // YYYYYYYY // YYYYYYYY // YYYYYYYY // VVVVVV.. <-- V and U planes follow the Y plane, as linear // ..UUUUUU arrays--without respect to pitch. uint32_t YSize, UVSize, YVSizeRShift; uint32_t YSizeForUVPurposes, YSizeForUVPurposesDimensionalAlignment; YSize = WidthBytesPhysical * YHeight; // YVU9 has one U/V pixel for each 4x4 Y block. // The others have one U/V pixel for each 2x2 Y block. // YVU9 has a Y:V size ratio of 16 (4x4 --> 1). // The others have a ratio of 4 (2x2 --> 1). YVSizeRShift = (pTexInfo->Format != GMM_FORMAT_YVU9) ? 2 : 4; // If a Y plane isn't fully-aligned to its Y-->U/V block size, the // extra/unaligned Y pixels still need corresponding U/V pixels--So // for the purpose of computing the UVSize, we must consider a // dimensionally "rounded-up" YSize. (E.g. a 13x5 YVU9 Y plane would // require 4x2 U/V planes--the same UVSize as a fully-aligned 16x8 Y.) YSizeForUVPurposesDimensionalAlignment = (pTexInfo->Format != GMM_FORMAT_YVU9) ? 2 : 4; YSizeForUVPurposes = GFX_ALIGN(WidthBytesPhysical, YSizeForUVPurposesDimensionalAlignment) * GFX_ALIGN(YHeight, YSizeForUVPurposesDimensionalAlignment); UVSize = 2 * // <-- U + V (YSizeForUVPurposes >> YVSizeRShift); Height = GFX_CEIL_DIV(YSize + UVSize, WidthBytesPhysical); // Tiling not supported, since YPitch != UVPitch... pTexInfo->Flags.Info.TiledYf = 0; pTexInfo->Flags.Info.TiledX = 0; pTexInfo->Flags.Info.Linear = 1; pTexInfo->OffsetInfo.Plane.NoOfPlanes = 1; GMM_SET_64KB_TILE(pTexInfo->Flags, 0, pGmmLibContext); GMM_SET_4KB_TILE(pTexInfo->Flags, 0, pGmmLibContext); break; } default: { GMM_ASSERTDPF(0, "Unexpected format"); return GMM_ERROR; } } // Align Height to even row to avoid hang if HW over-fetch Height = GFX_ALIGN(Height, __GMM_EVEN_ROW); SetTileMode(pTexInfo); // If the Surface has Odd height dimension, we will fall back to Linear Format. // If MMC is enabled, disable MMC during such cases. if(pTexInfo->Flags.Gpu.MMC) { if(!(GMM_IS_4KB_TILE(pTexInfo->Flags) || GMM_IS_64KB_TILE(pTexInfo->Flags))) { pTexInfo->Flags.Gpu.MMC = 0; } } // If the Surface has Odd height dimension, we will fall back to Linear Format. // If MMC is enabled, disable .CCS/UnifiedAuxSurface during such cases. if(pTexInfo->Flags.Gpu.CCS) { if(!(GMM_IS_4KB_TILE(pTexInfo->Flags) || GMM_IS_64KB_TILE(pTexInfo->Flags)) && !(pTexInfo->Flags.Gpu.__NonMsaaTileYCcs && GMM_IS_4KB_TILE(pTexInfo->Flags))) { pTexInfo->Flags.Gpu.MMC = 0; pTexInfo->Flags.Gpu.CCS = 0; pTexInfo->Flags.Gpu.UnifiedAuxSurface = 0; pTexInfo->Flags.Gpu.__NonMsaaTileYCcs = 0; } } // Legacy Planar "Linear Video" Restrictions... if(pTexInfo->Flags.Info.Linear && !pTexInfo->Flags.Wa.NoLegacyPlanarLinearVideoRestrictions) { pRestrictions->LockPitchAlignment = GFX_MAX(pRestrictions->LockPitchAlignment, GMM_BYTES(64)); pRestrictions->MinPitch = GFX_MAX(pRestrictions->MinPitch, GMM_BYTES(64)); pRestrictions->PitchAlignment = GFX_MAX(pRestrictions->PitchAlignment, GMM_BYTES(64)); pRestrictions->RenderPitchAlignment = GFX_MAX(pRestrictions->RenderPitchAlignment, GMM_BYTES(64)); } // Multiply overall pitch alignment for surfaces whose U/V planes have a // pitch down-scaled from that of Y--Since the U/V pitches must meet the // original restriction, the Y pitch must meet a scaled-up multiple. if((pTexInfo->Format == GMM_FORMAT_I420) || (pTexInfo->Format == GMM_FORMAT_IYUV) || (pTexInfo->Format == GMM_FORMAT_NV11) || (pTexInfo->Format == GMM_FORMAT_YV12) || (pTexInfo->Format == GMM_FORMAT_YVU9)) { uint32_t LShift = (pTexInfo->Format != GMM_FORMAT_YVU9) ? 1 : // UVPitch = 1/2 YPitch 2; // UVPitch = 1/4 YPitch pRestrictions->LockPitchAlignment <<= LShift; pRestrictions->MinPitch <<= LShift; pRestrictions->PitchAlignment <<= LShift; pRestrictions->RenderPitchAlignment <<= LShift; } AdjustedVHeight = VHeight; FindMipTailStartLod(pTexInfo); // In case of Planar surfaces, only the last Plane has to be aligned to 64 for LCU access if(pGmmLibContext->GetWaTable().WaAlignYUVResourceToLCU && GmmIsYUVFormatLCUAligned(pTexInfo->Format) && VHeight > 0) { AdjustedVHeight = GFX_ALIGN(VHeight, GMM_SCANLINES(GMM_MAX_LCU_SIZE)); Height += AdjustedVHeight - VHeight; } // For std swizzled and UV packed tile Ys/Yf cases, the planes // must be tile-boundary aligned. Actual alignment is handled // in FillPlanarOffsetAddress, but height and width must // be adjusted for correct size calculation if(GMM_IS_TILED(pPlatform->TileInfo[pTexInfo->TileMode]) && !pTexInfo->Flags.Gpu.__NonMsaaTileYCcs) { uint32_t TileHeight = pGmmLibContext->GetPlatformInfo().TileInfo[pTexInfo->TileMode].LogicalTileHeight; uint32_t TileWidth = pGmmLibContext->GetPlatformInfo().TileInfo[pTexInfo->TileMode].LogicalTileWidth; pTexInfo->OffsetInfo.Plane.IsTileAlignedPlanes = true; if(pTexInfo->Flags.Gpu.CCS && !pGmmLibContext->GetSkuTable().FtrFlatPhysCCS) // alignment adjustment needed only for aux tables { if(GMM_IS_64KB_TILE(pTexInfo->Flags)) { TileHeight *= (!WA64K(pGmmLibContext) && !WA16K(pGmmLibContext)) ? 16 : 1; // For 64Kb Tile mode: Multiply TileHeight by 16 for 1 MB alignment } else { TileHeight *= (WA16K(pGmmLibContext) ? 1 : WA64K(pGmmLibContext) ? 4 : 64); // For 4k Tile: Multiply TileHeight by 4 and Pitch by 4 for 64kb alignment, multiply TileHeight by 64 and Pitch by 4 for 1 MB alignment } } if(pTexInfo->Format == GMM_FORMAT_IMC2 || // IMC2, IMC4 needs even tile columns pTexInfo->Format == GMM_FORMAT_IMC4) { // If the U & V planes are side-by-side then the surface pitch must be // padded out so that U and V planes will being on a tile boundary. // This means that an odd Y plane width must be padded out // with an additional tile. Even widths do not need padding uint32_t TileCols = GFX_CEIL_DIV(WidthBytesPhysical, TileWidth); if(TileCols % 2) { WidthBytesPhysical = (TileCols + 1) * TileWidth; } } Height = GFX_ALIGN(YHeight, TileHeight) + (UVPacked ? GFX_ALIGN(AdjustedVHeight, TileHeight) : (GFX_ALIGN(VHeight, TileHeight) + GFX_ALIGN(AdjustedVHeight, TileHeight))); if(GMM_IS_64KB_TILE(pTexInfo->Flags) || pTexInfo->Flags.Info.TiledYf) { pTexInfo->Flags.Info.RedecribedPlanes = true; } } else if(pTexInfo->Flags.Gpu.__NonMsaaTileYCcs) { uint32_t TileHeight = pGmmLibContext->GetPlatformInfo().TileInfo[pTexInfo->TileMode].LogicalTileHeight; BitsPerPixel = 8; if(pTexInfo->Format == GMM_FORMAT_IMC2 || // IMC2, IMC4 needs even tile columns pTexInfo->Format == GMM_FORMAT_IMC4) { // If the U & V planes are side-by-side then the surface pitch must be // padded out so that U and V planes will being on a tile boundary. // This means that an odd Y plane width must be padded out // with an additional tile. Even widths do not need padding // CCS must use padded main surface width, so get main surface TileWidth #define CCSMODE_TO_TILEMODE(y) ((y + TILE_YF_2D_8bpe) < TILE_YS_1D_8bpe) ? (y + TILE_YF_2D_8bpe) : \ ((y + TILE_YF_2D_8bpe + 5) >= TILE_YS_1D_128bpe) ? (y + TILE_YF_2D_8bpe + 5) : TILE_NONE uint32_t BaseTileWidth = pPlatform->TileInfo[CCSMODE_TO_TILEMODE(pTexInfo->CCSModeAlign)].LogicalTileWidth; WidthBytesPhysical = GFX_ALIGN(WidthBytesPhysical, 2 * BaseTileWidth); } AlignedWidth = GFX_ULONG_CAST(WidthBytesPhysical / (pTexInfo->BitsPerPixel >> 3)); WidthBytesPhysical = __GMM_EXPAND_WIDTH(this, AlignedWidth, pTexInfo->Alignment.HAlign, pTexInfo); WidthBytesPhysical = ScaleTextureWidth(pTexInfo, WidthBytesPhysical); //Should both YAux and UVAux use same CCModeALign (ie using common bpe?) //If different, then copy Aux info from per-plane Aux? HW has separate bpe or common? YHeight = __GMM_EXPAND_HEIGHT(this, YHeight, pTexInfo->Alignment.VAlign, pTexInfo); YHeight = ScaleTextureHeight(pTexInfo, YHeight); YHeight = GFX_ALIGN(YHeight, TileHeight); VHeight = __GMM_EXPAND_HEIGHT(this, VHeight, pTexInfo->Alignment.VAlign, pTexInfo); VHeight = ScaleTextureHeight(pTexInfo, VHeight); VHeight = GFX_ALIGN(VHeight, TileHeight); Height = YHeight + VHeight; } if(pTexInfo->Flags.Info.RedecribedPlanes) { if(false == RedescribeTexturePlanes(pTexInfo, &WidthBytesPhysical)) { __GMM_ASSERT(false); } } if((Status = // <-- Note assignment. FillTexPitchAndSize( pTexInfo, WidthBytesPhysical, Height, pRestrictions)) == GMM_SUCCESS) { FillPlanarOffsetAddress(pTexInfo); } // Planar & hybrid 2D arrays supported in DX11.1+ spec but not HW. Memory layout // is defined by SW requirements; Y plane must be 4KB aligned. if(pTexInfo->ArraySize > 1) { GMM_GFX_SIZE_T ElementSizeBytes = pTexInfo->Size; int64_t LargeSize; // Size should always be page aligned. __GMM_ASSERT((pTexInfo->Size % PAGE_SIZE) == 0); if((LargeSize = (int64_t)ElementSizeBytes * pTexInfo->ArraySize) <= pPlatform->SurfaceMaxSize) { pTexInfo->OffsetInfo.Plane.ArrayQPitch = ElementSizeBytes; pTexInfo->Size = LargeSize; } else { GMM_ASSERTDPF(0, "Surface too large!"); Status = GMM_ERROR; } } GMM_DPF_EXIT; return (Status); } // FillTexPlanar GMM_STATUS GMM_STDCALL GmmLib::GmmGen12TextureCalc::GetCCSScaleFactor(GMM_TEXTURE_INFO *pTexInfo, CCS_UNIT & ScaleFactor) { GMM_STATUS Status = GMM_SUCCESS; GMM_TEXTURE_ALIGN_EX TexAlignEx = static_cast(pGmmLibContext->GetPlatformInfoObj())->GetExTextureAlign(); uint32_t CCSModeIdx = 0; if(pTexInfo->Flags.Info.TiledYf || GMM_IS_64KB_TILE(pTexInfo->Flags)) //pTexInfo is RT Surf { CCSModeIdx = CCS_MODE(pTexInfo->TileMode); __GMM_ASSERT(pTexInfo->TileMode < GMM_TILE_MODES); } else //pTexInfo is CCS Surf { CCSModeIdx = pTexInfo->CCSModeAlign; } if(!(CCSModeIdx < CCS_MODES)) { __GMM_ASSERT(0); //indicates something wrong w/ H/V/D Align Filling function or Wrong TileMode set return GMM_ERROR; } ScaleFactor = TexAlignEx.CCSEx[CCSModeIdx]; return (Status); } GMM_STATUS GMM_STDCALL GmmLib::GmmGen12TextureCalc::GetCCSExMode(GMM_TEXTURE_INFO *AuxSurf) { if(GMM_IS_4KB_TILE(AuxSurf->Flags) || GMM_IS_64KB_TILE(AuxSurf->Flags) || AuxSurf->Flags.Info.Linear) { if(pGmmLibContext->GetSkuTable().FtrLinearCCS) { AuxSurf->Flags.Gpu.__NonMsaaLinearCCS = 1; } else { AuxSurf->Flags.Gpu.__NonMsaaTileYCcs = 1; //CCS is always 2D, even for 3D surface if(AuxSurf->Type == RESOURCE_CUBE) { AuxSurf->ArraySize = 6; } AuxSurf->Type = RESOURCE_2D; } if(AuxSurf->Flags.Gpu.__NonMsaaTileYCcs) { AuxSurf->CCSModeAlign = 0; SetTileMode(AuxSurf); /*if (AuxSurf->Flags.Gpu.UnifiedAuxSurface)*/ { AuxSurf->CCSModeAlign = CCS_MODE(AuxSurf->TileMode); } AuxSurf->TileMode = TILE_NONE; __GMM_ASSERT(AuxSurf->CCSModeAlign < CCS_MODES); return (AuxSurf->CCSModeAlign < CCS_MODES) ? GMM_SUCCESS : GMM_INVALIDPARAM; } } return GMM_SUCCESS; } uint32_t GMM_STDCALL GmmLib::GmmGen12TextureCalc::ScaleTextureHeight(GMM_TEXTURE_INFO *pTexInfo, uint32_t Height) { uint32_t ScaledHeight = Height; if(pTexInfo->Flags.Gpu.CCS && pTexInfo->Flags.Gpu.__NonMsaaTileYCcs) { CCS_UNIT ScaleFactor; GetCCSScaleFactor(pTexInfo, ScaleFactor); ScaledHeight /= ScaleFactor.Downscale.Height; } return ScaledHeight; } uint32_t GMM_STDCALL GmmLib::GmmGen12TextureCalc::ScaleTextureWidth(GMM_TEXTURE_INFO *pTexInfo, uint32_t Width) { uint32_t ScaledWidth = Width; if(pTexInfo->Flags.Gpu.CCS && pTexInfo->Flags.Gpu.__NonMsaaTileYCcs) { CCS_UNIT ScaleFactor; GetCCSScaleFactor(pTexInfo, ScaleFactor); if(ScaleFactor.Downscale.Width < 0) { ScaledWidth *= ((-1) * ScaleFactor.Downscale.Width); } else { ScaledWidth /= ScaleFactor.Downscale.Width; } } else if(pTexInfo->Flags.Gpu.ColorSeparation) { ScaledWidth *= pTexInfo->ArraySize; __GMM_ASSERT(0 == (ScaledWidth % GMM_COLOR_SEPARATION_WIDTH_DIVISION)); ScaledWidth /= GMM_COLOR_SEPARATION_WIDTH_DIVISION; } else if(pTexInfo->Flags.Gpu.ColorSeparationRGBX) { ScaledWidth *= pTexInfo->ArraySize; __GMM_ASSERT(0 == (ScaledWidth % GMM_COLOR_SEPARATION_RGBX_WIDTH_DIVISION)); ScaledWidth /= GMM_COLOR_SEPARATION_RGBX_WIDTH_DIVISION; } return ScaledWidth; } uint32_t GMM_STDCALL GmmLib::GmmGen12TextureCalc::ScaleFCRectHeight(GMM_TEXTURE_INFO *pTexInfo, uint32_t Height) { uint32_t ScaledHeight = Height; if(pTexInfo->Flags.Gpu.CCS) { CCS_UNIT *FCRectAlign = static_cast(pGmmLibContext->GetPlatformInfoObj())->GetFCRectAlign(); uint8_t index = FCMaxModes; if((index = FCMode(pTexInfo->TileMode, pTexInfo->BitsPerPixel)) < FCMaxModes) { ScaledHeight = GFX_ALIGN(ScaledHeight, FCRectAlign[index].Align.Height); ScaledHeight /= FCRectAlign[index].Downscale.Height; } else { __GMM_ASSERT(0); } } return ScaledHeight; } uint64_t GMM_STDCALL GmmLib::GmmGen12TextureCalc::ScaleFCRectWidth(GMM_TEXTURE_INFO *pTexInfo, uint64_t Width) { uint64_t ScaledWidth = Width; if(pTexInfo->Flags.Gpu.CCS) { CCS_UNIT *FCRectAlign = static_cast(pGmmLibContext->GetPlatformInfoObj())->GetFCRectAlign(); uint8_t index = FCMaxModes; if((index = FCMode(pTexInfo->TileMode, pTexInfo->BitsPerPixel)) < FCMaxModes) { ScaledWidth = GFX_ALIGN(ScaledWidth, FCRectAlign[index].Align.Width); ScaledWidth /= FCRectAlign[index].Downscale.Width; } else { //Unsupported tiling-type for FastClear __GMM_ASSERT(0); } } return ScaledWidth; } uint64_t GMM_STDCALL GmmLib::GmmGen12TextureCalc::Get2DFCSurfaceWidthFor3DSurface(GMM_TEXTURE_INFO *pTexInfo, uint64_t Width) { uint64_t Width2D = Width; if (pTexInfo->Flags.Gpu.CCS) { CCS_UNIT *FCRectAlign = static_cast(pGmmLibContext->GetPlatformInfoObj())->GetFCRectAlign(); uint8_t index = FCMaxModes; if ((index = FCMode(pTexInfo->TileMode, pTexInfo->BitsPerPixel)) < FCMaxModes) { Width2D = GFX_ALIGN(Width2D, FCRectAlign[index].Align.Width); Width2D *= FCRectAlign[index].Downscale.Width; } else { __GMM_ASSERT(0); } } return Width2D; } uint64_t GMM_STDCALL GmmLib::GmmGen12TextureCalc::Get2DFCSurfaceHeightFor3DSurface(GMM_TEXTURE_INFO *pTexInfo, uint32_t Height, uint32_t Depth) { uint64_t Height2D = Height; uint32_t Depth3D = Depth; if (pTexInfo->Flags.Gpu.CCS && (Depth > 1)) { CCS_UNIT *FCRectAlign = static_cast(pGmmLibContext->GetPlatformInfoObj())->GetFCRectAlign(); uint8_t index = FCMaxModes; if ((index = FCMode(pTexInfo->TileMode, pTexInfo->BitsPerPixel)) < FCMaxModes) { Height2D = GFX_ALIGN(Height2D, FCRectAlign[index].Align.Height); Height2D *= FCRectAlign[index].Downscale.Height; Depth3D = GFX_ALIGN(Depth3D, FCRectAlign[index].Align.Depth) / FCRectAlign[index].Align.Depth; Height2D *= Depth3D; } else { __GMM_ASSERT(0); } } return Height2D; } ///////////////////////////////////////////////////////////////////////////////////// /// This function does any special-case conversion from client-provided pseudo creation /// parameters to actual parameters for CCS. /// /// @param[in] pTexInfo: Reference to ::GMM_TEXTURE_INFO /// /// @return ::GMM_STATUS ///////////////////////////////////////////////////////////////////////////////////// GMM_STATUS GMM_STDCALL GmmLib::GmmGen12TextureCalc::MSAACCSUsage(GMM_TEXTURE_INFO *pTexInfo) { GMM_STATUS Status = GMM_SUCCESS; if(pTexInfo->MSAA.NumSamples > 1 && (pTexInfo->Flags.Gpu.MCS)) // CCS for MSAA Compression { Status = MSAACompression(pTexInfo); } else // Non-MSAA CCS Use (i.e. Render Target Fast Clear) { if(!pTexInfo->Flags.Info.TiledW && (!pTexInfo->Flags.Info.TiledX) && ((GMM_IS_4KB_TILE(pTexInfo->Flags) || GMM_IS_64KB_TILE(pTexInfo->Flags) || (pTexInfo->Type == RESOURCE_BUFFER && pTexInfo->Flags.Info.Linear)))) //!Yf - deprecate Yf) { // For non-MSAA CCS usage, the Doc has four tables of // requirements: // (1) RT Alignment (GMM Don't Care: Occurs Naturally) // (2) ClearRect Alignment // (3) ClearRect Scaling (GMM Don't Care: GHAL3D Matter) // (4) Non-MSAA CCS Sizing // Gen8+: // Since mip-mapped and arrayed surfaces are supported, we // deal with alignment later at per mip level. Here, we set // tiling type only. TileX is not supported on Gen9+. // Pre-Gen8: // (!) For all the above, the doc has separate entries for // 32/64/128bpp--and then deals with PIXEL widths--Here, // though, we will unify by considering 8bpp table entries // (unlisted--i.e. do the math)--and deal with BYTE widths. // (1) RT Alignment -- The surface width and height don't // need to be padded to RT CL granularity. On HSW, all tiled // RT's will have appropriate alignment (given 4KB surface // base and no mip-map support) and appropriate padding // (due to tile padding). On BDW+, GMM uses H/VALIGN that // will guarantee the MCS RT alignment for all subresources. // (2) ClearRect Alignment -- I.e. FastClears must be done // with certain granularity: // TileY: 512 Bytes x 128 Lines // TileX: 1024 Bytes x 64 Lines // So a CCS must be sized to match that granularity (though // the RT itself need not be fully padded to that // granularity to use FastClear). // (4) Non-MSAA CCS Sizing -- CCS sizing is based on the // size of the FastClear (with granularity padding) for the // paired RT. CCS's (byte widths and heights) are scaled // down from their RT's by: // TileY: 32 x 32 // TileX: 64 x 16 // ### Example ############################################# // RT: 800x600, 32bpp, TileY // 8bpp: 3200x600 // FastClear: 3584x640 (for TileY FastClear Granularity of 512x128) // CCS: 112x20 (for TileY RT:CCS Sizing Downscale of 32x32) GetCCSExMode(pTexInfo); } else { GMM_ASSERTDPF(0, "Illegal CCS creation parameters!"); Status = GMM_ERROR; } } return Status; } ///////////////////////////////////////////////////////////////////////////////////// /// Returns the mip offset of given LOD in Mip Tail /// /// @param[in] pTexInfo: ptr to ::GMM_TEXTURE_INFO, /// MipLevel: mip-map level /// /// @return offset value of LOD in bytes ///////////////////////////////////////////////////////////////////////////////////// uint32_t GmmLib::GmmGen12TextureCalc::GetMipTailByteOffset(GMM_TEXTURE_INFO *pTexInfo, uint32_t MipLevel) { uint32_t ByteOffset = 0, Slot = 0xff; GMM_DPF_ENTER; if(pGmmLibContext->GetSkuTable().FtrTileY) { return GmmGen11TextureCalc::GetMipTailByteOffset(pTexInfo, MipLevel); } // 3D textures follow the Gen10 mip tail format if(!pGmmLibContext->GetSkuTable().FtrStandardMipTailFormat) { return GmmGen9TextureCalc::GetMipTailByteOffset(pTexInfo, MipLevel); } // Til64 is the only format which supports MipTail on FtrTileY disabled platforms __GMM_ASSERT(pTexInfo->Flags.Info.Tile64); // Mipped MSAA is not supported for Tile64 __GMM_ASSERT(pTexInfo->MSAA.NumSamples <= 1); if((pTexInfo->Type == RESOURCE_1D) || (pTexInfo->Type == RESOURCE_3D) || (pTexInfo->Type == RESOURCE_2D || pTexInfo->Type == RESOURCE_CUBE)) { Slot = MipLevel - pTexInfo->Alignment.MipTailStartLod; } // Miptail Slot layout in Tile64: as per specifications // Byteoffset varies based on bpp for tile64 format, so any caller who needs to use byteoffset needs to call cpuswizzle with corresponding geomteric offsets // Returning ByteOffset as 0 for Tile64 always // GMM_DPF_CRITICAL("Miptail byte offset requested for Tile64 \r\n"); GMM_DPF_EXIT; // return ByteOffset=0, i.e return start of miptail for any address within packed miptail return (ByteOffset); } void GmmLib::GmmGen12TextureCalc::GetMipTailGeometryOffset(GMM_TEXTURE_INFO *pTexInfo, uint32_t MipLevel, uint32_t * OffsetX, uint32_t * OffsetY, uint32_t * OffsetZ) { uint32_t ArrayIndex = 0; uint32_t Slot = 0; GMM_DPF_ENTER; if(pGmmLibContext->GetSkuTable().FtrTileY) { return GmmGen11TextureCalc::GetMipTailGeometryOffset(pTexInfo, MipLevel, OffsetX, OffsetY, OffsetZ); } // Til64 is the only format which supports MipTail on FtrTileY disabled platforms __GMM_ASSERT(pTexInfo->Flags.Info.Tile64); // Mipped MSAA is not supported for Tile64 __GMM_ASSERT(pTexInfo->MSAA.NumSamples <= 1); switch(pTexInfo->BitsPerPixel) { case 128: ArrayIndex = 0; break; case 64: ArrayIndex = 1; break; case 32: ArrayIndex = 2; break; case 16: ArrayIndex = 3; break; case 8: ArrayIndex = 4; break; default: __GMM_ASSERT(0); break; } // FtrTileY disabled platforms: platforms which support Tile4/Tile64 tiled formats if(pTexInfo->Type == RESOURCE_1D) { Slot = MipLevel - pTexInfo->Alignment.MipTailStartLod; *OffsetX = MipTailSlotOffset1DSurface[Slot][ArrayIndex].X * pTexInfo->BitsPerPixel / 8; *OffsetY = MipTailSlotOffset1DSurface[Slot][ArrayIndex].Y; *OffsetZ = MipTailSlotOffset1DSurface[Slot][ArrayIndex].Z; } else if(pTexInfo->Type == RESOURCE_2D || pTexInfo->Type == RESOURCE_CUBE) { // Mipped MSAA is not supported on Tile64, so need not account for MSAA here Slot = MipLevel - pTexInfo->Alignment.MipTailStartLod; *OffsetX = MipTailSlotOffset2DSurface[Slot][ArrayIndex].X * pTexInfo->BitsPerPixel / 8; *OffsetY = MipTailSlotOffset2DSurface[Slot][ArrayIndex].Y; *OffsetZ = MipTailSlotOffset2DSurface[Slot][ArrayIndex].Z; } else if(pTexInfo->Type == RESOURCE_3D) { Slot = MipLevel - pTexInfo->Alignment.MipTailStartLod; *OffsetX = MipTailSlotOffset3DSurface[Slot][ArrayIndex].X * pTexInfo->BitsPerPixel / 8; *OffsetY = MipTailSlotOffset3DSurface[Slot][ArrayIndex].Y; *OffsetZ = MipTailSlotOffset3DSurface[Slot][ArrayIndex].Z; } GMM_DPF_EXIT; return; } gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/Texture/GmmGen7Texture.cpp000066400000000000000000000775051466655022700250570ustar00rootroot00000000000000/*============================================================================== Copyright(c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ============================================================================*/ #include "Internal/Common/GmmLibInc.h" ///////////////////////////////////////////////////////////////////////////////////// /// Allocates the 2D mip layout for surface state programming. /// /// @param[in] pTexInfo: ptr to ::GMM_TEXTURE_INFO, /// @param[in] pRestrictions: ptr to surface alignment and size restrictions /// /// @return ::GMM_STATUS ///////////////////////////////////////////////////////////////////////////////////// GMM_STATUS GMM_STDCALL GmmLib::GmmGen7TextureCalc::FillTex2D(GMM_TEXTURE_INFO * pTexInfo, __GMM_BUFFER_TYPE *pRestrictions) { uint32_t Width, Height, BitsPerPixel; uint32_t HAlign, VAlign; uint32_t CompressHeight, CompressWidth, CompressDepth; uint32_t AlignedWidth, BlockHeight, ExpandedArraySize, Pitch; uint8_t Compress = 0; GMM_STATUS Status; __GMM_ASSERTPTR(pTexInfo, GMM_ERROR); __GMM_ASSERTPTR(pRestrictions, GMM_ERROR); GMM_DPF_ENTER; const GMM_PLATFORM_INFO *pPlatform = GMM_OVERRIDE_PLATFORM_INFO(pTexInfo, pGmmLibContext); BitsPerPixel = pTexInfo->BitsPerPixel; Height = pTexInfo->BaseHeight; Width = GFX_ULONG_CAST(pTexInfo->BaseWidth); pTexInfo->MSAA.NumSamples = GFX_MAX(pTexInfo->MSAA.NumSamples, 1); ExpandedArraySize = GFX_MAX(pTexInfo->ArraySize, 1) * ((pTexInfo->Type == RESOURCE_CUBE) ? 6 : 1) * // Cubemaps simply 6-element, 2D arrays. ((pTexInfo->Flags.Gpu.Depth || pTexInfo->Flags.Gpu.SeparateStencil) ? 1 : pTexInfo->MSAA.NumSamples); // Gen7 MSAA (non-Depth/Stencil) RT samples stored as array planes. // // Check for color separation // if(pTexInfo->Flags.Gpu.ColorSeparation || pTexInfo->Flags.Gpu.ColorSeparationRGBX) { bool csRestrictionsMet = (((ExpandedArraySize <= 2) && (ExpandedArraySize == pTexInfo->ArraySize) && ((pTexInfo->Format == GMM_FORMAT_R8G8B8A8_UNORM) || (pTexInfo->Format == GMM_FORMAT_R8G8B8A8_UNORM_SRGB) || (pTexInfo->Format == GMM_FORMAT_B8G8R8A8_UNORM) || (pTexInfo->Format == GMM_FORMAT_B8G8R8A8_UNORM_SRGB) || (pTexInfo->Format == GMM_FORMAT_B8G8R8X8_UNORM) || (pTexInfo->Format == GMM_FORMAT_B8G8R8X8_UNORM_SRGB)) && ((pTexInfo->Flags.Gpu.ColorSeparation && (Width % 16) == 0) || (pTexInfo->Flags.Gpu.ColorSeparationRGBX && (Width % 12) == 0)))); if(csRestrictionsMet) { ExpandedArraySize = GMM_COLOR_SEPARATION_ARRAY_SIZE; } else { pTexInfo->Flags.Gpu.ColorSeparation = 0; pTexInfo->Flags.Gpu.ColorSeparationRGBX = 0; } } HAlign = pTexInfo->Alignment.HAlign; VAlign = pTexInfo->Alignment.VAlign; GetCompressionBlockDimensions(pTexInfo->Format, &CompressWidth, &CompressHeight, &CompressDepth); Compress = GmmIsCompressed(pGmmLibContext, pTexInfo->Format); ///////////////////////////////// // Calculate Block Surface Height ///////////////////////////////// // Adjust total height for arrayed 2D textures if(ExpandedArraySize > 1) { uint32_t Height0, Height1; Height0 = __GMM_EXPAND_HEIGHT(this, Height, VAlign, pTexInfo); // If not ARYSPC_LOD0-eligible... if((pTexInfo->MaxLod > 0) || pTexInfo->Flags.Gpu.Depth || // Depth/HiZ/Stencil buffers not ARYSPC_LOD0-compatible. pTexInfo->Flags.Gpu.HiZ || pTexInfo->Flags.Gpu.SeparateStencil) { Height1 = __GMM_EXPAND_HEIGHT(this, Height >> 1, VAlign, pTexInfo); // QPitch = (h0 + h1 + 12j) * pitch BlockHeight = Height0 + Height1 + 12 * VAlign; } else // SURFACE_STATE: Surface Array Spacing: ARYSPC_LOD0 { // QPitch = h0 * pitch BlockHeight = Height0; pTexInfo->Alignment.ArraySpacingSingleLod = true; } if(Compress) { BlockHeight /= CompressHeight; } else if(pTexInfo->Flags.Gpu.SeparateStencil) { BlockHeight /= 2; } // Compute total array height BlockHeight *= ExpandedArraySize; } else { BlockHeight = Get2DMipMapHeight(pTexInfo); } /////////////////////////////////// // Calculate Pitch /////////////////////////////////// AlignedWidth = __GMM_EXPAND_WIDTH(this, Width, HAlign, pTexInfo); // Calculate special pitch case of small dimensions where LOD1 + LOD2 widths are greater // than LOD0. e.g. dimensions 4x4 and MinPitch == 1 if(pTexInfo->MaxLod >= 2) { uint32_t AlignedWidthLod1, AlignedWidthLod2; AlignedWidthLod1 = __GMM_EXPAND_WIDTH(this, Width >> 1, HAlign, pTexInfo); AlignedWidthLod2 = __GMM_EXPAND_WIDTH(this, Width >> 2, HAlign, pTexInfo); AlignedWidth = GFX_MAX(AlignedWidth, AlignedWidthLod1 + AlignedWidthLod2); } if(Compress) { AlignedWidth /= CompressWidth; } else if(pTexInfo->Flags.Gpu.SeparateStencil) { AlignedWidth *= 2; } else if(pTexInfo->Flags.Gpu.ColorSeparation) { AlignedWidth *= pTexInfo->ArraySize; __GMM_ASSERT(0 == (AlignedWidth % GMM_COLOR_SEPARATION_WIDTH_DIVISION)); AlignedWidth /= GMM_COLOR_SEPARATION_WIDTH_DIVISION; } else if(pTexInfo->Flags.Gpu.ColorSeparationRGBX) { AlignedWidth *= pTexInfo->ArraySize; __GMM_ASSERT(0 == (AlignedWidth % GMM_COLOR_SEPARATION_RGBX_WIDTH_DIVISION)); AlignedWidth /= GMM_COLOR_SEPARATION_RGBX_WIDTH_DIVISION; } // Default pitch Pitch = AlignedWidth * BitsPerPixel >> 3; // Make sure the pitch satisfy linear min pitch requirment Pitch = GFX_MAX(Pitch, pRestrictions->MinPitch); // Make sure pitch satisfy alignment restriction Pitch = GFX_ALIGN(Pitch, pRestrictions->PitchAlignment); //////////////////// // Adjust for Tiling //////////////////// if(GMM_IS_TILED(pPlatform->TileInfo[pTexInfo->TileMode])) { Pitch = GFX_ALIGN(Pitch, pPlatform->TileInfo[pTexInfo->TileMode].LogicalTileWidth); BlockHeight = GFX_ALIGN(BlockHeight, pPlatform->TileInfo[pTexInfo->TileMode].LogicalTileHeight); // If Tiled Resource or Undefined64KBSwizzle resource, align to 64KB tile size if((pTexInfo->Flags.Gpu.TiledResource || pTexInfo->Flags.Info.Undefined64KBSwizzle) && (pTexInfo->Flags.Info.TiledY)) { uint32_t ColFactor = 0, RowFactor = 0; uint32_t TRTileWidth = 0, TRTileHeight = 0; GmmGetD3DToHwTileConversion(pTexInfo, &ColFactor, &RowFactor); TRTileWidth = pPlatform->TileInfo[pTexInfo->TileMode].LogicalTileWidth * ColFactor; TRTileHeight = pPlatform->TileInfo[pTexInfo->TileMode].LogicalTileHeight * RowFactor; Pitch = GFX_ALIGN(Pitch, TRTileWidth); BlockHeight = GFX_ALIGN(BlockHeight, TRTileHeight); } } GMM_ASSERTDPF(pTexInfo->Flags.Info.LayoutBelow || !pTexInfo->Flags.Info.LayoutRight, "MIPLAYOUT_RIGHT not supported after Gen6!"); pTexInfo->Flags.Info.LayoutBelow = 1; pTexInfo->Flags.Info.LayoutRight = 0; // If a texture is YUV packed, 96, or 48 bpp then one row plus 16 bytes of // padding needs to be added. Since this will create a none pitch aligned // surface the padding is aligned to the next row if(GmmIsYUVPacked(pTexInfo->Format) || (pTexInfo->BitsPerPixel == GMM_BITS(96)) || (pTexInfo->BitsPerPixel == GMM_BITS(48))) { BlockHeight += GMM_SCANLINES(1) + GFX_CEIL_DIV(GMM_BYTES(16), Pitch); } // Align height to even row to cover for HW over - fetch BlockHeight = GFX_ALIGN(BlockHeight, __GMM_EVEN_ROW); if((Status = // <-- Note assignment. FillTexPitchAndSize( pTexInfo, Pitch, BlockHeight, pRestrictions)) == GMM_SUCCESS) { Fill2DTexOffsetAddress(pTexInfo); // Init to no-packed mips. It'll be initialized when app calls to get packed // mips. Calculate packed mips here if there's a chance apps won't call to // get packed mips. pTexInfo->Alignment.PackedMipStartLod = GMM_TILED_RESOURCE_NO_PACKED_MIPS; } GMM_DPF_EXIT; return (Status); } ///////////////////////////////////////////////////////////////////////////////////// /// Calculates the mip offset of given LOD in 2D mip layout /// /// @param[in] pTexInfo: ptr to ::GMM_TEXTURE_INFO, /// /// @return offset value in bytes ///////////////////////////////////////////////////////////////////////////////////// GMM_GFX_SIZE_T GmmLib::GmmGen7TextureCalc::Get2DTexOffsetAddressPerMip(GMM_TEXTURE_INFO *pTexInfo, uint32_t MipLevel) { GMM_GFX_SIZE_T MipOffset; uint32_t AlignedMipHeight, i, MipHeight, OffsetHeight; uint32_t HAlign, VAlign; uint32_t CompressHeight, CompressWidth, CompressDepth; uint8_t Compress; __GMM_ASSERTPTR(pTexInfo, GMM_ERROR); GMM_DPF_ENTER; const GMM_PLATFORM_INFO *pPlatform = GMM_OVERRIDE_PLATFORM_INFO(pTexInfo, pGmmLibContext); HAlign = pTexInfo->Alignment.HAlign; VAlign = pTexInfo->Alignment.VAlign; GetCompressionBlockDimensions(pTexInfo->Format, &CompressWidth, &CompressHeight, &CompressDepth); Compress = GmmIsCompressed(pGmmLibContext, pTexInfo->Format); MipHeight = pTexInfo->BaseHeight; OffsetHeight = 0; // Mips 0 and 1 are on the left edge... if(MipLevel < 2) { MipOffset = 0; } else // Mip2 and beyond are to the right of Mip1... { uint32_t Mip1Width = GFX_ULONG_CAST(pTexInfo->BaseWidth) >> 1; Mip1Width = __GMM_EXPAND_WIDTH(this, Mip1Width, HAlign, pTexInfo); if(Compress) { Mip1Width /= CompressWidth; if((pGmmLibContext->GetWaTable().WaAstcCorruptionForOddCompressedBlockSizeX || pTexInfo->Flags.Wa.CHVAstcSkipVirtualMips) && pPlatform->FormatTable[pTexInfo->Format].ASTC && CompressWidth == 5) { uint32_t Width1 = (pTexInfo->BaseWidth == 1) ? 1 : (GFX_ULONG_CAST(pTexInfo->BaseWidth) >> 1); uint32_t Modulo10 = Width1 % 10; if(Modulo10 >= 1 && Modulo10 <= CompressWidth) { Mip1Width += 3; } } } else if(pTexInfo->Flags.Gpu.SeparateStencil) { Mip1Width *= 2; } MipOffset = (GMM_GFX_SIZE_T)Mip1Width * pTexInfo->BitsPerPixel >> 3; } for(i = 1; i <= MipLevel; i++) { AlignedMipHeight = GFX_ULONG_CAST(__GMM_EXPAND_HEIGHT(this, MipHeight, VAlign, pTexInfo)); if(Compress) { AlignedMipHeight /= CompressHeight; } else if(pTexInfo->Flags.Gpu.SeparateStencil) { AlignedMipHeight /= 2; } OffsetHeight += ((i != 2) ? AlignedMipHeight : 0); MipHeight >>= 1; } MipOffset += OffsetHeight * GFX_ULONG_CAST(pTexInfo->Pitch); GMM_DPF_EXIT; return (MipOffset); } ///////////////////////////////////////////////////////////////////////////////////// /// Calculates height of the 2D mip layout /// /// @param[in] pTexInfo: ptr to ::GMM_TEXTURE_INFO, /// /// @return Height of 2D mip layout ///////////////////////////////////////////////////////////////////////////////////// uint32_t GmmLib::GmmGen7TextureCalc::Get2DMipMapHeight(GMM_TEXTURE_INFO *pTexInfo) { uint32_t Height, BlockHeight, NumLevels; // Final height for 2D surface uint32_t HeightLines, HeightLinesLevel0, HeightLinesLevel1, HeightLinesLevel2; uint32_t VAlign, CompressHeight, CompressWidth, CompressDepth; uint32_t i; uint8_t Compress; GMM_DPF_ENTER; const GMM_PLATFORM_INFO *pPlatform = GMM_OVERRIDE_PLATFORM_INFO(pTexInfo, pGmmLibContext); // Mip 0 height is needed later Height = pTexInfo->BaseHeight; Compress = GmmIsCompressed(pGmmLibContext, pTexInfo->Format); NumLevels = pTexInfo->MaxLod; HeightLines = Height; VAlign = pTexInfo->Alignment.VAlign; GetCompressionBlockDimensions(pTexInfo->Format, &CompressWidth, &CompressHeight, &CompressDepth); HeightLinesLevel0 = __GMM_EXPAND_HEIGHT(this, HeightLines, VAlign, pTexInfo); if(Compress) { HeightLinesLevel0 /= CompressHeight; } else if(pTexInfo->Flags.Gpu.SeparateStencil) { HeightLinesLevel0 /= 2; } // Start out with mip0 BlockHeight = HeightLinesLevel0; // Height of mip1 and height of all others mips(2,3,4,5,,) needed later HeightLinesLevel1 = HeightLinesLevel2 = 0; for(i = 1; i <= NumLevels; i++) { uint32_t AlignedHeightLines; HeightLines >>= 1; AlignedHeightLines = __GMM_EXPAND_HEIGHT(this, HeightLines, VAlign, pTexInfo); if(Compress) { AlignedHeightLines /= CompressHeight; } else if(pTexInfo->Flags.Gpu.SeparateStencil) { AlignedHeightLines /= 2; } if(i == 1) { HeightLinesLevel1 = AlignedHeightLines; } else { HeightLinesLevel2 += AlignedHeightLines; } } // If mip1 height covers all others then that is all we need if(HeightLinesLevel1 >= HeightLinesLevel2) { BlockHeight += GFX_ALIGN_NP2(HeightLinesLevel1, VAlign); } else { BlockHeight += GFX_ALIGN_NP2(HeightLinesLevel2, VAlign); } GMM_DPF_EXIT; return (BlockHeight); } ///////////////////////////////////////////////////////////////////////////////////// /// Calculates the address offset for each mip map of 2D texture and store them /// into the GMM_TEXTURE_INFO for surf state programming. /// /// @param[in] pTexInfo: pointer to ::GMM_TEXTURE_INFO /// ///////////////////////////////////////////////////////////////////////////////////// void GmmLib::GmmGen7TextureCalc::Fill2DTexOffsetAddress(GMM_TEXTURE_INFO *pTexInfo) { uint32_t i; __GMM_ASSERTPTR(pTexInfo, VOIDRETURN); GMM_DPF_ENTER; // QPitch: Array Element-to-Element, or Cube Face-to-Face Pitch... // ------------------------------------------------------------------------- // Note: Gen7 MSAA RT samples stored as contiguous array planes-- // e.g. MSAA-4X'ed array elements A and B stored: A0 A1 A2 A3 B0 B1 B2 B3. // However, for GMM's purposes QPitch is still the distance between // elements--not the distance between samples. // ------------------------------------------------------------------------- if((pTexInfo->ArraySize <= 1) && (pTexInfo->Type != RESOURCE_CUBE) && !(pTexInfo->Flags.Gpu.ColorSeparation || pTexInfo->Flags.Gpu.ColorSeparationRGBX)) { pTexInfo->OffsetInfo.Texture2DOffsetInfo.ArrayQPitchRender = 0; pTexInfo->OffsetInfo.Texture2DOffsetInfo.ArrayQPitchLock = 0; } else { uint32_t Height, Height0, Height1, ArrayQPitch, VAlign; Height = pTexInfo->BaseHeight; VAlign = pTexInfo->Alignment.VAlign; Height0 = __GMM_EXPAND_HEIGHT(this, Height, VAlign, pTexInfo); Height1 = __GMM_EXPAND_HEIGHT(this, Height >> 1, VAlign, pTexInfo); if(!pTexInfo->Alignment.ArraySpacingSingleLod) { // QPitch = (h0 + h1 + 12j) * pitch ArrayQPitch = Height0 + Height1 + 12 * VAlign; } else // SURFACE_STATE: Surface Array Spacing: ARYSPC_LOD0 { // QPitch = h0 * pitch ArrayQPitch = Height0; } if(GmmIsCompressed(pGmmLibContext, pTexInfo->Format)) { uint32_t CompressHeight, CompressWidth, CompressDepth; GetCompressionBlockDimensions(pTexInfo->Format, &CompressWidth, &CompressHeight, &CompressDepth); ArrayQPitch /= CompressHeight; } else if(pTexInfo->Flags.Gpu.SeparateStencil) { ArrayQPitch /= 2; } if((pTexInfo->MSAA.NumSamples > 1) && !(pTexInfo->Flags.Gpu.Depth || pTexInfo->Flags.Gpu.SeparateStencil)) { // Gen7 MSAA (non-Depth/Stencil) RT samples stored as array planes; // QPitch still element-to-element, not sample-to-sample. ArrayQPitch *= pTexInfo->MSAA.NumSamples; } pTexInfo->OffsetInfo.Texture2DOffsetInfo.ArrayQPitchRender = ArrayQPitch * pTexInfo->Pitch; pTexInfo->OffsetInfo.Texture2DOffsetInfo.ArrayQPitchLock = ArrayQPitch * pTexInfo->Pitch; } for(i = 0; i <= pTexInfo->MaxLod; i++) { pTexInfo->OffsetInfo.Texture2DOffsetInfo.Offset[i] = Get2DTexOffsetAddressPerMip(pTexInfo, i); } GMM_DPF_EXIT; } ///////////////////////////////////////////////////////////////////////////////////// /// Calculates total height of an arrayed 3D mip layout /// /// @param[in] pTexInfo: ptr to ::GMM_TEXTURE_INFO, /// /// @return height of arrayed 3D mip layout ///////////////////////////////////////////////////////////////////////////////////// uint32_t GmmLib::GmmGen7TextureCalc::GetTotal3DHeight(GMM_TEXTURE_INFO *pTexInfo) { uint32_t AlignedHeight, BlockHeight, Depth; uint8_t Compressed; uint32_t i, MipsInThisRow, MipLevel, MipRows; uint32_t Total3DHeight = 0, UnitAlignHeight; uint32_t CompressHeight, CompressWidth, CompressDepth; GMM_TEXTURE_CALC *pTextureCalc; GMM_DPF_ENTER; pTextureCalc = GMM_OVERRIDE_TEXTURE_CALC(pTexInfo, pGmmLibContext); BlockHeight = pTexInfo->BaseHeight; Depth = pTexInfo->Depth; MipLevel = pTexInfo->MaxLod; UnitAlignHeight = pTexInfo->Alignment.VAlign; Compressed = GmmIsCompressed(pGmmLibContext, pTexInfo->Format); pTextureCalc->GetCompressionBlockDimensions(pTexInfo->Format, &CompressWidth, &CompressHeight, &CompressDepth); // All mip0s of all planes are stacked together, then mip1s and so on... for(i = 0; i <= MipLevel; i++) { BlockHeight = GFX_MAX(BlockHeight, UnitAlignHeight); AlignedHeight = GFX_ALIGN(BlockHeight, UnitAlignHeight); if(Compressed) { AlignedHeight /= CompressHeight; } else if(pTexInfo->Flags.Gpu.SeparateStencil) { AlignedHeight /= 2; } else if(pTexInfo->Flags.Gpu.CCS) { if(pTexInfo->Flags.Gpu.__NonMsaaTileYCcs) { AlignedHeight /= 32; } else if(pTexInfo->Flags.Gpu.__NonMsaaTileXCcs) { AlignedHeight /= 16; } } // See how many mip can fit in one row MipsInThisRow = GFX_2_TO_POWER_OF(i); // calculate if the mips will spill over to multiple rows MipRows = GFX_CEIL_DIV(GFX_MAX(1, Depth >> i), MipsInThisRow); Total3DHeight += MipRows * AlignedHeight; // next level height BlockHeight >>= 1; } GMM_DPF_EXIT; return Total3DHeight; } ///////////////////////////////////////////////////////////////////////////////////// /// Calculates the address offset for each mip map of 3D texture and store them /// into the GMM_TEXTURE_INFO for surf state programming. /// /// @param[in] pTexInfo: ptr to ::GMM_TEXTURE_INFO, /// ///////////////////////////////////////////////////////////////////////////////////// void GmmLib::GmmGen7TextureCalc::Fill3DTexOffsetAddress(GMM_TEXTURE_INFO *pTexInfo) { uint32_t AlignedMipHeight, AlignedMipWidth; uint32_t i, Depth; uint32_t MipsInThisRow, MipLevel, MipRows; uint32_t MipHeight, MipWidth; uint32_t UnitAlignHeight, UnitAlignWidth; uint32_t CompressHeight, CompressWidth, CompressDepth; uint32_t OffsetMipRows = 0; GMM_GFX_SIZE_T OffsetValue; uint8_t Compress; GMM_TEXTURE_CALC *pTextureCalc; __GMM_ASSERT(pTexInfo); pTextureCalc = GMM_OVERRIDE_TEXTURE_CALC(pTexInfo, pGmmLibContext); // Assign directly to unaligned MipMap dimension variables // There isn't a need to save original dimensions MipWidth = GFX_ULONG_CAST(pTexInfo->BaseWidth); MipHeight = pTexInfo->BaseHeight; // Align before we compress UnitAlignWidth = pTexInfo->Alignment.HAlign; UnitAlignHeight = pTexInfo->Alignment.VAlign; Compress = GmmIsCompressed(pGmmLibContext, pTexInfo->Format); pTextureCalc->GetCompressionBlockDimensions(pTexInfo->Format, &CompressWidth, &CompressHeight, &CompressDepth); // Aligned MipMap Dimensions AlignedMipWidth = GFX_ALIGN(MipWidth, UnitAlignWidth); AlignedMipHeight = GFX_ALIGN(MipHeight, UnitAlignHeight); Depth = pTexInfo->Depth; MipLevel = pTexInfo->MaxLod; // Start with base offset OffsetValue = 0; // calculate the offset for each Mip level for(i = 0; i <= MipLevel; i++) { // store the value in blockdesc if(Compress) { // If there is compression, compress after the alignment at each level AlignedMipWidth /= CompressWidth; AlignedMipHeight /= CompressHeight; } else if(pTexInfo->Flags.Gpu.SeparateStencil) { AlignedMipWidth *= 2; AlignedMipHeight /= 2; } else if(pTexInfo->Flags.Gpu.CCS) { if(pTexInfo->Flags.Gpu.__NonMsaaTileYCcs) { switch(pTexInfo->BitsPerPixel) { case 32: AlignedMipWidth /= 8; break; case 64: AlignedMipWidth /= 4; break; case 128: AlignedMipWidth /= 2; break; default: __GMM_ASSERT(0); } AlignedMipHeight /= 32; } else if(pTexInfo->Flags.Gpu.__NonMsaaTileXCcs) { switch(pTexInfo->BitsPerPixel) { case 32: AlignedMipWidth /= 16; break; case 64: AlignedMipWidth /= 8; break; case 128: AlignedMipWidth /= 4; break; default: __GMM_ASSERT(0); } AlignedMipHeight /= 16; } } pTexInfo->OffsetInfo.Texture3DOffsetInfo.Offset[i] = OffsetValue; // See how many mip can fit in one row MipsInThisRow = GFX_2_TO_POWER_OF(i); // Slice pitch for LOD0 if(MipsInThisRow == 1) { pTexInfo->OffsetInfo.Texture3DOffsetInfo.Mip0SlicePitch = AlignedMipHeight * pTexInfo->Pitch; } // calculate if the mips will spill over to multiple rows MipRows = GFX_CEIL_DIV(GFX_MAX(1, Depth >> i), MipsInThisRow); // Offset in terms of height OffsetMipRows += MipRows * AlignedMipHeight; // For a particular mip This is offset of a base slice (i.e. Slice 0) OffsetValue = OffsetMipRows * pTexInfo->Pitch; // next level height MipHeight >>= 1; // Clamp such that mip height is at least1 MipHeight = GFX_MAX(MipHeight, 1); AlignedMipHeight = GFX_ALIGN(MipHeight, UnitAlignHeight); MipWidth >>= 1; // Clamp such that mip width is at least 1 MipWidth = GFX_MAX(MipWidth, 1); AlignedMipWidth = GFX_ALIGN(MipWidth, UnitAlignWidth); } } ///////////////////////////////////////////////////////////////////////////////////// /// Calculates the 3D offset and QPitch for surface state programming. /// /// @param[in] pTexInfo: ptr to ::GMM_TEXTURE_INFO, /// @param[in] pRestrictions: ptr to surface alignment and size restrictions /// /// @return ::GMM_STATUS ///////////////////////////////////////////////////////////////////////////////////// GMM_STATUS GMM_STDCALL GmmLib::GmmGen7TextureCalc::FillTex3D(GMM_TEXTURE_INFO * pTexInfo, __GMM_BUFFER_TYPE *pRestrictions) { uint32_t AlignedMipWidth; uint32_t BitsPerPixel; uint32_t Depth, Height, Width; uint32_t i, MipsInThisRow, MipWidth; uint32_t RenderPitch = 0, ThisRowPitch; uint32_t UnitAlignWidth; uint32_t Total3DHeight; uint32_t WidthBytesPhysical; uint8_t Compress; uint32_t CompressHeight, CompressWidth, CompressDepth; bool SeparateStencil; GMM_STATUS Status; GMM_DPF_ENTER; __GMM_ASSERTPTR(pTexInfo, GMM_ERROR); __GMM_ASSERTPTR(pRestrictions, GMM_ERROR); const __GMM_PLATFORM_RESOURCE *pPlatformResource = GMM_OVERRIDE_PLATFORM_INFO(pTexInfo, pGmmLibContext); BitsPerPixel = pTexInfo->BitsPerPixel; Height = pTexInfo->BaseHeight; Width = GFX_ULONG_CAST(pTexInfo->BaseWidth); Depth = pTexInfo->Depth; // Align before we compress UnitAlignWidth = pTexInfo->Alignment.HAlign; Compress = GmmIsCompressed(pGmmLibContext, pTexInfo->Format); GetCompressionBlockDimensions(pTexInfo->Format, &CompressWidth, &CompressHeight, &CompressDepth); SeparateStencil = pTexInfo->Flags.Gpu.SeparateStencil ? true : false; // Unaligned MipMap dimension variables MipWidth = Width; // Aligned MipMap dimension variables AlignedMipWidth = GFX_ALIGN(MipWidth, UnitAlignWidth); // Calculate the render pitch exactly the same way we do the // offset for each Mip level for(i = 0; i <= pTexInfo->MaxLod; i++) { if(Compress) { // If there is compression, compress after the alignment at each level AlignedMipWidth /= CompressWidth; } else if(SeparateStencil) { AlignedMipWidth *= 2; } else if(pTexInfo->Flags.Gpu.CCS) { if(pTexInfo->Flags.Gpu.__NonMsaaTileYCcs) { switch(BitsPerPixel) { case 32: AlignedMipWidth /= 8; break; case 64: AlignedMipWidth /= 4; break; case 128: AlignedMipWidth /= 2; break; default: __GMM_ASSERT(0); } } else if(pTexInfo->Flags.Gpu.__NonMsaaTileXCcs) { switch(BitsPerPixel) { case 32: AlignedMipWidth /= 16; break; case 64: AlignedMipWidth /= 8; break; case 128: AlignedMipWidth /= 4; break; default: __GMM_ASSERT(0); } } } // See how many mip can fit in one row MipsInThisRow = GFX_2_TO_POWER_OF(i); // LOD planes may be less than MipsInThisRow, take the smaller value for pitch MipsInThisRow = GFX_MIN(GFX_MAX(1, (Depth >> i)), MipsInThisRow); ThisRowPitch = AlignedMipWidth * MipsInThisRow; // Default pitch WidthBytesPhysical = ThisRowPitch * BitsPerPixel >> 3; if(RenderPitch < WidthBytesPhysical) { RenderPitch = WidthBytesPhysical; } MipWidth >>= 1; // Clamp such that mip width is at least 1 MipWidth = GFX_MAX(MipWidth, 1); AlignedMipWidth = GFX_ALIGN(MipWidth, UnitAlignWidth); } WidthBytesPhysical = RenderPitch; // Make sure the pitch satisfy linear min pitch requirment WidthBytesPhysical = GFX_MAX(WidthBytesPhysical, pRestrictions->MinPitch); // Make sure pitch satisfy alignment restriction WidthBytesPhysical = GFX_ALIGN(WidthBytesPhysical, pRestrictions->PitchAlignment); // Get Total height for the entire 3D texture Total3DHeight = GetTotal3DHeight(pTexInfo); if(GMM_IS_TILED(pPlatformResource->TileInfo[pTexInfo->TileMode])) { // Align to tile boundary Total3DHeight = GFX_ALIGN(Total3DHeight, pPlatformResource->TileInfo[pTexInfo->TileMode].LogicalTileHeight); WidthBytesPhysical = GFX_ALIGN(WidthBytesPhysical, pPlatformResource->TileInfo[pTexInfo->TileMode].LogicalTileWidth); } // If a texture is YUV packed, 96, or 48 bpp then one row plus 16 bytes of // padding needs to be added. Since this will create a none pitch aligned // surface the padding is aligned to the next row if(GmmIsYUVPacked(pTexInfo->Format) || (pTexInfo->BitsPerPixel == GMM_BITS(96)) || (pTexInfo->BitsPerPixel == GMM_BITS(48))) { Total3DHeight += GMM_SCANLINES(1) + GFX_CEIL_DIV(GMM_BYTES(16), WidthBytesPhysical); } Total3DHeight = GFX_ALIGN(Total3DHeight, __GMM_EVEN_ROW); if((Status = // <-- Note assignment. FillTexPitchAndSize( pTexInfo, WidthBytesPhysical, Total3DHeight, pRestrictions)) == GMM_SUCCESS) { Fill3DTexOffsetAddress(pTexInfo); } GMM_DPF_EXIT; return (Status); } ///////////////////////////////////////////////////////////////////////////////////// /// Allocates the 1D mip layout for surface state programming. /// /// @param[in] pTexInfo: ptr to ::GMM_TEXTURE_INFO, /// @param[in] pRestrictions: ptr to surface alignment and size restrictions /// /// @return ::GMM_STATUS ///////////////////////////////////////////////////////////////////////////////////// GMM_STATUS GMM_STDCALL GmmLib::GmmGen7TextureCalc::FillTex1D(GMM_TEXTURE_INFO * pTexInfo, __GMM_BUFFER_TYPE *pRestrictions) { return FillTex2D(pTexInfo, pRestrictions); } ///////////////////////////////////////////////////////////////////////////////////// /// Calculates the cube layout for surface state programming. /// /// @param[in] pTexInfo: ptr to ::GMM_TEXTURE_INFO, /// @param[in] pRestrictions: ptr to surface alignment and size restrictions /// /// @return ::GMM_STATUS ///////////////////////////////////////////////////////////////////////////////////// GMM_STATUS GMM_STDCALL GmmLib::GmmGen7TextureCalc::FillTexCube(GMM_TEXTURE_INFO * pTexInfo, __GMM_BUFFER_TYPE *pRestrictions) { return FillTex2D(pTexInfo, pRestrictions); } gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/Texture/GmmGen8Texture.cpp000066400000000000000000000466511466655022700250560ustar00rootroot00000000000000/*============================================================================== Copyright(c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ============================================================================*/ #include "Internal/Common/GmmLibInc.h" ///////////////////////////////////////////////////////////////////////////////////// /// Allocates the 2D mip layout for surface state programming. /// /// @param[in] pTexInfo: ptr to ::GMM_TEXTURE_INFO, /// @param[in] pRestrictions: ptr to surface alignment and size restrictions /// /// @return ::GMM_STATUS ///////////////////////////////////////////////////////////////////////////////////// GMM_STATUS GMM_STDCALL GmmLib::GmmGen8TextureCalc::FillTex2D(GMM_TEXTURE_INFO * pTexInfo, __GMM_BUFFER_TYPE *pRestrictions) { uint32_t Width, Height, BitsPerPixel; uint32_t HAlign, VAlign; uint32_t CompressHeight, CompressWidth, CompressDepth; uint32_t AlignedWidth, BlockHeight, ExpandedArraySize, Pitch; uint8_t Compress = 0; GMM_STATUS Status; GMM_DPF_ENTER; __GMM_ASSERTPTR(pTexInfo, GMM_ERROR); __GMM_ASSERTPTR(pRestrictions, GMM_ERROR); const GMM_PLATFORM_INFO *pPlatform = GMM_OVERRIDE_PLATFORM_INFO(pTexInfo, pGmmLibContext); BitsPerPixel = pTexInfo->BitsPerPixel; Height = pTexInfo->BaseHeight; Width = GFX_ULONG_CAST(pTexInfo->BaseWidth); pTexInfo->MSAA.NumSamples = GFX_MAX(pTexInfo->MSAA.NumSamples, 1); ExpandedArraySize = GFX_MAX(pTexInfo->ArraySize, 1) * ((pTexInfo->Type == RESOURCE_CUBE) ? 6 : 1) * // Cubemaps simply 6-element, 2D arrays. ((pTexInfo->Flags.Gpu.Depth || pTexInfo->Flags.Gpu.SeparateStencil) ? 1 : pTexInfo->MSAA.NumSamples); // MSAA (non-Depth/Stencil) RT samples stored as array planes. // // Check for color separation // if(pTexInfo->Flags.Gpu.ColorSeparation || pTexInfo->Flags.Gpu.ColorSeparationRGBX) { bool csRestrictionsMet = (((ExpandedArraySize <= 2) && (ExpandedArraySize == pTexInfo->ArraySize) && ((pTexInfo->Format == GMM_FORMAT_R8G8B8A8_UNORM) || (pTexInfo->Format == GMM_FORMAT_R8G8B8A8_UNORM_SRGB) || (pTexInfo->Format == GMM_FORMAT_B8G8R8A8_UNORM) || (pTexInfo->Format == GMM_FORMAT_B8G8R8A8_UNORM_SRGB) || (pTexInfo->Format == GMM_FORMAT_B8G8R8X8_UNORM) || (pTexInfo->Format == GMM_FORMAT_B8G8R8X8_UNORM_SRGB)) && ((pTexInfo->Flags.Gpu.ColorSeparation && (Width % 16) == 0) || (pTexInfo->Flags.Gpu.ColorSeparationRGBX && (Width % 12) == 0)))); if(csRestrictionsMet) { ExpandedArraySize = GMM_COLOR_SEPARATION_ARRAY_SIZE; } else { pTexInfo->Flags.Gpu.ColorSeparation = 0; pTexInfo->Flags.Gpu.ColorSeparationRGBX = 0; } } HAlign = pTexInfo->Alignment.HAlign; VAlign = pTexInfo->Alignment.VAlign; GetCompressionBlockDimensions(pTexInfo->Format, &CompressWidth, &CompressHeight, &CompressDepth); Compress = GmmIsCompressed(pGmmLibContext, pTexInfo->Format); // Calculate Block Surface Height ///////////////////////////////// if(ExpandedArraySize > 1) { uint32_t Height0, Height1, Mip0BlockHeight, Slice0Delta = 0; Height0 = __GMM_EXPAND_HEIGHT(this, Height, VAlign, pTexInfo); Height1 = __GMM_EXPAND_HEIGHT(this, Height >> 1, VAlign, pTexInfo); Mip0BlockHeight = BlockHeight = (pTexInfo->MaxLod > 0) ? Height0 + Height1 + 12 * VAlign : Height0; BlockHeight -= (pTexInfo->Flags.Wa.CHVAstcSkipVirtualMips) ? Height0 : 0; if(pTexInfo->Flags.Gpu.S3dDx && pGmmLibContext->GetSkuTable().FtrDisplayEngineS3d) { BlockHeight = GFX_ALIGN(BlockHeight, pPlatform->TileInfo[pTexInfo->TileMode].LogicalTileHeight); } // QPitch for compressed surface must be multiple of BlockHeight and 4... if(Compress && (CompressHeight % 4)) { uint32_t LCM = CompressHeight * ((CompressHeight % 2) ? 4 : 2); BlockHeight = GFX_ALIGN_NP2(BlockHeight, LCM); Mip0BlockHeight = GFX_ALIGN_NP2(Mip0BlockHeight, LCM); } // Gen8 QPitch programming refers to the logical view, not physical. pTexInfo->Alignment.QPitch = BlockHeight; if(Compress) { BlockHeight /= CompressHeight; Mip0BlockHeight /= CompressHeight; } else if(pTexInfo->Flags.Gpu.SeparateStencil) { BlockHeight /= 2; } else if(pTexInfo->Flags.Gpu.CCS) { if(pTexInfo->Flags.Gpu.__NonMsaaTileYCcs) { BlockHeight /= 32; } else if(pTexInfo->Flags.Gpu.__NonMsaaTileXCcs) { BlockHeight /= 16; } } Slice0Delta = (pTexInfo->Flags.Wa.CHVAstcSkipVirtualMips) ? (Mip0BlockHeight - BlockHeight) : 0; BlockHeight *= ExpandedArraySize; BlockHeight += Slice0Delta; } else { pTexInfo->Alignment.QPitch = 0; BlockHeight = Get2DMipMapHeight(pTexInfo); } /////////////////////////////////// // Calculate Pitch /////////////////////////////////// AlignedWidth = __GMM_EXPAND_WIDTH(this, Width, HAlign, pTexInfo); // Calculate special pitch case of small dimensions where LOD1 + LOD2 widths // are greater than LOD0. e.g. dimensions 4x4 and MinPitch == 1 if(pTexInfo->MaxLod >= 2) { uint32_t AlignedWidthLod1, AlignedWidthLod2; AlignedWidthLod1 = __GMM_EXPAND_WIDTH(this, Width >> 1, HAlign, pTexInfo); AlignedWidthLod2 = __GMM_EXPAND_WIDTH(this, Width >> 2, HAlign, pTexInfo); if((pGmmLibContext->GetWaTable().WaAstcCorruptionForOddCompressedBlockSizeX || pTexInfo->Flags.Wa.CHVAstcSkipVirtualMips) && pPlatform->FormatTable[pTexInfo->Format].ASTC && CompressWidth == 5) { uint32_t Width1 = (Width == 1) ? 1 : (Width >> 1); uint32_t Modulo10 = Width1 % 10; if(Modulo10 >= 1 && Modulo10 <= CompressWidth) { AlignedWidthLod2 += 3 * CompressWidth; } } AlignedWidth = GFX_MAX(AlignedWidth, AlignedWidthLod1 + AlignedWidthLod2); } if(Compress) { AlignedWidth /= CompressWidth; } else if(pTexInfo->Flags.Gpu.SeparateStencil) { AlignedWidth *= 2; } else if(pTexInfo->Flags.Gpu.CCS) { if(pTexInfo->Flags.Gpu.__NonMsaaTileYCcs) { switch(pTexInfo->BitsPerPixel) { case 32: AlignedWidth /= 8; break; case 64: AlignedWidth /= 4; break; case 128: AlignedWidth /= 2; break; default: __GMM_ASSERT(0); } } else if(pTexInfo->Flags.Gpu.__NonMsaaTileXCcs) { switch(pTexInfo->BitsPerPixel) { case 32: AlignedWidth /= 16; break; case 64: AlignedWidth /= 8; break; case 128: AlignedWidth /= 4; break; default: __GMM_ASSERT(0); } } } else if(pTexInfo->Flags.Gpu.ColorSeparation) { AlignedWidth *= pTexInfo->ArraySize; __GMM_ASSERT(0 == (AlignedWidth % GMM_COLOR_SEPARATION_WIDTH_DIVISION)); AlignedWidth /= GMM_COLOR_SEPARATION_WIDTH_DIVISION; } else if(pTexInfo->Flags.Gpu.ColorSeparationRGBX) { AlignedWidth *= pTexInfo->ArraySize; __GMM_ASSERT(0 == (AlignedWidth % GMM_COLOR_SEPARATION_RGBX_WIDTH_DIVISION)); AlignedWidth /= GMM_COLOR_SEPARATION_RGBX_WIDTH_DIVISION; } // Default pitch Pitch = AlignedWidth * BitsPerPixel >> 3; // Make sure the pitch satisfy linear min pitch requirment Pitch = GFX_MAX(Pitch, pRestrictions->MinPitch); // Make sure pitch satisfy alignment restriction Pitch = GFX_ALIGN(Pitch, pRestrictions->PitchAlignment); //////////////////// // Adjust for Tiling //////////////////// if(GMM_IS_TILED(pPlatform->TileInfo[pTexInfo->TileMode])) { Pitch = GFX_ALIGN(Pitch, pPlatform->TileInfo[pTexInfo->TileMode].LogicalTileWidth); BlockHeight = GFX_ALIGN(BlockHeight, pPlatform->TileInfo[pTexInfo->TileMode].LogicalTileHeight); // If Tiled Resource or Undefined64KBSwizzle resource, align to 64KB tile size if((pTexInfo->Flags.Gpu.TiledResource || pTexInfo->Flags.Info.Undefined64KBSwizzle) && (pTexInfo->Flags.Info.TiledY)) { uint32_t ColFactor = 0, RowFactor = 0; uint32_t TRTileWidth = 0, TRTileHeight = 0; GmmGetD3DToHwTileConversion(pTexInfo, &ColFactor, &RowFactor); TRTileWidth = pPlatform->TileInfo[pTexInfo->TileMode].LogicalTileWidth * ColFactor; TRTileHeight = pPlatform->TileInfo[pTexInfo->TileMode].LogicalTileHeight * RowFactor; Pitch = GFX_ALIGN(Pitch, TRTileWidth); BlockHeight = GFX_ALIGN(BlockHeight, TRTileHeight); } } GMM_ASSERTDPF(pTexInfo->Flags.Info.LayoutBelow || !pTexInfo->Flags.Info.LayoutRight, "MIPLAYOUT_RIGHT not supported after Gen6!"); pTexInfo->Flags.Info.LayoutBelow = 1; pTexInfo->Flags.Info.LayoutRight = 0; // If a texture is YUV packed, 96, or 48 bpp then one row plus 16 bytes of // padding needs to be added. Since this will create a none pitch aligned // surface the padding is aligned to the next row if(GmmIsYUVPacked(pTexInfo->Format) || (pTexInfo->BitsPerPixel == GMM_BITS(96)) || (pTexInfo->BitsPerPixel == GMM_BITS(48))) { BlockHeight += GMM_SCANLINES(1) + GFX_CEIL_DIV(GMM_BYTES(16), Pitch); } // Align height to even row to cover for HW over-fetch BlockHeight = GFX_ALIGN(BlockHeight, __GMM_EVEN_ROW); if((Status = // <-- Note assignment. FillTexPitchAndSize( pTexInfo, Pitch, BlockHeight, pRestrictions)) == GMM_SUCCESS) { Fill2DTexOffsetAddress(pTexInfo); // Init to no-packed mips. It'll be initialized when app calls to get packed // mips. Calculate packed mips here if there's a chance apps won't call to // get packed mips. pTexInfo->Alignment.PackedMipStartLod = GMM_TILED_RESOURCE_NO_PACKED_MIPS; } if(pTexInfo->Flags.Wa.CHVAstcSkipVirtualMips) { uint32_t i = 0; uint64_t SkipMip0Tiles = 0; SkipMip0Tiles = pTexInfo->OffsetInfo.Texture2DOffsetInfo.Offset[1] / (pTexInfo->Pitch * pPlatform->TileInfo[pTexInfo->TileMode].LogicalTileHeight); SkipMip0Tiles *= pTexInfo->Pitch * pPlatform->TileInfo[pTexInfo->TileMode].LogicalTileHeight; pTexInfo->Size -= SkipMip0Tiles; for(i = 0; i <= pTexInfo->MaxLod; i++) { pTexInfo->OffsetInfo.Texture2DOffsetInfo.Offset[i] -= SkipMip0Tiles; } } GMM_DPF_EXIT; return (Status); } ///////////////////////////////////////////////////////////////////////////////////// /// Calculates the address offset for each mip map of 2D texture and store them into /// the GMM_TEXTURE_INFO for surf state programming. /// /// @param[in] pTexInfo: ptr to ::GMM_TEXTURE_INFO, /// ///////////////////////////////////////////////////////////////////////////////////// void GmmLib::GmmGen8TextureCalc::Fill2DTexOffsetAddress(GMM_TEXTURE_INFO *pTexInfo) { uint32_t i; GMM_DPF_ENTER; // QPitch: Array Element-to-Element, or Cube Face-to-Face Pitch... if((pTexInfo->ArraySize <= 1) && (pTexInfo->Type != RESOURCE_CUBE) && !(pTexInfo->Flags.Gpu.ColorSeparation || pTexInfo->Flags.Gpu.ColorSeparationRGBX)) { pTexInfo->OffsetInfo.Texture2DOffsetInfo.ArrayQPitchRender = 0; pTexInfo->OffsetInfo.Texture2DOffsetInfo.ArrayQPitchLock = 0; } else { uint32_t ArrayQPitch; uint32_t CompressHeight, CompressWidth, CompressDepth; GetCompressionBlockDimensions(pTexInfo->Format, &CompressWidth, &CompressHeight, &CompressDepth); ArrayQPitch = pTexInfo->Alignment.QPitch; if(GmmIsCompressed(pGmmLibContext, pTexInfo->Format)) { ArrayQPitch /= CompressHeight; } else if(pTexInfo->Flags.Gpu.SeparateStencil) { ArrayQPitch /= 2; } else if(pTexInfo->Flags.Gpu.CCS) { if(pTexInfo->Flags.Gpu.__NonMsaaTileYCcs) { ArrayQPitch /= 32; } else if(pTexInfo->Flags.Gpu.__NonMsaaTileXCcs) { ArrayQPitch /= 16; } } pTexInfo->OffsetInfo.Texture2DOffsetInfo.ArrayQPitchRender = ArrayQPitch * pTexInfo->Pitch; pTexInfo->OffsetInfo.Texture2DOffsetInfo.ArrayQPitchLock = ArrayQPitch * pTexInfo->Pitch; } for(i = 0; i <= pTexInfo->MaxLod; i++) { pTexInfo->OffsetInfo.Texture2DOffsetInfo.Offset[i] = Get2DTexOffsetAddressPerMip(pTexInfo, i); } GMM_DPF_EXIT; } ///////////////////////////////////////////////////////////////////////////////////// /// Allocates the 1D mip layout for surface state programming. /// /// @param[in] pTexInfo: ptr to ::GMM_TEXTURE_INFO, /// @param[in] pRestrictions: ptr to surface alignment and size restrictions /// /// @return ::GMM_STATUS ///////////////////////////////////////////////////////////////////////////////////// GMM_STATUS GMM_STDCALL GmmLib::GmmGen8TextureCalc::FillTex1D(GMM_TEXTURE_INFO * pTexInfo, __GMM_BUFFER_TYPE *pRestrictions) { return FillTex2D(pTexInfo, pRestrictions); } ///////////////////////////////////////////////////////////////////////////////////// /// Calculates the cube layout for surface state programming. /// /// @param[in] pTexInfo: ptr to ::GMM_TEXTURE_INFO, /// @param[in] pRestrictions: ptr to surface alignment and size restrictions /// /// @return ::GMM_STATUS ///////////////////////////////////////////////////////////////////////////////////// GMM_STATUS GMM_STDCALL GmmLib::GmmGen8TextureCalc::FillTexCube(GMM_TEXTURE_INFO * pTexInfo, __GMM_BUFFER_TYPE *pRestrictions) { return FillTex2D(pTexInfo, pRestrictions); } ///////////////////////////////////////////////////////////////////////////////////// /// This function does any special-case conversion from client-provided pseudo creation /// parameters to actual parameters for CCS. /// /// @param[in] pTexInfo: Reference to ::GMM_TEXTURE_INFO /// /// @return ::GMM_STATUS ///////////////////////////////////////////////////////////////////////////////////// GMM_STATUS GMM_STDCALL GmmLib::GmmGen8TextureCalc::MSAACCSUsage(GMM_TEXTURE_INFO *pTexInfo) { GMM_STATUS Status = GMM_SUCCESS; if(pTexInfo->MSAA.NumSamples > 1) // CCS for MSAA Compression { Status = MSAACompression(pTexInfo); } else // Non-MSAA CCS Use (i.e. Render Target Fast Clear) { if(!pTexInfo->Flags.Info.TiledW && ((!pTexInfo->Flags.Info.Linear) || (GMM_IS_4KB_TILE(pTexInfo->Flags) || GMM_IS_64KB_TILE(pTexInfo->Flags) || (pTexInfo->Type == RESOURCE_BUFFER && pTexInfo->Flags.Info.Linear))) && //!Yf - deprecate Yf ((pTexInfo->BitsPerPixel == 32) || (pTexInfo->BitsPerPixel == 64) || (pTexInfo->BitsPerPixel == 128))) { // For non-MSAA CCS usage, the four tables of // requirements: // (1) RT Alignment (GMM Don't Care: Occurs Naturally) // (2) ClearRect Alignment // (3) ClearRect Scaling (GMM Don't Care: GHAL3D Matter) // (4) Non-MSAA CCS Sizing // Gen8+: // Since mip-mapped and arrayed surfaces are supported, we // deal with alignment later at per mip level. Here, we set // tiling type only. TileX is not supported on Gen9+. // Pre-Gen8: // (!) For all the above, there are separate entries for // 32/64/128bpp--and then deals with PIXEL widths--Here, // though, we will unify by considering 8bpp table entries // (unlisted--i.e. do the math)--and deal with BYTE widths. // (1) RT Alignment -- The surface width and height don't // need to be padded to RT CL granularity. On HSW, all tiled // RT's will have appropriate alignment (given 4KB surface // base and no mip-map support) and appropriate padding // (due to tile padding). On BDW+, GMM uses H/VALIGN that // will guarantee the MCS RT alignment for all subresources. // (2) ClearRect Alignment -- I.e. FastClears must be done // with certain granularity: // TileY: 512 Bytes x 128 Lines // TileX: 1024 Bytes x 64 Lines // So a CCS must be sized to match that granularity (though // the RT itself need not be fully padded to that // granularity to use FastClear). // (4) Non-MSAA CCS Sizing -- CCS sizing is based on the // size of the FastClear (with granularity padding) for the // paired RT. CCS's (byte widths and heights) are scaled // down from their RT's by: // TileY: 32 x 32 // TileX: 64 x 16 // ### Example ############################################# // RT: 800x600, 32bpp, TileY // 8bpp: 3200x600 // FastClear: 3584x640 (for TileY FastClear Granularity of 512x128) // CCS: 112x20 (for TileY RT:CCS Sizing Downscale of 32x32) pTexInfo->Flags.Gpu.__NonMsaaTileYCcs = pTexInfo->Flags.Info.TiledY || pTexInfo->Flags.Info.TiledYf || pTexInfo->Flags.Info.TiledYs; pTexInfo->Flags.Gpu.__NonMsaaTileXCcs = pTexInfo->Flags.Info.TiledX; } else { GMM_ASSERTDPF(0, "Illegal CCS creation parameters!"); Status = GMM_ERROR; } } return Status; } gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/Texture/GmmGen9Texture.cpp000066400000000000000000001316321466655022700250510ustar00rootroot00000000000000/*============================================================================== Copyright(c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ============================================================================*/ #include "Internal/Common/GmmLibInc.h" ///////////////////////////////////////////////////////////////////////////////////// /// Calculates the mip offset of given LOD in 1D mip layout /// /// @param[in] pTexInfo: ptr to ::GMM_TEXTURE_INFO, /// /// @return offset value in bytes ///////////////////////////////////////////////////////////////////////////////////// GMM_GFX_SIZE_T GmmLib::GmmGen9TextureCalc::Get1DTexOffsetAddressPerMip(GMM_TEXTURE_INFO *pTexInfo, uint32_t MipLevel) { uint32_t AlignedMipWidth, MipWidth, __MipLevel; uint32_t i, HAlign; GMM_GFX_SIZE_T MipOffset = 0; uint8_t Compressed; uint32_t CompressHeight, CompressWidth, CompressDepth; GMM_DPF_ENTER; HAlign = pTexInfo->Alignment.HAlign; MipWidth = GFX_ULONG_CAST(pTexInfo->BaseWidth); __MipLevel = (pTexInfo->Flags.Info.TiledYf || GMM_IS_64KB_TILE(pTexInfo->Flags)) ? GFX_MIN(MipLevel, pTexInfo->Alignment.MipTailStartLod) : MipLevel; Compressed = GmmIsCompressed(pGmmLibContext, pTexInfo->Format); GetCompressionBlockDimensions(pTexInfo->Format, &CompressWidth, &CompressHeight, &CompressDepth); for(i = 1; i <= __MipLevel; i++) { AlignedMipWidth = __GMM_EXPAND_WIDTH(this, MipWidth, HAlign, pTexInfo); if(Compressed) { AlignedMipWidth /= CompressWidth; } MipOffset += AlignedMipWidth; MipWidth = GFX_ULONG_CAST(GmmTexGetMipWidth(pTexInfo, i)); } MipOffset *= (pTexInfo->BitsPerPixel >> 3); if((pTexInfo->Flags.Info.TiledYf || GMM_IS_64KB_TILE(pTexInfo->Flags)) && (MipLevel >= pTexInfo->Alignment.MipTailStartLod)) { MipOffset += GetMipTailByteOffset(pTexInfo, MipLevel); } GMM_DPF_EXIT; return (MipOffset); } ///////////////////////////////////////////////////////////////////////////////////// /// Calculates the address offset for each mip map of 1D texture and store them into /// the GMM_TEXTURE_INFO for surf state programming. /// /// @param[in] pTexInfo: ptr to ::GMM_TEXTURE_INFO, /// ///////////////////////////////////////////////////////////////////////////////////// void GmmLib::GmmGen9TextureCalc::Fill1DTexOffsetAddress(GMM_TEXTURE_INFO *pTexInfo) { uint32_t i; GMM_DPF_ENTER; pTexInfo->OffsetInfo.Texture2DOffsetInfo.ArrayQPitchRender = pTexInfo->OffsetInfo.Texture2DOffsetInfo.ArrayQPitchLock = pTexInfo->Alignment.QPitch * pTexInfo->BitsPerPixel >> 3; for(i = 0; i <= pTexInfo->MaxLod; i++) { pTexInfo->OffsetInfo.Texture2DOffsetInfo.Offset[i] = Get1DTexOffsetAddressPerMip(pTexInfo, i); } GMM_DPF_EXIT; } ///////////////////////////////////////////////////////////////////////////////////// /// Allocates the 1D mip layout for surface state programming. /// /// @param[in] pTexInfo: ptr to ::GMM_TEXTURE_INFO, /// @param[in] pRestrictions: ptr to surface alignment and size restrictions /// /// @return ::GMM_STATUS ///////////////////////////////////////////////////////////////////////////////////// GMM_STATUS GMM_STDCALL GmmLib::GmmGen9TextureCalc::FillTex1D(GMM_TEXTURE_INFO * pTexInfo, __GMM_BUFFER_TYPE *pRestrictions) { uint32_t ArraySize, BitsPerPixel, HAlign, i, Width, MipWidth; int64_t Size; GMM_STATUS Status = GMM_SUCCESS; uint8_t Compressed; uint32_t CompressHeight, CompressWidth, CompressDepth; GMM_DPF_ENTER; __GMM_ASSERTPTR(pTexInfo, GMM_ERROR); __GMM_ASSERTPTR(pRestrictions, GMM_ERROR); __GMM_ASSERT(pTexInfo->Flags.Info.Linear || pTexInfo->Flags.Info.TiledYf || GMM_IS_64KB_TILE(pTexInfo->Flags)); pTexInfo->Flags.Info.Linear = 1; pTexInfo->Flags.Info.TiledW = 0; pTexInfo->Flags.Info.TiledX = 0; GMM_SET_4KB_TILE(pTexInfo->Flags, 0, pGmmLibContext); const GMM_PLATFORM_INFO *pPlatform = GMM_OVERRIDE_PLATFORM_INFO(pTexInfo, pGmmLibContext); ArraySize = GFX_MAX(pTexInfo->ArraySize, 1); BitsPerPixel = pTexInfo->BitsPerPixel; HAlign = pTexInfo->Alignment.HAlign; Compressed = GmmIsCompressed(pGmmLibContext, pTexInfo->Format); GetCompressionBlockDimensions(pTexInfo->Format, &CompressWidth, &CompressHeight, &CompressDepth); if(pTexInfo->Flags.Info.TiledYf || GMM_IS_64KB_TILE(pTexInfo->Flags)) { FindMipTailStartLod(pTexInfo); } ///////////////////////////// // Calculate Surface QPitch ///////////////////////////// Width = __GMM_EXPAND_WIDTH(this, GFX_ULONG_CAST(pTexInfo->BaseWidth), HAlign, pTexInfo); MipWidth = Width; if((pTexInfo->Flags.Info.TiledYf || GMM_IS_64KB_TILE(pTexInfo->Flags)) && ((pTexInfo->Alignment.MipTailStartLod == 0) || (pTexInfo->MaxLod == 0))) { // Do nothing. Width is already aligned. } else { for(i = 1; i <= pTexInfo->MaxLod; i++) { uint32_t AlignedMipWidth; if((pTexInfo->Flags.Info.TiledYf || GMM_IS_64KB_TILE(pTexInfo->Flags)) && (i == pTexInfo->Alignment.MipTailStartLod)) { Width += pPlatform->TileInfo[pTexInfo->TileMode].LogicalTileWidth; break; } else { MipWidth = GFX_ULONG_CAST(GmmTexGetMipWidth(pTexInfo, i)); AlignedMipWidth = __GMM_EXPAND_WIDTH(this, MipWidth, HAlign, pTexInfo); if(Compressed) { AlignedMipWidth /= CompressWidth; } Width += AlignedMipWidth; } } } pTexInfo->Alignment.QPitch = GFX_ALIGN((ArraySize > 1) ? Width : 0, HAlign); // in pixels pTexInfo->Pitch = 0; /////////////////////////// // Calculate Surface Size /////////////////////////// Width *= BitsPerPixel >> 3; Size = GFX_ALIGN((uint64_t)Width * ArraySize, PAGE_SIZE); if(Size <= pPlatform->SurfaceMaxSize) { pTexInfo->Size = Size; Fill1DTexOffsetAddress(pTexInfo); } else { GMM_ASSERTDPF(0, "Surface too large!"); Status = GMM_ERROR; } ////////////////////// // Surface Alignment ////////////////////// if(!pTexInfo->Alignment.BaseAlignment || __GMM_IS_ALIGN(pRestrictions->Alignment, pTexInfo->Alignment.BaseAlignment)) { pTexInfo->Alignment.BaseAlignment = pRestrictions->Alignment; } else if(__GMM_IS_ALIGN(pTexInfo->Alignment.BaseAlignment, pRestrictions->Alignment)) { // Do nothing: pTexInfo->Alignment.BaseAlignment is properly aligned } else { pTexInfo->Alignment.BaseAlignment = pTexInfo->Alignment.BaseAlignment * pRestrictions->Alignment; GMM_ASSERTDPF(0, "Client requested alignment that is not properly aligned to HW requirements." "Alignment is going to be much higher to match both client and HW requirements.\r\n"); } GMM_DPF_EXIT; return (Status); } ///////////////////////////////////////////////////////////////////////////////////// /// Calculates height of the 2D mip layout on Gen9 /// /// @param[in] pTexInfo: ptr to ::GMM_TEXTURE_INFO, /// /// @return height of 2D mip layout ///////////////////////////////////////////////////////////////////////////////////// uint32_t GmmLib::GmmGen9TextureCalc::Get2DMipMapHeight(GMM_TEXTURE_INFO *pTexInfo) { uint32_t BlockHeight, MipHeight; uint32_t HeightLinesLevel0, HeightLinesLevel1, HeightLinesLevel2; uint32_t i, MipLevel, VAlign, CompressHeight, CompressWidth, CompressDepth; uint8_t Compressed; GMM_DPF_ENTER; const GMM_PLATFORM_INFO *pPlatform = GMM_OVERRIDE_PLATFORM_INFO(pTexInfo, pGmmLibContext); Compressed = GmmIsCompressed(pGmmLibContext, pTexInfo->Format); MipHeight = pTexInfo->BaseHeight; MipLevel = pTexInfo->MaxLod; VAlign = pTexInfo->Alignment.VAlign; GetCompressionBlockDimensions(pTexInfo->Format, &CompressWidth, &CompressHeight, &CompressDepth); HeightLinesLevel0 = __GMM_EXPAND_HEIGHT(this, MipHeight, VAlign, pTexInfo); if(Compressed) { HeightLinesLevel0 /= CompressHeight; } else if(pTexInfo->Flags.Gpu.SeparateStencil && pTexInfo->Flags.Info.TiledW) { HeightLinesLevel0 /= 2; } else if(pTexInfo->Flags.Gpu.CCS && pTexInfo->Flags.Gpu.__NonMsaaTileYCcs) { HeightLinesLevel0 /= 16; } // Mip0 height... BlockHeight = HeightLinesLevel0; if((pTexInfo->Flags.Info.TiledYf || pTexInfo->Flags.Info.TiledYs) && ((pTexInfo->Alignment.MipTailStartLod == 0) || (pTexInfo->MaxLod == 0))) { // Do nothing. Height is already aligned. } else { // Height of Mip1 and Mip2..n needed later... HeightLinesLevel1 = HeightLinesLevel2 = 0; for(i = 1; i <= MipLevel; i++) { uint32_t AlignedHeightLines; if((pTexInfo->Flags.Info.TiledYf || pTexInfo->Flags.Info.TiledYs) && (i == pTexInfo->Alignment.MipTailStartLod)) { AlignedHeightLines = pPlatform->TileInfo[pTexInfo->TileMode].LogicalTileHeight; if(i == 1) { HeightLinesLevel1 = AlignedHeightLines; } else { HeightLinesLevel2 += AlignedHeightLines; } break; } else { MipHeight = GmmTexGetMipHeight(pTexInfo, i); AlignedHeightLines = __GMM_EXPAND_HEIGHT(this, MipHeight, VAlign, pTexInfo); if(Compressed) { AlignedHeightLines /= CompressHeight; } else if(pTexInfo->Flags.Gpu.SeparateStencil && pTexInfo->Flags.Info.TiledW) { AlignedHeightLines /= 2; } else if(pTexInfo->Flags.Gpu.CCS && pTexInfo->Flags.Gpu.__NonMsaaTileYCcs) { AlignedHeightLines /= 16; } if(i == 1) { HeightLinesLevel1 = AlignedHeightLines; } else { HeightLinesLevel2 += AlignedHeightLines; } } } // If Mip1 height covers all others, then that is all we need... if(!(pTexInfo->Flags.Info.TiledYf || pTexInfo->Flags.Info.TiledYs)) { if(HeightLinesLevel1 >= HeightLinesLevel2) { BlockHeight += GFX_ALIGN(HeightLinesLevel1, VAlign); } else { BlockHeight += GFX_ALIGN(HeightLinesLevel2, VAlign); } } else { //TR mode- requires TileMode height alignment BlockHeight += (HeightLinesLevel1 >= HeightLinesLevel2) ? HeightLinesLevel1 : HeightLinesLevel2; BlockHeight = GFX_ALIGN(BlockHeight, pPlatform->TileInfo[pTexInfo->TileMode].LogicalTileHeight); } } GMM_DPF_EXIT; return (BlockHeight); } ///////////////////////////////////////////////////////////////////////////////////// /// Calculates total height of an arrayed 2D/3D mip layout /// /// @param[in] pTexInfo: ptr to ::GMM_TEXTURE_INFO, /// /// @return height of arrayed 2D/3D mip layout ///////////////////////////////////////////////////////////////////////////////////// uint32_t GmmLib::GmmGen9TextureCalc::Get2DMipMapTotalHeight(GMM_TEXTURE_INFO *pTexInfo) { uint32_t BlockHeight, MipHeight; uint32_t HeightLinesLevel0, HeightLinesLevel1, HeightLinesLevel2; uint32_t i, MipLevel, VAlign; uint32_t AlignedHeightLines; GMM_DPF_ENTER; MipHeight = pTexInfo->BaseHeight; MipLevel = pTexInfo->MaxLod; VAlign = pTexInfo->Alignment.VAlign; MipLevel = (pTexInfo->Flags.Info.TiledYf || GMM_IS_64KB_TILE(pTexInfo->Flags)) ? GFX_MIN(MipLevel, pTexInfo->Alignment.MipTailStartLod) : MipLevel; HeightLinesLevel0 = __GMM_EXPAND_HEIGHT(this, MipHeight, VAlign, pTexInfo); // Mip0 height... BlockHeight = HeightLinesLevel0; // Height of Mip1 and Mip2..n needed later... HeightLinesLevel1 = HeightLinesLevel2 = 0; for(i = 1; i <= MipLevel; i++) { MipHeight = GmmTexGetMipHeight(pTexInfo, i); AlignedHeightLines = __GMM_EXPAND_HEIGHT(this, MipHeight, VAlign, pTexInfo); if(i == 1) { HeightLinesLevel1 = AlignedHeightLines; } else { HeightLinesLevel2 += AlignedHeightLines; } } // If Mip1 height covers all others, then that is all we need... if(HeightLinesLevel1 >= HeightLinesLevel2) { BlockHeight += HeightLinesLevel1; } else { BlockHeight += HeightLinesLevel2; } GMM_DPF_EXIT; return (BlockHeight); } ///////////////////////////////////////////////////////////////////////////////////// /// Calculates the mip offset of given LOD in 2D/3D mip layout /// /// @param[in] pTexInfo: ptr to ::GMM_TEXTURE_INFO, /// /// @return ::GMM_GFX_SIZE_T offset value in bytes ///////////////////////////////////////////////////////////////////////////////////// GMM_GFX_SIZE_T GmmLib::GmmGen9TextureCalc::Get2DTexOffsetAddressPerMip(GMM_TEXTURE_INFO *pTexInfo, uint32_t MipLevel) { uint32_t AlignedMipHeight, i, OffsetHeight; uint8_t Compressed; uint32_t HAlign, VAlign, __MipLevel; uint32_t CompressHeight, CompressWidth, CompressDepth; uint32_t MipHeight; GMM_GFX_SIZE_T MipOffset; GMM_DPF_ENTER; const GMM_PLATFORM_INFO *pPlatform = GMM_OVERRIDE_PLATFORM_INFO(pTexInfo, pGmmLibContext); HAlign = pTexInfo->Alignment.HAlign; VAlign = pTexInfo->Alignment.VAlign; Compressed = GmmIsCompressed(pGmmLibContext, pTexInfo->Format); MipHeight = pTexInfo->BaseHeight; OffsetHeight = 0; GetCompressionBlockDimensions(pTexInfo->Format, &CompressWidth, &CompressHeight, &CompressDepth); __MipLevel = (pTexInfo->Flags.Info.TiledYf || GMM_IS_64KB_TILE(pTexInfo->Flags)) ? GFX_MIN(MipLevel, pTexInfo->Alignment.MipTailStartLod) : MipLevel; if(__MipLevel < 2) // LOD0 and LOD1 are on the left edge... { MipOffset = 0; } else // LOD2 and beyond are to the right of LOD1... { uint32_t MipWidth = GFX_ULONG_CAST(GmmTexGetMipWidth(pTexInfo, 1)); uint32_t BitsPerPixel = pTexInfo->BitsPerPixel; MipWidth = __GMM_EXPAND_WIDTH(this, MipWidth, HAlign, pTexInfo); if(Compressed) { MipWidth /= CompressWidth; } else if(pTexInfo->Flags.Gpu.SeparateStencil && pTexInfo->Flags.Info.TiledW) { //Expt: Stencil Row interleaving, where Rowheight = VALign=8 //XOffset on interleaved row not different than w/o interleave. //MipWidth *= 2; } else if(pTexInfo->Flags.Gpu.CCS && pTexInfo->Flags.Gpu.__NonMsaaTileYCcs) { BitsPerPixel = 8; // Aux Surfaces are 8bpp switch(pTexInfo->BitsPerPixel) { case 32: MipWidth /= 8; break; case 64: MipWidth /= 4; break; case 128: MipWidth /= 2; break; default: __GMM_ASSERT(0); } } MipOffset = (GMM_GFX_SIZE_T)MipWidth * BitsPerPixel >> 3; } for(i = 1; i <= __MipLevel; i++) { AlignedMipHeight = GFX_ULONG_CAST(__GMM_EXPAND_HEIGHT(this, MipHeight, VAlign, pTexInfo)); if(Compressed) { AlignedMipHeight /= CompressHeight; } else if(pTexInfo->Flags.Gpu.SeparateStencil && pTexInfo->Flags.Info.TiledW) { AlignedMipHeight /= 2; } else if(pTexInfo->Flags.Gpu.CCS && pTexInfo->Flags.Gpu.__NonMsaaTileYCcs) { AlignedMipHeight /= 16; } OffsetHeight += ((i != 2) ? AlignedMipHeight : 0); MipHeight = GmmTexGetMipHeight(pTexInfo, i); } OffsetHeight *= GFX_MAX(pPlatform->TileInfo[pTexInfo->TileMode].LogicalTileDepth, 1); MipOffset += OffsetHeight * GFX_ULONG_CAST(pTexInfo->Pitch); if((pTexInfo->Flags.Info.TiledYf || GMM_IS_64KB_TILE(pTexInfo->Flags)) && (MipLevel >= pTexInfo->Alignment.MipTailStartLod)) { MipOffset += GetMipTailByteOffset(pTexInfo, MipLevel); } GMM_DPF_EXIT; return (MipOffset); } ///////////////////////////////////////////////////////////////////////////////////// /// Calculates the address offset for each mip map of 2D texture and store them into /// the GMM_TEXTURE_INFO for surf state programming. /// /// @param[in] pTexInfo: ptr to ::GMM_TEXTURE_INFO, /// ///////////////////////////////////////////////////////////////////////////////////// void GmmLib::GmmGen9TextureCalc::Fill2DTexOffsetAddress(GMM_TEXTURE_INFO *pTexInfo) { uint32_t i; GMM_DPF_ENTER; const GMM_PLATFORM_INFO *pPlatform = GMM_OVERRIDE_PLATFORM_INFO(pTexInfo, pGmmLibContext); // QPitch: Array Element-to-Element, or Cube Face-to-Face Pitch... if((pTexInfo->ArraySize <= 1) && (pTexInfo->Type != RESOURCE_3D) && (pTexInfo->Type != RESOURCE_CUBE) && !(pTexInfo->Flags.Gpu.ColorSeparation || pTexInfo->Flags.Gpu.ColorSeparationRGBX)) { pTexInfo->OffsetInfo.Texture2DOffsetInfo.ArrayQPitchRender = pTexInfo->OffsetInfo.Texture2DOffsetInfo.ArrayQPitchLock = 0; } else { uint32_t ArrayQPitch, Alignment; Alignment = pTexInfo->Alignment.VAlign; if((pTexInfo->Type == RESOURCE_3D && !pTexInfo->Flags.Info.Linear) || (pTexInfo->Flags.Gpu.S3dDx && pGmmLibContext->GetSkuTable().FtrDisplayEngineS3d) || (pTexInfo->Flags.Wa.MediaPipeUsage)) { Alignment = pPlatform->TileInfo[pTexInfo->TileMode].LogicalTileHeight; //Gmm uses TileY for Stencil allocations, having half TileW height (TileY width compensates) if(pTexInfo->Flags.Gpu.SeparateStencil && pTexInfo->Flags.Info.TiledW) { Alignment *= 2; } } // Calculate the overall Block height...Mip0Height + Max(Mip1Height, Sum of Mip2Height..MipnHeight) ArrayQPitch = Get2DMipMapTotalHeight(pTexInfo); ArrayQPitch = GFX_ALIGN_NP2(ArrayQPitch, Alignment); // Color Surf with MSAA Enabled Mutiply 4 if (GMM_IS_64KB_TILE(pTexInfo->Flags) && (!pGmmLibContext->GetSkuTable().FtrTileY) && (!pGmmLibContext->GetSkuTable().FtrXe2PlusTiling) && ((pTexInfo->MSAA.NumSamples == 8) || (pTexInfo->MSAA.NumSamples == 16)) && ((pTexInfo->Flags.Gpu.Depth == 0) && (pTexInfo->Flags.Gpu.SeparateStencil == 0))) { // ArrayQPitch *= 4; /* Aligned height of 4 samples */ } pTexInfo->Alignment.QPitch = ArrayQPitch; if(GmmIsCompressed(pGmmLibContext, pTexInfo->Format)) { uint32_t CompressWidth, CompressHeight, CompressDepth; GetCompressionBlockDimensions(pTexInfo->Format, &CompressWidth, &CompressHeight, &CompressDepth); ArrayQPitch /= CompressHeight; if((pTexInfo->Type == RESOURCE_3D) && !pTexInfo->Flags.Info.Linear) { ArrayQPitch = GFX_ALIGN(ArrayQPitch, pPlatform->TileInfo[pTexInfo->TileMode].LogicalTileHeight); } } else if(pTexInfo->Flags.Gpu.SeparateStencil && pTexInfo->Flags.Info.TiledW) { ArrayQPitch /= 2; if(pTexInfo->Type == RESOURCE_3D && !pTexInfo->Flags.Info.Linear) { pTexInfo->Alignment.QPitch = ArrayQPitch; } } else if(pTexInfo->Flags.Gpu.CCS && pTexInfo->Flags.Gpu.__NonMsaaTileYCcs) { ArrayQPitch /= 16; } pTexInfo->OffsetInfo.Texture2DOffsetInfo.ArrayQPitchRender = pTexInfo->OffsetInfo.Texture2DOffsetInfo.ArrayQPitchLock = ArrayQPitch * pTexInfo->Pitch; } for(i = 0; i <= pTexInfo->MaxLod; i++) { pTexInfo->OffsetInfo.Texture2DOffsetInfo.Offset[i] = Get2DTexOffsetAddressPerMip(pTexInfo, i); } GMM_DPF_EXIT; } ///////////////////////////////////////////////////////////////////////////////////// /// Returns the aligned block height of the 3D surface on Gen9 /// /// @param[in] pTexInfo: ptr to ::GMM_TEXTURE_INFO, /// BlockHeight: Unaligned block height /// ExpandedArraySize: adjusted array size for MSAA, cube faces, etc. /// /// @return Aligned BlockHeight ///////////////////////////////////////////////////////////////////////////////////// uint32_t GmmLib::GmmGen9TextureCalc::GetAligned3DBlockHeight(GMM_TEXTURE_INFO *pTexInfo, uint32_t BlockHeight, uint32_t ExpandedArraySize) { GMM_DPF_ENTER; GMM_UNREFERENCED_PARAMETER(ExpandedArraySize); __GMM_ASSERTPTR(pTexInfo, 0); const GMM_PLATFORM_INFO *pPlatform = GMM_OVERRIDE_PLATFORM_INFO(pTexInfo, pGmmLibContext); if((pTexInfo->Type == RESOURCE_3D) && !pTexInfo->Flags.Info.Linear) { BlockHeight = GFX_ALIGN(BlockHeight, pPlatform->TileInfo[pTexInfo->TileMode].LogicalTileHeight); } GMM_DPF_EXIT; return BlockHeight; } ///////////////////////////////////////////////////////////////////////////////////// /// Allocates the 2D mip layout for surface state programming. /// /// @param[in] pTexInfo: ptr to ::GMM_TEXTURE_INFO, /// @param[in] pRestrictions: ptr to surface alignment and size restrictions /// /// @return ::GMM_STATUS ///////////////////////////////////////////////////////////////////////////////////// GMM_STATUS GMM_STDCALL GmmLib::GmmGen9TextureCalc::FillTex2D(GMM_TEXTURE_INFO * pTexInfo, __GMM_BUFFER_TYPE *pRestrictions) { uint32_t Width, Height, BitsPerPixel; uint32_t HAlign, VAlign, DAlign, CompressHeight, CompressWidth, CompressDepth; uint32_t AlignedWidth, BlockHeight, ExpandedArraySize, Pitch; uint8_t Compress = 0; GMM_STATUS Status; GMM_DPF_ENTER; __GMM_ASSERTPTR(pTexInfo, GMM_ERROR); __GMM_ASSERTPTR(pRestrictions, GMM_ERROR); const GMM_PLATFORM_INFO *pPlatform = GMM_OVERRIDE_PLATFORM_INFO(pTexInfo, pGmmLibContext); BitsPerPixel = pTexInfo->BitsPerPixel; if(pTexInfo->Flags.Gpu.CCS && pTexInfo->Flags.Gpu.__NonMsaaTileYCcs) { // Aux Surfaces are 8bpp. BitsPerPixel = 8; } Height = pTexInfo->BaseHeight; Width = GFX_ULONG_CAST(pTexInfo->BaseWidth); pTexInfo->MSAA.NumSamples = GFX_MAX(pTexInfo->MSAA.NumSamples, 1); if(pTexInfo->Flags.Info.TiledYf || pTexInfo->Flags.Info.TiledYs) { FindMipTailStartLod(pTexInfo); } ExpandedArraySize = GFX_MAX(pTexInfo->ArraySize, 1) * ((pTexInfo->Type == RESOURCE_CUBE) ? 6 : 1) * // Cubemaps simply 6-element, 2D arrays. ((pTexInfo->Type == RESOURCE_3D) ? pTexInfo->Depth : 1) * // 3D's simply 2D arrays. ((pTexInfo->Flags.Gpu.Depth || pTexInfo->Flags.Gpu.SeparateStencil || (pTexInfo->Flags.Info.TiledYs || pTexInfo->Flags.Info.TiledYf)) ? // MSAA Ys samples are NOT stored as array planes. 1 : pTexInfo->MSAA.NumSamples); // MSAA (non-Depth/Stencil) RT samples stored as array planes. if(pTexInfo->Flags.Info.TiledYs || pTexInfo->Flags.Info.TiledYf) { ExpandedArraySize = GFX_CEIL_DIV(ExpandedArraySize, pPlatform->TileInfo[pTexInfo->TileMode].LogicalTileDepth); } // // Check for color separation // if(pTexInfo->Flags.Gpu.ColorSeparation || pTexInfo->Flags.Gpu.ColorSeparationRGBX) { bool csRestrictionsMet = (((ExpandedArraySize <= 2) && (ExpandedArraySize == pTexInfo->ArraySize) && ((pTexInfo->Format == GMM_FORMAT_R8G8B8A8_UNORM) || (pTexInfo->Format == GMM_FORMAT_R8G8B8A8_UNORM_SRGB) || (pTexInfo->Format == GMM_FORMAT_B8G8R8A8_UNORM) || (pTexInfo->Format == GMM_FORMAT_B8G8R8A8_UNORM_SRGB) || (pTexInfo->Format == GMM_FORMAT_B8G8R8X8_UNORM) || (pTexInfo->Format == GMM_FORMAT_B8G8R8X8_UNORM_SRGB)) && ((pTexInfo->Flags.Gpu.ColorSeparation && (Width % 16) == 0) || (pTexInfo->Flags.Gpu.ColorSeparationRGBX && (Width % 12) == 0)))); if(csRestrictionsMet) { ExpandedArraySize = GMM_COLOR_SEPARATION_ARRAY_SIZE; } else { pTexInfo->Flags.Gpu.ColorSeparation = false; pTexInfo->Flags.Gpu.ColorSeparationRGBX = false; } } HAlign = pTexInfo->Alignment.HAlign; VAlign = pTexInfo->Alignment.VAlign; DAlign = pTexInfo->Alignment.DAlign; GetCompressionBlockDimensions(pTexInfo->Format, &CompressWidth, &CompressHeight, &CompressDepth); Compress = GmmIsCompressed(pGmmLibContext, pTexInfo->Format); ///////////////////////////////// // Calculate Block Surface Height ///////////////////////////////// if(ExpandedArraySize > 1) { uint32_t Alignment = VAlign; if((pTexInfo->Type == RESOURCE_3D && !pTexInfo->Flags.Info.Linear) || (pTexInfo->Flags.Gpu.S3dDx && pGmmLibContext->GetSkuTable().FtrDisplayEngineS3d) || (pTexInfo->Flags.Wa.MediaPipeUsage)) { Alignment = pPlatform->TileInfo[pTexInfo->TileMode].LogicalTileHeight; //Gmm uses TileY for Stencil allocations, having half TileW height (TileY width compensates) if(pTexInfo->Flags.Gpu.SeparateStencil && pTexInfo->Flags.Info.TiledW) { Alignment *= 2; } } // Calculate the overall Block height...Mip0Height + Max(Mip1Height, Sum of Mip2Height..MipnHeight) BlockHeight = Get2DMipMapTotalHeight(pTexInfo); BlockHeight = GFX_ALIGN_NP2(BlockHeight, Alignment); // GMM internally uses QPitch as the logical distance between slices, but translates // as appropriate to service client queries in GmmResGetQPitch. pTexInfo->Alignment.QPitch = BlockHeight; if(Compress) { BlockHeight = GFX_CEIL_DIV(BlockHeight, CompressHeight); BlockHeight = GetAligned3DBlockHeight(pTexInfo, BlockHeight, ExpandedArraySize); } else if(pTexInfo->Flags.Gpu.SeparateStencil && pTexInfo->Flags.Info.TiledW) { BlockHeight /= 2; } else if(pTexInfo->Flags.Gpu.CCS && pTexInfo->Flags.Gpu.__NonMsaaTileYCcs) { BlockHeight /= 16; } BlockHeight *= ExpandedArraySize; } else { pTexInfo->Alignment.QPitch = 0; BlockHeight = Get2DMipMapHeight(pTexInfo); } /////////////////////////////////// // Calculate Pitch /////////////////////////////////// AlignedWidth = __GMM_EXPAND_WIDTH(this, Width, HAlign, pTexInfo); // Calculate special pitch case of small dimensions where LOD1 + LOD2 widths // are greater than LOD0. e.g. dimensions 4x4 and MinPitch == 1 if((pTexInfo->Flags.Info.TiledYf || pTexInfo->Flags.Info.TiledYs) && (pTexInfo->Alignment.MipTailStartLod < 2)) { // Do nothing -- all mips are in LOD0/LOD1, which is already width aligned. } else if(pTexInfo->MaxLod >= 2) { uint32_t AlignedWidthLod1, AlignedWidthLod2; AlignedWidthLod1 = __GMM_EXPAND_WIDTH(this, Width >> 1, HAlign, pTexInfo); AlignedWidthLod2 = __GMM_EXPAND_WIDTH(this, Width >> 2, HAlign, pTexInfo); AlignedWidth = GFX_MAX(AlignedWidth, AlignedWidthLod1 + AlignedWidthLod2); } if(Compress) { AlignedWidth = GFX_CEIL_DIV(AlignedWidth, CompressWidth); } else if(pTexInfo->Flags.Gpu.SeparateStencil && pTexInfo->Flags.Info.TiledW) { AlignedWidth *= 2; } else if(pTexInfo->Flags.Gpu.CCS && pTexInfo->Flags.Gpu.__NonMsaaTileYCcs) { switch(pTexInfo->BitsPerPixel) { case 32: AlignedWidth /= 8; break; case 64: AlignedWidth /= 4; break; case 128: AlignedWidth /= 2; break; default: __GMM_ASSERT(0); } } else if(pTexInfo->Flags.Gpu.ColorSeparation) { AlignedWidth *= pTexInfo->ArraySize; __GMM_ASSERT(0 == (AlignedWidth % GMM_COLOR_SEPARATION_WIDTH_DIVISION)); AlignedWidth /= GMM_COLOR_SEPARATION_WIDTH_DIVISION; } else if(pTexInfo->Flags.Gpu.ColorSeparationRGBX) { AlignedWidth *= pTexInfo->ArraySize; __GMM_ASSERT(0 == (AlignedWidth % GMM_COLOR_SEPARATION_RGBX_WIDTH_DIVISION)); AlignedWidth /= GMM_COLOR_SEPARATION_RGBX_WIDTH_DIVISION; } // Default pitch Pitch = AlignedWidth * BitsPerPixel >> 3; // Make sure the pitch satisfy linear min pitch requirment Pitch = GFX_MAX(Pitch, pRestrictions->MinPitch); // Make sure pitch satisfy alignment restriction Pitch = GFX_ALIGN(Pitch, pRestrictions->PitchAlignment); //////////////////// // Adjust for Tiling //////////////////// if(GMM_IS_TILED(pPlatform->TileInfo[pTexInfo->TileMode])) { Pitch = GFX_ALIGN(Pitch, pPlatform->TileInfo[pTexInfo->TileMode].LogicalTileWidth); BlockHeight = GFX_ALIGN(BlockHeight, pPlatform->TileInfo[pTexInfo->TileMode].LogicalTileHeight); } GMM_ASSERTDPF(pTexInfo->Flags.Info.LayoutBelow || !pTexInfo->Flags.Info.LayoutRight, "MIPLAYOUT_RIGHT not supported after Gen6!"); pTexInfo->Flags.Info.LayoutBelow = 1; pTexInfo->Flags.Info.LayoutRight = 0; // If a texture is YUV packed, 96, or 48 bpp then one row plus 16 bytes of // padding needs to be added. Since this will create a none pitch aligned // surface the padding is aligned to the next row if(GmmIsYUVPacked(pTexInfo->Format) || (pTexInfo->BitsPerPixel == GMM_BITS(96)) || (pTexInfo->BitsPerPixel == GMM_BITS(48))) { BlockHeight += GMM_SCANLINES(1) + GFX_CEIL_DIV(GMM_BYTES(16), Pitch); } // Align height to even row to cover for HW over-fetch BlockHeight = GFX_ALIGN(BlockHeight, __GMM_EVEN_ROW); if((Status = // <-- Note assignment. FillTexPitchAndSize( pTexInfo, Pitch, BlockHeight, pRestrictions)) == GMM_SUCCESS) { Fill2DTexOffsetAddress(pTexInfo); } GMM_DPF_EXIT; return (Status); } ///////////////////////////////////////////////////////////////////////////////////// /// Returns the mip offset of given LOD in Mip Tail /// /// @param[in] pTexInfo: ptr to ::GMM_TEXTURE_INFO, /// MipLevel: given LOD # /// /// @return offset value of LOD in bytes ///////////////////////////////////////////////////////////////////////////////////// uint32_t GmmLib::GmmGen9TextureCalc::GetMipTailByteOffset(GMM_TEXTURE_INFO *pTexInfo, uint32_t MipLevel) { uint32_t ByteOffset = 0, Slot; GMM_DPF_ENTER; if((pTexInfo->Type == RESOURCE_1D) || (pTexInfo->Type == RESOURCE_3D)) { Slot = MipLevel - pTexInfo->Alignment.MipTailStartLod + (pTexInfo->Flags.Info.TiledYf ? 4 : 0); switch(Slot) { case 0: ByteOffset = GMM_KBYTE(32); break; case 1: ByteOffset = GMM_KBYTE(16); break; case 2: ByteOffset = GMM_KBYTE(8); break; case 3: ByteOffset = GMM_KBYTE(4); break; case 4: ByteOffset = GMM_KBYTE(2); break; case 5: ByteOffset = GMM_KBYTE(1); break; case 6: ByteOffset = GMM_BYTES(768); break; case 7: ByteOffset = GMM_BYTES(512); break; case 8: ByteOffset = GMM_BYTES(448); break; case 9: ByteOffset = GMM_BYTES(384); break; case 10: ByteOffset = GMM_BYTES(320); break; case 11: ByteOffset = GMM_BYTES(256); break; case 12: ByteOffset = GMM_BYTES(192); break; case 13: ByteOffset = GMM_BYTES(128); break; case 14: ByteOffset = GMM_BYTES(64); break; case 15: ByteOffset = GMM_BYTES(0); break; default: __GMM_ASSERT(0); } } else if(pTexInfo->Type == RESOURCE_2D || pTexInfo->Type == RESOURCE_CUBE) { // clang-format off Slot = MipLevel - pTexInfo->Alignment.MipTailStartLod + // TileYs ((pTexInfo->Flags.Info.TiledYs && pTexInfo->MSAA.NumSamples == 16) ? 4 : (pTexInfo->Flags.Info.TiledYs && pTexInfo->MSAA.NumSamples == 8) ? 3 : (pTexInfo->Flags.Info.TiledYs && pTexInfo->MSAA.NumSamples == 4) ? 2 : (pTexInfo->Flags.Info.TiledYs && pTexInfo->MSAA.NumSamples == 2) ? 1 : (pTexInfo->Flags.Info.TiledYs ) ? 0 : // TileYf (pTexInfo->Flags.Info.TiledYf ) ? 4: 0); // clang-format on switch(Slot) { case 0: ByteOffset = GMM_KBYTE(32); break; case 1: ByteOffset = GMM_KBYTE(16); break; case 2: ByteOffset = GMM_KBYTE(8); break; case 3: ByteOffset = GMM_KBYTE(4); break; case 4: ByteOffset = GMM_KBYTE(2); break; case 5: ByteOffset = GMM_BYTES(1536); break; case 6: ByteOffset = GMM_BYTES(1280); break; case 7: ByteOffset = GMM_BYTES(1024); break; case 8: ByteOffset = GMM_BYTES(768); break; case 9: ByteOffset = GMM_BYTES(512); break; case 10: ByteOffset = GMM_BYTES(256); break; case 11: ByteOffset = GMM_BYTES(192); break; case 12: ByteOffset = GMM_BYTES(128); break; case 13: ByteOffset = GMM_BYTES(64); break; case 14: ByteOffset = GMM_BYTES(0); break; default: __GMM_ASSERT(0); } } GMM_DPF_EXIT; return (ByteOffset); } GMM_MIPTAIL_SLOT_OFFSET Gen9MipTailSlotOffset1DSurface[16][5] = GEN9_MIPTAIL_SLOT_OFFSET_1D_SURFACE; GMM_MIPTAIL_SLOT_OFFSET Gen9MipTailSlotOffset2DSurface[15][5] = GEN9_MIPTAIL_SLOT_OFFSET_2D_SURFACE; GMM_MIPTAIL_SLOT_OFFSET Gen9MipTailSlotOffset3DSurface[16][5] = GEN9_MIPTAIL_SLOT_OFFSET_3D_SURFACE; ///////////////////////////////////////////////////////////////////////////////////// /// Returns the mip-map offset in geometric OffsetX, Y, Z // for a given LOD in Mip Tail. /// /// @param[in] pTexInfo: ptr to ::GMM_TEXTURE_INFO, /// MipLevel: mip-map level /// OffsetX: ptr to Offset in X direction (in bytes) /// OffsetY: ptr to Offset in Y direction (in pixels) /// OffsetZ: ptr to Offset in Z direction (in pixels) /// ///////////////////////////////////////////////////////////////////////////////////// void GmmLib::GmmGen9TextureCalc::GetMipTailGeometryOffset(GMM_TEXTURE_INFO *pTexInfo, uint32_t MipLevel, uint32_t * OffsetX, uint32_t * OffsetY, uint32_t * OffsetZ) { uint32_t ArrayIndex = 0; uint32_t Slot = 0; GMM_DPF_ENTER; switch(pTexInfo->BitsPerPixel) { case 128: ArrayIndex = 0; break; case 64: ArrayIndex = 1; break; case 32: ArrayIndex = 2; break; case 16: ArrayIndex = 3; break; case 8: ArrayIndex = 4; break; default: __GMM_ASSERT(0); break; } if(pTexInfo->Type == RESOURCE_1D) { Slot = MipLevel - pTexInfo->Alignment.MipTailStartLod + (pTexInfo->Flags.Info.TiledYf ? 4 : 0); *OffsetX = Gen9MipTailSlotOffset1DSurface[Slot][ArrayIndex].X * pTexInfo->BitsPerPixel / 8; *OffsetY = Gen9MipTailSlotOffset1DSurface[Slot][ArrayIndex].Y; *OffsetZ = Gen9MipTailSlotOffset1DSurface[Slot][ArrayIndex].Z; } else if(pTexInfo->Type == RESOURCE_2D || pTexInfo->Type == RESOURCE_CUBE) { // clang-format off Slot = MipLevel - pTexInfo->Alignment.MipTailStartLod + // TileYs ((pTexInfo->Flags.Info.TiledYs && pTexInfo->MSAA.NumSamples == 16) ? 4 : (pTexInfo->Flags.Info.TiledYs && pTexInfo->MSAA.NumSamples == 8) ? 3 : (pTexInfo->Flags.Info.TiledYs && pTexInfo->MSAA.NumSamples == 4) ? 2 : (pTexInfo->Flags.Info.TiledYs && pTexInfo->MSAA.NumSamples == 2) ? 1 : (pTexInfo->Flags.Info.TiledYs ) ? 0 : // TileYf (pTexInfo->Flags.Info.TiledYf ) ? 4: 0); // clang-format on *OffsetX = Gen9MipTailSlotOffset2DSurface[Slot][ArrayIndex].X * pTexInfo->BitsPerPixel / 8; *OffsetY = Gen9MipTailSlotOffset2DSurface[Slot][ArrayIndex].Y; *OffsetZ = Gen9MipTailSlotOffset2DSurface[Slot][ArrayIndex].Z; } else if(pTexInfo->Type == RESOURCE_3D) { Slot = MipLevel - pTexInfo->Alignment.MipTailStartLod + (pTexInfo->Flags.Info.TiledYf ? 4 : 0); *OffsetX = Gen9MipTailSlotOffset3DSurface[Slot][ArrayIndex].X * pTexInfo->BitsPerPixel / 8; *OffsetY = Gen9MipTailSlotOffset3DSurface[Slot][ArrayIndex].Y; *OffsetZ = Gen9MipTailSlotOffset3DSurface[Slot][ArrayIndex].Z; } GMM_DPF_EXIT; return; } ///////////////////////////////////////////////////////////////////////////////////// /// Allocates the 3D mip layout for surface state programming. /// /// @param[in] pTexInfo: ptr to ::GMM_TEXTURE_INFO, /// @param[in] pRestrictions: ptr to surface alignment and size restrictions /// /// @return ::GMM_STATUS ///////////////////////////////////////////////////////////////////////////////////// GMM_STATUS GMM_STDCALL GmmLib::GmmGen9TextureCalc::FillTex3D(GMM_TEXTURE_INFO * pTexInfo, __GMM_BUFFER_TYPE *pRestrictions) { return FillTex2D(pTexInfo, pRestrictions); } ///////////////////////////////////////////////////////////////////////////////////// /// Calculates the cube layout for surface state programming. /// /// @param[in] pTexInfo: ptr to ::GMM_TEXTURE_INFO, /// @param[in] pRestrictions: ptr to surface alignment and size restrictions /// /// @return ::GMM_STATUS ///////////////////////////////////////////////////////////////////////////////////// GMM_STATUS GMM_STDCALL GmmLib::GmmGen9TextureCalc::FillTexCube(GMM_TEXTURE_INFO * pTexInfo, __GMM_BUFFER_TYPE *pRestrictions) { return FillTex2D(pTexInfo, pRestrictions); } ///////////////////////////////////////////////////////////////////////////////////// /// This function does any special-case conversion from client-provided pseudo creation /// parameters to actual parameters for CCS. /// /// @param[in] pTexInfo: Reference to ::GMM_TEXTURE_INFO /// /// @return ::GMM_STATUS ///////////////////////////////////////////////////////////////////////////////////// GMM_STATUS GMM_STDCALL GmmLib::GmmGen9TextureCalc::MSAACCSUsage(GMM_TEXTURE_INFO *pTexInfo) { GMM_STATUS Status = GMM_SUCCESS; if(pTexInfo->MSAA.NumSamples > 1) // CCS for MSAA Compression { Status = MSAACompression(pTexInfo); } else // Non-MSAA CCS Use (i.e. Render Target Fast Clear) { if(!pTexInfo->Flags.Info.TiledW && (!pTexInfo->Flags.Info.TiledX) && ((!pTexInfo->Flags.Info.Linear) || (GMM_IS_4KB_TILE(pTexInfo->Flags) || GMM_IS_64KB_TILE(pTexInfo->Flags) || (pTexInfo->Type == RESOURCE_BUFFER && pTexInfo->Flags.Info.Linear))) && //!Yf - deprecate Yf ((pTexInfo->BitsPerPixel == 32) || (pTexInfo->BitsPerPixel == 64) || (pTexInfo->BitsPerPixel == 128))) { // For non-MSAA CCS usage, the four tables of // requirements: // (1) RT Alignment (GMM Don't Care: Occurs Naturally) // (2) ClearRect Alignment // (3) ClearRect Scaling (GMM Don't Care: GHAL3D Matter) // (4) Non-MSAA CCS Sizing // Gen8+: // Since mip-mapped and arrayed surfaces are supported, we // deal with alignment later at per mip level. Here, we set // tiling type only. TileX is not supported on Gen9+. // Pre-Gen8: // (!) For all the above, there are separate entries for // 32/64/128bpp--and then deals with PIXEL widths--Here, // though, we will unify by considering 8bpp table entries // (unlisted--i.e. do the math)--and deal with BYTE widths. // (1) RT Alignment -- The surface width and height don't // need to be padded to RT CL granularity. On HSW, all tiled // RT's will have appropriate alignment (given 4KB surface // base and no mip-map support) and appropriate padding // (due to tile padding). On BDW+, GMM uses H/VALIGN that // will guarantee the MCS RT alignment for all subresources. // (2) ClearRect Alignment -- I.e. FastClears must be done // with certain granularity: // TileY: 512 Bytes x 128 Lines // TileX: 1024 Bytes x 64 Lines // So a CCS must be sized to match that granularity (though // the RT itself need not be fully padded to that // granularity to use FastClear). // (4) Non-MSAA CCS Sizing -- CCS sizing is based on the // size of the FastClear (with granularity padding) for the // paired RT. CCS's (byte widths and heights) are scaled // down from their RT's by: // TileY: 32 x 32 // TileX: 64 x 16 // ### Example ############################################# // RT: 800x600, 32bpp, TileY // 8bpp: 3200x600 // FastClear: 3584x640 (for TileY FastClear Granularity of 512x128) // CCS: 112x20 (for TileY RT:CCS Sizing Downscale of 32x32) pTexInfo->Flags.Gpu.__NonMsaaTileYCcs = pTexInfo->Flags.Info.TiledY || pTexInfo->Flags.Info.TiledYf || pTexInfo->Flags.Info.TiledYs; pTexInfo->Flags.Gpu.__NonMsaaTileXCcs = pTexInfo->Flags.Info.TiledX; } else { GMM_ASSERTDPF(0, "Illegal CCS creation parameters!"); Status = GMM_ERROR; } } return Status; } gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/Texture/GmmTexture.cpp000066400000000000000000000775761466655022700243460ustar00rootroot00000000000000/*============================================================================== Copyright(c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ============================================================================*/ #include "Internal/Common/GmmLibInc.h" ///////////////////////////////////////////////////////////////////////////////////// /// This function calculates the (X,Y) address of each given plane. X is in bytes /// and Y is in scanlines. /// /// @param[in] pTexInfo: ptr to ::GMM_TEXTURE_INFO /// ///////////////////////////////////////////////////////////////////////////////////// void GmmLib::GmmTextureCalc::FillPlanarOffsetAddress(GMM_TEXTURE_INFO *pTexInfo) { GMM_GFX_SIZE_T *pUOffsetX, *pUOffsetY; GMM_GFX_SIZE_T *pVOffsetX, *pVOffsetY; uint32_t YHeight = 0, VHeight = 0; bool UVPacked = false; uint32_t Height; uint32_t WidthBytesPhysical = GFX_ULONG_CAST(pTexInfo->BaseWidth) * pTexInfo->BitsPerPixel >> 3; #define SWAP_UV() \ { \ GMM_GFX_SIZE_T *pTemp; \ \ pTemp = pUOffsetX; \ pUOffsetX = pVOffsetX; \ pVOffsetX = pTemp; \ \ pTemp = pUOffsetY; \ pUOffsetY = pVOffsetY; \ pVOffsetY = pTemp; \ } __GMM_ASSERTPTR(pTexInfo, VOIDRETURN); __GMM_ASSERTPTR(((pTexInfo->TileMode < GMM_TILE_MODES) && (pTexInfo->TileMode >= TILE_NONE)), VOIDRETURN); GMM_DPF_ENTER; const GMM_PLATFORM_INFO *pPlatform = GMM_OVERRIDE_PLATFORM_INFO(pTexInfo, pGmmLibContext); // GMM_PLANE_Y always at (0, 0)... pTexInfo->OffsetInfo.Plane.X[GMM_PLANE_Y] = 0; pTexInfo->OffsetInfo.Plane.Y[GMM_PLANE_Y] = 0; Height = pTexInfo->BaseHeight; if(pTexInfo->Flags.Gpu.__NonMsaaTileYCcs) { Height = __GMM_EXPAND_HEIGHT(this, Height, pTexInfo->Alignment.VAlign, pTexInfo); Height = ScaleTextureHeight(pTexInfo, Height); if(pTexInfo->Flags.Gpu.UnifiedAuxSurface) { pTexInfo->OffsetInfo.Plane.Y[GMM_PLANE_Y] = 0; } } // GMM_PLANE_U/V Planes... pUOffsetX = &pTexInfo->OffsetInfo.Plane.X[GMM_PLANE_U]; pUOffsetY = &pTexInfo->OffsetInfo.Plane.Y[GMM_PLANE_U]; pVOffsetX = &pTexInfo->OffsetInfo.Plane.X[GMM_PLANE_V]; pVOffsetY = &pTexInfo->OffsetInfo.Plane.Y[GMM_PLANE_V]; switch(pTexInfo->Format) { case GMM_FORMAT_IMC1: SWAP_UV(); // IMC1 = IMC3 with Swapped U/V case GMM_FORMAT_IMC3: case GMM_FORMAT_MFX_JPEG_YUV420: // Same as IMC3. // YYYYYYYY // YYYYYYYY // YYYYYYYY // YYYYYYYY // UUUU // UUUU // VVVV // VVVV case GMM_FORMAT_MFX_JPEG_YUV422V: // Similar to IMC3 but U/V are full width. // YYYYYYYY // YYYYYYYY // YYYYYYYY // YYYYYYYY // UUUUUUUU // UUUUUUUU // VVVVVVVV // VVVVVVVV { *pUOffsetX = 0; YHeight = GFX_ALIGN(pTexInfo->BaseHeight, GMM_IMCx_PLANE_ROW_ALIGNMENT); *pUOffsetY = GFX_ALIGN(pTexInfo->BaseHeight, GMM_IMCx_PLANE_ROW_ALIGNMENT); *pVOffsetX = 0; VHeight = GFX_ALIGN(GFX_CEIL_DIV(pTexInfo->BaseHeight, 2), GMM_IMCx_PLANE_ROW_ALIGNMENT); *pVOffsetY = GFX_ALIGN(pTexInfo->BaseHeight, GMM_IMCx_PLANE_ROW_ALIGNMENT) + GFX_ALIGN(GFX_CEIL_DIV(pTexInfo->BaseHeight, 2), GMM_IMCx_PLANE_ROW_ALIGNMENT); break; } case GMM_FORMAT_MFX_JPEG_YUV411R_TYPE: //Similar to IMC3 but U/V are quarther height and full width. //YYYYYYYY //YYYYYYYY //YYYYYYYY //YYYYYYYY //UUUUUUUU //VVVVVVVV { *pUOffsetX = 0; YHeight = GFX_ALIGN(pTexInfo->BaseHeight, GMM_IMCx_PLANE_ROW_ALIGNMENT); *pUOffsetY = GFX_ALIGN(pTexInfo->BaseHeight, GMM_IMCx_PLANE_ROW_ALIGNMENT); *pVOffsetX = 0; VHeight = GFX_ALIGN(GFX_CEIL_DIV(pTexInfo->BaseHeight, 4), GMM_IMCx_PLANE_ROW_ALIGNMENT); *pVOffsetY = GFX_ALIGN(pTexInfo->BaseHeight, GMM_IMCx_PLANE_ROW_ALIGNMENT) + GFX_ALIGN(GFX_CEIL_DIV(pTexInfo->BaseHeight, 4), GMM_IMCx_PLANE_ROW_ALIGNMENT); break; } case GMM_FORMAT_MFX_JPEG_YUV411: // Similar to IMC3 but U/V are quarter width and full height. // YYYYYYYY // YYYYYYYY // YYYYYYYY // YYYYYYYY // UU // UU // UU // UU // VV // VV // VV // VV case GMM_FORMAT_MFX_JPEG_YUV422H: // Similar to IMC3 but U/V are full height. // YYYYYYYY // YYYYYYYY // YYYYYYYY // YYYYYYYY // UUUU // UUUU // UUUU // UUUU // VVVV // VVVV // VVVV // VVVV case GMM_FORMAT_MFX_JPEG_YUV444: // Similar to IMC3 but U/V are full size. // YYYYYYYY // YYYYYYYY // YYYYYYYY // YYYYYYYY // UUUUUUUU // UUUUUUUU // UUUUUUUU // UUUUUUUU // VVVVVVVV // VVVVVVVV // VVVVVVVV // VVVVVVVV { *pUOffsetX = 0; YHeight = GFX_ALIGN(pTexInfo->BaseHeight, GMM_IMCx_PLANE_ROW_ALIGNMENT); *pUOffsetY = GFX_ALIGN(pTexInfo->BaseHeight, GMM_IMCx_PLANE_ROW_ALIGNMENT); *pVOffsetX = 0; VHeight = GFX_ALIGN(pTexInfo->BaseHeight, GMM_IMCx_PLANE_ROW_ALIGNMENT); *pVOffsetY = GFX_ALIGN(pTexInfo->BaseHeight, GMM_IMCx_PLANE_ROW_ALIGNMENT) * 2; break; } case GMM_FORMAT_BGRP: case GMM_FORMAT_RGBP: { //For RGBP linear Tile keep resource Offset non aligned and for other Tile format to be 16-bit aligned if(pTexInfo->Flags.Info.Linear) { *pUOffsetX = 0; YHeight = pTexInfo->BaseHeight; *pUOffsetY = pTexInfo->BaseHeight; *pVOffsetX = 0; VHeight = pTexInfo->BaseHeight; *pVOffsetY = (GMM_GFX_SIZE_T)pTexInfo->BaseHeight * 2; } else // Tiled { *pUOffsetX = 0; YHeight = GFX_ALIGN(pTexInfo->BaseHeight, GMM_IMCx_PLANE_ROW_ALIGNMENT); *pUOffsetY = GFX_ALIGN(pTexInfo->BaseHeight, GMM_IMCx_PLANE_ROW_ALIGNMENT); *pVOffsetX = 0; VHeight = GFX_ALIGN(pTexInfo->BaseHeight, GMM_IMCx_PLANE_ROW_ALIGNMENT); *pVOffsetY = (GMM_GFX_SIZE_T)GFX_ALIGN(pTexInfo->BaseHeight, GMM_IMCx_PLANE_ROW_ALIGNMENT) * 2; } break; } case GMM_FORMAT_IMC2: SWAP_UV(); // IMC2 = IMC4 with Swapped U/V case GMM_FORMAT_IMC4: { // YYYYYYYY // YYYYYYYY // YYYYYYYY // YYYYYYYY // UUUUVVVV // UUUUVVVV __GMM_ASSERT((pTexInfo->Pitch & 1) == 0); *pUOffsetX = 0; YHeight = GFX_ALIGN(pTexInfo->BaseHeight, GMM_IMCx_PLANE_ROW_ALIGNMENT); *pUOffsetY = GFX_ALIGN(pTexInfo->BaseHeight, GMM_IMCx_PLANE_ROW_ALIGNMENT); *pVOffsetX = pTexInfo->Pitch / 2; VHeight = GFX_CEIL_DIV(YHeight, 2); *pVOffsetY = GFX_ALIGN(pTexInfo->BaseHeight, GMM_IMCx_PLANE_ROW_ALIGNMENT); // Not technically UV packed but sizing works out the same UVPacked = true; break; } case GMM_FORMAT_I420: // I420 = IYUV case GMM_FORMAT_IYUV: SWAP_UV(); // I420/IYUV = YV12 with Swapped U/V case GMM_FORMAT_YV12: case GMM_FORMAT_YVU9: { // YYYYYYYY // YYYYYYYY // YYYYYYYY // YYYYYYYY // VVVVVV.. <-- V and U planes follow the Y plane, as linear // ..UUUUUU arrays--without respect to pitch. uint32_t YSize, YVSizeRShift, VSize, UOffset; uint32_t YSizeForUVPurposes, YSizeForUVPurposesDimensionalAlignment; YSize = GFX_ULONG_CAST(pTexInfo->Pitch) * pTexInfo->BaseHeight; // YVU9 has one U/V pixel for each 4x4 Y block. // The others have one U/V pixel for each 2x2 Y block. // YVU9 has a Y:V size ratio of 16 (4x4 --> 1). // The others have a ratio of 4 (2x2 --> 1). YVSizeRShift = (pTexInfo->Format != GMM_FORMAT_YVU9) ? 2 : 4; // If a Y plane isn't fully-aligned to its Y-->U/V block size, the // extra/unaligned Y pixels still need corresponding U/V pixels--So // for the purpose of computing the UVSize, we must consider a // dimensionally "rounded-up" YSize. (E.g. a 13x5 YVU9 Y plane would // require 4x2 U/V planes--the same UVSize as a fully-aligned 16x8 Y.) YSizeForUVPurposesDimensionalAlignment = (pTexInfo->Format != GMM_FORMAT_YVU9) ? 2 : 4; YSizeForUVPurposes = GFX_ALIGN(GFX_ULONG_CAST(pTexInfo->Pitch), YSizeForUVPurposesDimensionalAlignment) * GFX_ALIGN(pTexInfo->BaseHeight, YSizeForUVPurposesDimensionalAlignment); VSize = (YSizeForUVPurposes >> YVSizeRShift); UOffset = YSize + VSize; *pVOffsetX = 0; *pVOffsetY = pTexInfo->BaseHeight; *pUOffsetX = UOffset % pTexInfo->Pitch; *pUOffsetY = UOffset / pTexInfo->Pitch; YHeight = GFX_CEIL_DIV(YSize + 2 * VSize, WidthBytesPhysical); break; } case GMM_FORMAT_NV12: case GMM_FORMAT_NV21: case GMM_FORMAT_NV11: case GMM_FORMAT_P010: case GMM_FORMAT_P012: case GMM_FORMAT_P016: case GMM_FORMAT_P208: case GMM_FORMAT_P216: { // YYYYYYYY // YYYYYYYY // YYYYYYYY // YYYYYYYY // [UV-Packing] *pUOffsetX = *pVOffsetX = 0; YHeight = GFX_ALIGN(Height, __GMM_EVEN_ROW); *pUOffsetY = *pVOffsetY = YHeight; if((pTexInfo->Format == GMM_FORMAT_NV12) || (pTexInfo->Format == GMM_FORMAT_NV21) || (pTexInfo->Format == GMM_FORMAT_P010) || (pTexInfo->Format == GMM_FORMAT_P012) || (pTexInfo->Format == GMM_FORMAT_P016)) { VHeight = GFX_CEIL_DIV(Height, 2); } else { VHeight = YHeight; // U/V plane is same as Y } UVPacked = true; break; } default: { GMM_ASSERTDPF(0, "Unknown Video Format U\n"); break; } } pTexInfo->OffsetInfo.Plane.UnAligned.Height[GMM_PLANE_Y] = YHeight; if(pTexInfo->OffsetInfo.Plane.NoOfPlanes == 2) { pTexInfo->OffsetInfo.Plane.UnAligned.Height[GMM_PLANE_U] = VHeight; } else if(pTexInfo->OffsetInfo.Plane.NoOfPlanes == 3) { pTexInfo->OffsetInfo.Plane.UnAligned.Height[GMM_PLANE_U] = pTexInfo->OffsetInfo.Plane.UnAligned.Height[GMM_PLANE_V] = VHeight; } if(GMM_IS_TILED(pPlatform->TileInfo[pTexInfo->TileMode]) || pTexInfo->Flags.Gpu.__NonMsaaTileYCcs) { GMM_GFX_SIZE_T TileHeight = pGmmLibContext->GetPlatformInfo().TileInfo[pTexInfo->TileMode].LogicalTileHeight; GMM_GFX_SIZE_T TileWidth = pGmmLibContext->GetPlatformInfo().TileInfo[pTexInfo->TileMode].LogicalTileWidth; *pUOffsetX = GFX_ALIGN(*pUOffsetX, TileWidth); *pUOffsetY = GFX_ALIGN(*pUOffsetY, TileHeight); *pVOffsetX = GFX_ALIGN(*pVOffsetX, TileWidth); *pVOffsetY = UVPacked ? GFX_ALIGN(*pVOffsetY, TileHeight) : GFX_ALIGN(YHeight, TileHeight) + GFX_ALIGN(VHeight, TileHeight); if(pTexInfo->Flags.Gpu.UnifiedAuxSurface && pTexInfo->Flags.Gpu.__NonMsaaTileYCcs) { *pUOffsetY += pTexInfo->OffsetInfo.Plane.Y[GMM_PLANE_Y]; *pVOffsetY = *pUOffsetY; } } //Special case LKF MMC compressed surfaces if(pTexInfo->Flags.Gpu.MMC && pTexInfo->Flags.Gpu.UnifiedAuxSurface && GMM_IS_4KB_TILE(pTexInfo->Flags)) { GMM_GFX_SIZE_T TileHeight = pGmmLibContext->GetPlatformInfo().TileInfo[pTexInfo->TileMode].LogicalTileHeight; GMM_GFX_SIZE_T TileWidth = pGmmLibContext->GetPlatformInfo().TileInfo[pTexInfo->TileMode].LogicalTileWidth; *pUOffsetX = GFX_ALIGN(*pUOffsetX, TileWidth); *pUOffsetY = GFX_ALIGN(*pUOffsetY, TileHeight); *pVOffsetX = GFX_ALIGN(*pVOffsetX, TileWidth); *pVOffsetY = GFX_ALIGN(*pVOffsetY, TileHeight); } GMM_DPF_EXIT; #undef SWAP_UV } ///////////////////////////////////////////////////////////////////////////////////// /// Sibling function of GmmLib::GmmTextureCalc::ExpandWidth. it returns the given /// Width, as appropriately scaled by the MSAA NumSamples parameter and aligned to the /// given UnitAlignment. /// /// @param[in] Height: Height of the surface /// @param[in] UnitAlignment: Unit alignment factor /// @param[in] NumSamples: No of MSAA samples /// /// @return scaled height ///////////////////////////////////////////////////////////////////////////////////// uint32_t GmmLib::GmmTextureCalc::ExpandHeight(uint32_t Height, uint32_t UnitAlignment, uint32_t NumSamples) { // Implemented as separate function (instead of as a single function with a // Width/Height parameter) so both functions can be later implemented without // branches, if need be. return ( GmmLib::GmmTextureCalc::ExpandWidth( Height, UnitAlignment, (NumSamples == 2) ? 1 : // MSAA_2X: No height adjustment ((NumSamples == 8) ? 4 : NumSamples))); // <-- MSAA_8X:Height = MSAA_4X:Height. } ///////////////////////////////////////////////////////////////////////////////////// /// This function returns the given Width, as appropriately scaled by the MSAA /// NumSamples parameter and aligned to the given UnitAlignment. /// /// @param[in] Width: Height of the surface /// @param[in] UnitAlignment: Unit alignment factor /// @param[in] NumSamples: No of MSAA samples /// /// @return scaled width ///////////////////////////////////////////////////////////////////////////////////// uint32_t GmmLib::GmmTextureCalc::ExpandWidth(uint32_t Width, uint32_t UnitAlignment, uint32_t NumSamples) { uint32_t ExpandedWidth; switch(NumSamples) { case 1: ExpandedWidth = Width; break; case 2: // Same as 4x... case 4: ExpandedWidth = GFX_CEIL_DIV(GFX_MAX(Width, 1), 2) * 4; break; case 8: // Same as 16x... case 16: ExpandedWidth = GFX_CEIL_DIV(GFX_MAX(Width, 1), 2) * 8; break; default: ExpandedWidth = Width; __GMM_ASSERT(0); } ExpandedWidth = GFX_MAX(ExpandedWidth, UnitAlignment); ExpandedWidth = GFX_ALIGN_NP2(ExpandedWidth, UnitAlignment); return (ExpandedWidth); } ///////////////////////////////////////////////////////////////////////////////////// /// This function calculates Mip Tail Start LOD using max mip tail dimensions and /// populates pTexInfo->Alignment.MipTailStartLod /// /// @param[in] pTexInfo: ptr to ::GMM_TEXTURE_INFO /// ///////////////////////////////////////////////////////////////////////////////////// void GmmLib::GmmTextureCalc::FindMipTailStartLod(GMM_TEXTURE_INFO *pTexInfo) { GMM_DPF_ENTER; if(!(pTexInfo->Flags.Info.TiledYf || GMM_IS_64KB_TILE(pTexInfo->Flags)) || (pTexInfo->MaxLod == 0) || (pTexInfo->Flags.Wa.DisablePackedMipTail)) { // HW never ignores MipTailStartLod for Yf/Ys surfaces. If we do not // want a mip tail, we set MipTailStartLod to be greater than MaxLod. pTexInfo->Alignment.MipTailStartLod = GMM_TILED_RESOURCE_NO_MIP_TAIL; } else { uint32_t MipDepth, MipHeight, MipWidth, CompressWidth, CompressHeight, CompressDepth; uint32_t Level = 0; const GMM_PLATFORM_INFO *pPlatform = GMM_OVERRIDE_PLATFORM_INFO(pTexInfo, pGmmLibContext); MipDepth = pTexInfo->Depth; MipHeight = pTexInfo->BaseHeight; MipWidth = GFX_ULONG_CAST(pTexInfo->BaseWidth); //if compressed texture format, use compressed height, width GetCompressionBlockDimensions(pTexInfo->Format, &CompressWidth, &CompressHeight, &CompressDepth); if(GmmIsCompressed(pGmmLibContext, pTexInfo->Format)) { MipWidth = GFX_CEIL_DIV(MipWidth, CompressWidth); MipHeight = GFX_CEIL_DIV(MipHeight, CompressHeight); MipDepth = GFX_CEIL_DIV(MipDepth, CompressDepth); } __GMM_ASSERT(pTexInfo->TileMode < GMM_TILE_MODES); while((Level < pTexInfo->MaxLod) && (((pTexInfo->Type == RESOURCE_1D) && !(MipWidth <= pPlatform->TileInfo[pTexInfo->TileMode].MaxMipTailStartWidth)) || (((pTexInfo->Type == RESOURCE_2D) || (pTexInfo->Type == RESOURCE_CUBE)) && !((MipWidth <= pPlatform->TileInfo[pTexInfo->TileMode].MaxMipTailStartWidth) && (MipHeight <= pPlatform->TileInfo[pTexInfo->TileMode].MaxMipTailStartHeight))) || ((pTexInfo->Type == RESOURCE_3D) && !((MipWidth <= pPlatform->TileInfo[pTexInfo->TileMode].MaxMipTailStartWidth) && (MipHeight <= pPlatform->TileInfo[pTexInfo->TileMode].MaxMipTailStartHeight) && (MipDepth <= pPlatform->TileInfo[pTexInfo->TileMode].MaxMipTailStartDepth))))) { Level++; MipWidth = GFX_ULONG_CAST(GmmTexGetMipWidth(pTexInfo, Level)); MipHeight = GmmTexGetMipHeight(pTexInfo, Level); MipDepth = GmmTexGetMipDepth(pTexInfo, Level); MipWidth = GFX_CEIL_DIV(MipWidth, CompressWidth); MipHeight = GFX_CEIL_DIV(MipHeight, CompressHeight); MipDepth = GFX_CEIL_DIV(MipDepth, CompressDepth); } if(((pTexInfo->Type == RESOURCE_1D) && (MipWidth <= pPlatform->TileInfo[pTexInfo->TileMode].MaxMipTailStartWidth)) || (((pTexInfo->Type == RESOURCE_2D) || (pTexInfo->Type == RESOURCE_CUBE)) && ((MipWidth <= pPlatform->TileInfo[pTexInfo->TileMode].MaxMipTailStartWidth) && (MipHeight <= pPlatform->TileInfo[pTexInfo->TileMode].MaxMipTailStartHeight))) || ((pTexInfo->Type == RESOURCE_3D) && ((MipWidth <= pPlatform->TileInfo[pTexInfo->TileMode].MaxMipTailStartWidth) && (MipHeight <= pPlatform->TileInfo[pTexInfo->TileMode].MaxMipTailStartHeight) && (MipDepth <= pPlatform->TileInfo[pTexInfo->TileMode].MaxMipTailStartDepth)))) { pTexInfo->Alignment.MipTailStartLod = Level; } else { pTexInfo->Alignment.MipTailStartLod = GMM_TILED_RESOURCE_NO_MIP_TAIL; } } GMM_DPF_EXIT; } ///////////////////////////////////////////////////////////////////////////////////// /// This function returns the height, width and depth of the compression block for a /// given surface format. /// /// @param[in] Format: ::GMM_RESOURCE_FORMAT /// @param[in] pWidth: populates Width /// @param[in] pHeight: populates Height /// @param[in] pDepth: populates Depth /// ///////////////////////////////////////////////////////////////////////////////////// void GmmLib::GmmTextureCalc::GetCompressionBlockDimensions(GMM_RESOURCE_FORMAT Format, uint32_t * pWidth, uint32_t * pHeight, uint32_t * pDepth) { GMM_DPF_ENTER; __GMM_ASSERT(pWidth && pHeight && pDepth); if(pWidth && pHeight && pDepth) { if((Format > GMM_FORMAT_INVALID) && (Format < GMM_RESOURCE_FORMATS)) { *pWidth = pGmmLibContext->GetPlatformInfo().FormatTable[Format].Element.Width; *pHeight = pGmmLibContext->GetPlatformInfo().FormatTable[Format].Element.Height; *pDepth = pGmmLibContext->GetPlatformInfo().FormatTable[Format].Element.Depth; } else { *pWidth = 1; *pHeight = 1; *pDepth = 1; } } GMM_DPF_EXIT; } ///////////////////////////////////////////////////////////////////////////////////// /// This function Convert from d3d tile (64KB) to h/w tile /// /// @param[in] pTexInfo: ::GMM_TEXTURE_INFO /// @param[in/out] pColFactor: populates Width /// @param[in/out] pRowFactor: populates Height /// @param[out] true on Success else false /// ///////////////////////////////////////////////////////////////////////////////////// bool GmmLib::GmmTextureCalc::GmmGetD3DToHwTileConversion(GMM_TEXTURE_INFO *pTexInfo, uint32_t * pColFactor, uint32_t * pRowFactor) { uint32_t i = 0; uint32_t Bpp = pTexInfo->BitsPerPixel; // check for unsupported bpp if(!(Bpp == 8 || Bpp == 16 || Bpp == 32 || Bpp == 64 || Bpp == 128)) { __GMM_ASSERT(false); goto EXIT_ERROR; } // for TileYS, no conversion if(GMM_IS_64KB_TILE(pTexInfo->Flags) || pTexInfo->Flags.Info.Linear) { *pColFactor = 1; *pRowFactor = 1; } else if(GMM_IS_4KB_TILE(pTexInfo->Flags)) { // Logic for non-MSAA { // Bpp = 8 => i = 0 , Bpp = 16 => i = 1, ... // Log2(Bpp = 8) = 3 => i = Log2(8) - 3. i = __GmmLog2(Bpp) - 3; *pColFactor = __GmmTileYConversionTable[i][0]; *pRowFactor = __GmmTileYConversionTable[i][1]; } // Logic for MSAA if(pTexInfo->MSAA.NumSamples > 1) { // For MSAA, the DirectX tile dimensions change, using the table __GmmMSAAConversion. uint32_t W = __GmmMSAAConversion[__GmmLog2(pTexInfo->MSAA.NumSamples)][0]; uint32_t H = __GmmMSAAConversion[__GmmLog2(pTexInfo->MSAA.NumSamples)][1]; // For the new DirectX tile dimensions the new Col and Row conversion factors are: *pColFactor /= W; *pRowFactor /= H; } } else { // unsupported format. __GMM_ASSERT(false); goto EXIT_ERROR; } return true; EXIT_ERROR: *pColFactor = 0; *pRowFactor = 0; return false; } ///////////////////////////////////////////////////////////////////////////////////// /// This function redescribes WidthBytesPhysical of main surface as per UV plane bpp and tilemode /// /// @return ::bool ///////////////////////////////////////////////////////////////////////////////////// bool GmmLib::GmmTextureCalc::RedescribeTexturePlanes(GMM_TEXTURE_INFO *pTexInfo, uint32_t *pWidthBytesPhysical) { GMM_STATUS Status = GMM_SUCCESS; GMM_TEXTURE_INFO TexInfoUVPlane; const GMM_PLATFORM_INFO *pPlatform = GMM_OVERRIDE_PLATFORM_INFO(pTexInfo, pGmmLibContext); __GMM_ASSERT(pTexInfo); __GMM_ASSERT(pTexInfo->Flags.Info.RedecribedPlanes); __GMM_ASSERT(pWidthBytesPhysical); TexInfoUVPlane = *pTexInfo; #ifdef _WIN32 memcpy_s(&TexInfoUVPlane, sizeof(GMM_TEXTURE_INFO), pTexInfo, sizeof(GMM_TEXTURE_INFO)); #else memcpy(&TexInfoUVPlane, pTexInfo, sizeof(GMM_TEXTURE_INFO)); #endif // _WIN32 if(GmmIsUVPacked(pTexInfo->Format)) { // UV packed resources must have two seperate // tiling modes per plane, due to the packed // UV plane having twice the bits per pixel // as the Y plane. switch(pTexInfo->Format) { case GMM_FORMAT_NV12: case GMM_FORMAT_NV21: case GMM_FORMAT_P208: TexInfoUVPlane.BitsPerPixel = 16; // Redescribe bpp to 16 from 8 break; case GMM_FORMAT_P010: case GMM_FORMAT_P012: case GMM_FORMAT_P016: case GMM_FORMAT_P216: TexInfoUVPlane.BitsPerPixel = 32; break; default: GMM_ASSERTDPF(0, "Unsupported format/pixel size combo!"); Status = GMM_INVALIDPARAM; goto ERROR_CASE; break; } } else { // Non-UV packed surfaces, TileMode and bpp of each plane is same as that of pTexInfo } SetTileMode(&TexInfoUVPlane); *pWidthBytesPhysical = GFX_ALIGN(*pWidthBytesPhysical, pPlatform->TileInfo[TexInfoUVPlane.TileMode].LogicalTileWidth); ERROR_CASE: return (Status == GMM_SUCCESS) ? true : false; } ///////////////////////////////////////////////////////////////////////////////////// /// This function returns per plane redescribed parameters (pRedescribedTexInfo: fmt, tilemode,bpp, width, height, size) when main surface pTexInfo is passed /// /// @return ::bool ///////////////////////////////////////////////////////////////////////////////////// bool GmmLib::GmmTextureCalc::GetRedescribedPlaneParams(GMM_TEXTURE_INFO *pTexInfo, GMM_YUV_PLANE PlaneType, GMM_TEXTURE_INFO *pRedescribedTexInfo) { GMM_STATUS Status = GMM_SUCCESS; GMM_TEXTURE_INFO TexInfoUVPlane; const GMM_PLATFORM_INFO *pPlatform = GMM_OVERRIDE_PLATFORM_INFO(pTexInfo, pGmmLibContext); __GMM_ASSERT(pTexInfo); __GMM_ASSERT(pTexInfo->Flags.Info.RedecribedPlanes); __GMM_ASSERT(pRedescribedTexInfo); *pRedescribedTexInfo = *pTexInfo; pRedescribedTexInfo->Flags.Info.RedecribedPlanes = 0; #ifdef _WIN32 memcpy_s(&TexInfoUVPlane, sizeof(GMM_TEXTURE_INFO), pTexInfo, sizeof(GMM_TEXTURE_INFO)); #else memcpy(&TexInfoUVPlane, pTexInfo, sizeof(GMM_TEXTURE_INFO)); #endif // _WIN32 if(GmmIsUVPacked(pTexInfo->Format)) { // UV packed resources must have two seperate // tiling modes per plane, due to the packed // UV plane having twice the bits per pixel // as the Y plane. if((PlaneType == GMM_PLANE_U) || (PlaneType == GMM_PLANE_V)) { switch(pTexInfo->Format) { // GMM_FORMAT_NV11 : linear format, no tiling supported, hence no redescription supported case GMM_FORMAT_NV12: case GMM_FORMAT_NV21: pRedescribedTexInfo->BitsPerPixel = 16; pRedescribedTexInfo->BaseWidth = GFX_CEIL_DIV(pTexInfo->BaseWidth, 2); pRedescribedTexInfo->BaseHeight = GFX_CEIL_DIV(pTexInfo->BaseHeight, 2); break; case GMM_FORMAT_P208: pRedescribedTexInfo->BitsPerPixel = 16; pRedescribedTexInfo->BaseWidth = GFX_CEIL_DIV(pTexInfo->BaseWidth, 2); // same base height as main surface break; case GMM_FORMAT_P010: case GMM_FORMAT_P012: case GMM_FORMAT_P016: pRedescribedTexInfo->BitsPerPixel = 32; pRedescribedTexInfo->BaseWidth = GFX_CEIL_DIV(pTexInfo->BaseWidth, 2); pRedescribedTexInfo->BaseHeight = GFX_CEIL_DIV(pTexInfo->BaseHeight, 2); break; case GMM_FORMAT_P216: pRedescribedTexInfo->BitsPerPixel = 32; pRedescribedTexInfo->BaseWidth = GFX_CEIL_DIV(pTexInfo->BaseWidth, 2); // same base height as main surface break; default: GMM_ASSERTDPF(0, "Unsupported format/pixel size combo!"); Status = GMM_INVALIDPARAM; goto ERROR_CASE; break; } } } else { // Non-UV packed surfaces TileMode of each plane is same as that of pTexInfo if((PlaneType == GMM_PLANE_U) || (PlaneType == GMM_PLANE_V)) { // Non-UV packed surfaces only require the plane descriptors have proper height and width for each plane switch(pTexInfo->Format) { case GMM_FORMAT_IMC1: case GMM_FORMAT_IMC2: case GMM_FORMAT_IMC3: case GMM_FORMAT_IMC4: case GMM_FORMAT_MFX_JPEG_YUV420: pRedescribedTexInfo->BaseWidth = GFX_CEIL_DIV(pTexInfo->BaseWidth, 2); pRedescribedTexInfo->BaseHeight = GFX_CEIL_DIV(pTexInfo->BaseHeight, 2); break; case GMM_FORMAT_MFX_JPEG_YUV422V: pRedescribedTexInfo->BaseHeight = GFX_CEIL_DIV(pTexInfo->BaseHeight, 2); break; case GMM_FORMAT_MFX_JPEG_YUV411R_TYPE: pRedescribedTexInfo->BaseHeight = GFX_CEIL_DIV(pTexInfo->BaseHeight, 4); break; case GMM_FORMAT_MFX_JPEG_YUV411: pRedescribedTexInfo->BaseWidth = GFX_CEIL_DIV(pTexInfo->BaseWidth, 4); break; case GMM_FORMAT_MFX_JPEG_YUV422H: pRedescribedTexInfo->BaseWidth = GFX_CEIL_DIV(pTexInfo->BaseWidth, 2); break; default: GMM_ASSERTDPF(0, "Unsupported format/pixel size combo!"); Status = GMM_INVALIDPARAM; goto ERROR_CASE; break; } } } SetTileMode(pRedescribedTexInfo); switch(pRedescribedTexInfo->BitsPerPixel) { case 8: pRedescribedTexInfo->Format = GMM_FORMAT_R8_UINT; break; case 16: pRedescribedTexInfo->Format = GMM_FORMAT_R16_UINT; break; case 32: pRedescribedTexInfo->Format = GMM_FORMAT_R32_UINT; break; default: GMM_ASSERTDPF(0, "Unsupported format/pixel size combo!"); Status = GMM_INVALIDPARAM; goto ERROR_CASE; break; } if(pTexInfo->ArraySize > 1) { pRedescribedTexInfo->OffsetInfo.Plane.ArrayQPitch = 0; // no longer a planar format on redescription pRedescribedTexInfo->Alignment.QPitch = GFX_ALIGN(pRedescribedTexInfo->BaseHeight, pTexInfo->Alignment.VAlign); pRedescribedTexInfo->OffsetInfo.Texture2DOffsetInfo.ArrayQPitchRender = pRedescribedTexInfo->OffsetInfo.Texture2DOffsetInfo.ArrayQPitchLock = pRedescribedTexInfo->Alignment.QPitch * pTexInfo->Pitch; pRedescribedTexInfo->Size = pRedescribedTexInfo->Alignment.QPitch * pTexInfo->Pitch * pTexInfo->ArraySize; } else { pRedescribedTexInfo->Size = (GFX_ALIGN(pRedescribedTexInfo->BaseHeight, pTexInfo->Alignment.VAlign)) * pTexInfo->Pitch; } ERROR_CASE: return (Status == GMM_SUCCESS) ? true : false; } gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/Texture/GmmTexture.h000066400000000000000000001007551466655022700237750ustar00rootroot00000000000000/*============================================================================== Copyright(c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ============================================================================*/ #pragma once #include "External/Common/GmmInternal.h" // UMD or KMD Windows header #include "External/Common/GmmTextureExt.h" #include "External/Common/GmmUtil.h" #include "External/Common/GmmInfoExt.h" #include "External/Common/GmmInfo.h" #include "External/Common/GmmProto.h" #ifdef __cplusplus #include "Internal/Common/Texture/GmmTextureCalc.h" //--------------------------------------------------------------------------- // ExpandWidth/Height Wrappers // // Gen7+ MSAA (non-Depth/Stencil) render targets use array expansion instead of // Width/Height expansion--So they pass NumSamples=1 to __GmmExpandXxx functions. // //--------------------------------------------------------------------------- #define __GMM_EXPAND_Xxx(ptr, Xxx, Dimension, UnitAlignment, pTexInfo) \ (ptr)->Expand##Xxx( \ (Dimension), (UnitAlignment), \ ((pTexInfo)->Flags.Gpu.Depth || (pTexInfo)->Flags.Gpu.SeparateStencil) ? \ (pTexInfo)->MSAA.NumSamples : 1) #define __GMM_EXPAND_WIDTH(ptr, __Width, UnitAlignment, pTexInfo) \ __GMM_EXPAND_Xxx(ptr, Width, __Width, UnitAlignment, pTexInfo) #define __GMM_EXPAND_HEIGHT(ptr, __Height, UnitAlignment, pTexInfo) \ __GMM_EXPAND_Xxx(ptr, Height, __Height, UnitAlignment, pTexInfo) //============================================================================= //Function: // __GmmTexFillHAlignVAlign // //Description: // Stores in pTexInfo the appropriate unit aligment sizes. // //----------------------------------------------------------------------------- // Gmmlib 2.0 TODO[Low] Move to Class and Inline function handling. GMM_INLINE GMM_STATUS __GmmTexFillHAlignVAlign(GMM_TEXTURE_INFO *pTexInfo,GMM_LIB_CONTEXT* pGmmLibContext) { uint32_t UnitAlignWidth = 0; uint32_t UnitAlignHeight = 0; uint32_t UnitAlignDepth = 0; const GMM_PLATFORM_INFO *pPlatform; GMM_TEXTURE_CALC *pTextureCalc; GMM_DPF_ENTER; __GMM_ASSERTPTR(pGmmLibContext,GMM_ERROR); __GMM_ASSERTPTR(pTexInfo, GMM_ERROR); #define SET_ALIGN_FACTOR(Xxx, Bytes) \ if(!pGmmLibContext->GetSkuTable().FtrTileY) \ { \ UnitAlign##Xxx = \ (pTexInfo->BitsPerPixel == 128) ? Bytes/16 : \ (pTexInfo->BitsPerPixel == 64) ? Bytes/8 : \ (pTexInfo->BitsPerPixel == 32) ? Bytes/4 : \ (pTexInfo->BitsPerPixel == 16) ? Bytes/2 : Bytes ; \ \ if(!pTexInfo->Flags.Info.Linear && \ (pTexInfo->BitsPerPixel == 24 || pTexInfo->BitsPerPixel == 48 || pTexInfo->BitsPerPixel == 96)) \ { \ UnitAlign##Xxx = 16; \ } \ else if (pTexInfo->Flags.Info.Linear && \ (pTexInfo->BitsPerPixel == 24 || pTexInfo->BitsPerPixel == 48 || pTexInfo->BitsPerPixel == 96))\ { \ UnitAlign##Xxx = 128; \ } \ } if (!((pTexInfo->Format > GMM_FORMAT_INVALID) && (pTexInfo->Format < GMM_RESOURCE_FORMATS))) { GMM_DPF_CRITICAL("Invalid Resource Format"); return GMM_ERROR; } if( !pTexInfo->Alignment.HAlign && !pTexInfo->Alignment.VAlign) { pPlatform = GMM_OVERRIDE_PLATFORM_INFO(pTexInfo,pGmmLibContext); pTextureCalc = GMM_OVERRIDE_TEXTURE_CALC(pTexInfo,pGmmLibContext); /// SKL TiledYf/Ys Surfaces ////////////////////////////////////////// if( ((GFX_GET_CURRENT_RENDERCORE(pPlatform->Platform) >= IGFX_GEN9_CORE) && (pTexInfo->Flags.Info.TiledYf || GMM_IS_64KB_TILE(pTexInfo->Flags)))) { #define SET_ALIGN_INFO(Xxx, A1, A2, A3, A4, A5) \ UnitAlign##Xxx = \ (pTexInfo->BitsPerPixel == 128) ? A1 : \ (pTexInfo->BitsPerPixel == 64) ? A2 : \ (pTexInfo->BitsPerPixel == 32) ? A3 : \ (pTexInfo->BitsPerPixel == 16) ? A4 : A5; \ if(pTexInfo->Type == RESOURCE_1D) { if(pTexInfo->Flags.Info.TiledYf) { SET_ALIGN_INFO(Width, 256, 512, 1024, 2048, 4096); } else // if(pTexInfo->Flags.Info.TiledYs) { SET_ALIGN_INFO(Width, 4096, 8192, 16384, 32768, 65536); } } else if((pTexInfo->Type == RESOURCE_2D) || (pTexInfo->Type == RESOURCE_CUBE) || (pTexInfo->Type == RESOURCE_PRIMARY)) { if(pTexInfo->Flags.Info.TiledYf) { SET_ALIGN_INFO(Width, 16, 32, 32, 64, 64); SET_ALIGN_INFO(Height, 16, 16, 32, 32, 64); } else // if(pTexInfo->Flags.Info.TiledYs) { SET_ALIGN_INFO(Width, 64, 128, 128, 256, 256); SET_ALIGN_INFO(Height, 64, 64, 128, 128, 256); } // Only color buffer MSAA if(pTexInfo->MSAA.NumSamples > 1 && !pTexInfo->Flags.Gpu.Depth && !pTexInfo->Flags.Gpu.SeparateStencil) { if(pGmmLibContext->GetSkuTable().FtrTileY) { switch(pTexInfo->MSAA.NumSamples) { case 16: UnitAlignWidth /= 4; UnitAlignHeight /= 4; break; case 8: UnitAlignWidth /= 4; UnitAlignHeight /= 2; break; case 4: UnitAlignWidth /= 2; UnitAlignHeight /= 2; break; case 2: UnitAlignWidth /= 2; break; default: __GMM_ASSERT(0); } } else { if (pGmmLibContext->GetSkuTable().FtrXe2PlusTiling) { switch (pTexInfo->MSAA.NumSamples) { case 16: if (pTexInfo->BitsPerPixel == 64) { UnitAlignWidth /= 8; UnitAlignHeight /= 2; } else { UnitAlignWidth /= 4; UnitAlignHeight /= 4; } break; case 8: if ((pTexInfo->BitsPerPixel == 8) || (pTexInfo->BitsPerPixel == 32)) { UnitAlignWidth /= 2; UnitAlignHeight /= 4; } else { UnitAlignWidth /= 4; UnitAlignHeight /= 2; } break; case 4: UnitAlignWidth /= 2; UnitAlignHeight /= 2; break; case 2: if (pTexInfo->BitsPerPixel == 128) { UnitAlignHeight /= 2; } else { UnitAlignWidth /= 2; } break; default: __GMM_ASSERT(0); } } else { switch (pTexInfo->MSAA.NumSamples) { case 4: case 8: case 16: UnitAlignWidth /= 2; UnitAlignHeight /= 2; break; case 2: UnitAlignWidth /= 2; break; default: __GMM_ASSERT(0); } } } } } else if(pTexInfo->Type == RESOURCE_3D) { if(pTexInfo->Flags.Info.TiledYf) { SET_ALIGN_INFO(Width, 4, 8, 8, 8, 16); SET_ALIGN_INFO(Height, 8, 8, 16, 16, 16); SET_ALIGN_INFO(Depth, 8, 8, 8, 16, 16); } else // if(pTexInfo->Flags.Info.TiledYs) { SET_ALIGN_INFO(Width, 16, 32, 32, 32, 64); SET_ALIGN_INFO(Height, 16, 16, 32, 32, 32); SET_ALIGN_INFO(Depth, 16, 16, 16, 32, 32); } } #undef SET_ALIGN_INFO if(GmmIsCompressed(pGmmLibContext, pTexInfo->Format)) { uint32_t ElementWidth, ElementHeight, ElementDepth; pTextureCalc->GetCompressionBlockDimensions(pTexInfo->Format, &ElementWidth, &ElementHeight, &ElementDepth); UnitAlignWidth *= ElementWidth; UnitAlignHeight *= ElementHeight; UnitAlignDepth *= ElementDepth; } } /// SKL 1D Surfaces /////////////////////////////////////////////// else if((GFX_GET_CURRENT_RENDERCORE(pPlatform->Platform) >= IGFX_GEN9_CORE) && (pTexInfo->Type == RESOURCE_1D)) { UnitAlignWidth = 64; // Tile4/64 SET_ALIGN_FACTOR(Width, 128); } /// CCS /////////////////////////////////////////////////////////// else if (pTexInfo->Flags.Gpu.CCS && (pTexInfo->Flags.Gpu.__NonMsaaTileYCcs || pTexInfo->Flags.Gpu.__NonMsaaTileXCcs)) { UnitAlignWidth = pPlatform->TexAlign.CCS.Align.Width; UnitAlignHeight = pPlatform->TexAlign.CCS.Align.Height; ALIGNMENT UnitAlign = { UnitAlignWidth , UnitAlignHeight, UnitAlignDepth }; pGmmLibContext->GetPlatformInfoObj()->ApplyExtendedTexAlign(pTexInfo->CCSModeAlign, UnitAlign); if (UnitAlign.Width != UnitAlignWidth || UnitAlign.Height != UnitAlignHeight || UnitAlign.Depth != UnitAlignDepth) { UnitAlignWidth = UnitAlign.Width; UnitAlignHeight = UnitAlign.Height; UnitAlignDepth = UnitAlign.Depth; } } else if (GmmIsYUVPacked(pTexInfo->Format)) ///////////////////////// { UnitAlignWidth = pPlatform->TexAlign.YUV422.Width; UnitAlignHeight = pPlatform->TexAlign.YUV422.Height; // For packed 8/16-bit formats alignment factor of 4 will give us < 16B so expand to 32B if (pTexInfo->Flags.Info.Linear) { SET_ALIGN_FACTOR(Width, 128); } else { SET_ALIGN_FACTOR(Width, 32); } } else if(GmmIsCompressed(pGmmLibContext, pTexInfo->Format)) ///////////////////////////// { uint32_t ElementWidth, ElementHeight, ElementDepth; pTextureCalc->GetCompressionBlockDimensions(pTexInfo->Format, &ElementWidth, &ElementHeight, &ElementDepth); UnitAlignWidth = ElementWidth * pPlatform->TexAlign.Compressed.Width; UnitAlignHeight = ElementHeight * pPlatform->TexAlign.Compressed.Height; UnitAlignDepth = (pTexInfo->Type == RESOURCE_3D) ? ElementDepth * pPlatform->TexAlign.Compressed.Depth : pPlatform->TexAlign.Compressed.Depth; } /// Depth Buffer ////////////////////////////////////////////////// else if(pTexInfo->Flags.Gpu.HiZ) { if( (GFX_GET_CURRENT_RENDERCORE(pPlatform->Platform) >= IGFX_GEN7_CORE) && (pTexInfo->BitsPerPixel == 16)) { UnitAlignWidth = 8; // Gen7 Special Case: HALIGN_8 for 16bpp Depth Buffers } else { UnitAlignWidth = pPlatform->TexAlign.Depth.Width; } UnitAlignHeight = pPlatform->TexAlign.Depth.Height; } else if (pTexInfo->Flags.Gpu.Depth) { if (pTexInfo->BitsPerPixel == 16) { if (pTexInfo->MSAA.NumSamples == 0x2 || pTexInfo->MSAA.NumSamples == 0x8) { UnitAlignWidth = pPlatform->TexAlign.Depth_D16_UNORM_2x_8x.Width; UnitAlignHeight = pPlatform->TexAlign.Depth_D16_UNORM_2x_8x.Height; } else { UnitAlignWidth = pPlatform->TexAlign.Depth_D16_UNORM_1x_4x_16x.Width; UnitAlignHeight = pPlatform->TexAlign.Depth_D16_UNORM_1x_4x_16x.Height; } SET_ALIGN_FACTOR(Width, 16); } else { UnitAlignWidth = pPlatform->TexAlign.Depth.Width; UnitAlignHeight = pPlatform->TexAlign.Depth.Height; SET_ALIGN_FACTOR(Width, 32); } } /// Separate Stencil ////////////////////////////////////////////// else if(pTexInfo->Flags.Gpu.SeparateStencil) { UnitAlignWidth = pPlatform->TexAlign.SeparateStencil.Width; UnitAlignHeight = pPlatform->TexAlign.SeparateStencil.Height; SET_ALIGN_FACTOR(Width, 16); } /// Cross Adapter ////////////////////////////////////////////// else if(pTexInfo->Flags.Info.XAdapter) { //Add cross adapter height restriction. UnitAlignHeight = pPlatform->TexAlign.XAdapter.Height; UnitAlignWidth = pPlatform->TexAlign.XAdapter.Width; SET_ALIGN_FACTOR(Width, 128); __GMM_ASSERT(pTexInfo->MaxLod == 0); } else if(((pTexInfo->Flags.Gpu.MCS && GFX_GET_CURRENT_RENDERCORE(pPlatform->Platform) >= IGFX_GEN12_CORE) || (pTexInfo->Flags.Gpu.CCS && GFX_GET_CURRENT_RENDERCORE(pPlatform->Platform) >= IGFX_GEN9_CORE)) && (pTexInfo->MSAA.NumSamples > 1)) { UnitAlignWidth = 16; UnitAlignHeight = 4; SET_ALIGN_FACTOR(Width, 128); } else if(pTexInfo->Flags.Wa.__ForceOtherHVALIGN4) { UnitAlignWidth = 4; UnitAlignHeight = 4; } else /// All Other //////////////////////////////////////////////// { UnitAlignWidth = pPlatform->TexAlign.AllOther.Width; if(GFX_GET_CURRENT_RENDERCORE(pPlatform->Platform) >= IGFX_GEN8_CORE) { UnitAlignHeight = pPlatform->TexAlign.AllOther.Height; // Let VAlign = 16, when bpp == 8 or 16 for both TileX and TileY on BDW if ((GmmGetWaTable(pGmmLibContext)->WaUseVAlign16OnTileXYBpp816) && (pTexInfo->BitsPerPixel == 8 || pTexInfo->BitsPerPixel == 16) && (pTexInfo->Flags.Info.TiledX || pTexInfo->Flags.Info.TiledY)) { UnitAlignHeight = 16; } if((GmmGetWaTable(pGmmLibContext)->Wa32bppTileY2DColorNoHAlign4) && (pTexInfo->BitsPerPixel == 32 && pTexInfo->Flags.Info.TiledY && pTexInfo->MSAA.NumSamples == 1 && pTexInfo->MaxLod > 1) && UnitAlignWidth <= 4) { UnitAlignWidth = 8; } SET_ALIGN_FACTOR(Width, 128); } else if(pTexInfo->MSAA.NumSamples <= 1) { if ((GmmGetWaTable(pGmmLibContext)->WaValign2For96bppFormats) && ( pTexInfo->BitsPerPixel == 96 ) ) { UnitAlignHeight = 2; } else if ((GmmGetWaTable(pGmmLibContext)->WaValign2ForR8G8B8UINTFormat) && ( pTexInfo->Format == GMM_FORMAT_R8G8B8_UINT ) ) { UnitAlignHeight = 2; } else { UnitAlignHeight = pPlatform->TexAlign.AllOther.Height; } } else { UnitAlignHeight = 4; // Gen6+ Special Case: VALIGN_4 for >= MSAA_4X Render Targets } } //ExistingSysMem override if(pTexInfo->Flags.Info.ExistingSysMem && !pTexInfo->ExistingSysMem.IsGmmAllocated && !pTexInfo->ExistingSysMem.IsPageAligned) { if(pTexInfo->Flags.Gpu.Texture) { UnitAlignWidth = pPlatform->SamplerFetchGranularityWidth; UnitAlignHeight = pPlatform->SamplerFetchGranularityHeight; } else if(pTexInfo->Flags.Gpu.RenderTarget) { UnitAlignWidth = (GmmIsYUVPlanar(pTexInfo->Format)) ? 2 : 1; UnitAlignHeight = 1; } } pTexInfo->Alignment.HAlign = UnitAlignWidth; pTexInfo->Alignment.VAlign = UnitAlignHeight; pTexInfo->Alignment.DAlign = UnitAlignDepth; } else { // Don't reinitialize b/c special-case ResCreates (e.g. MCS) need the // values from their first pass through here to stick (but they'll come // through here more than once, with different parameters). } GMM_DPF_EXIT; return GMM_SUCCESS; } // __GmmTexFillHAlignVAlign #endif //__cpluscplus //=========================================================================== // typedef: // GMM_MIPTAIL_SLOT_OFFSET_REC // // Description: // This structure used to describe the offset between miptail slot and // miptail starting address //--------------------------------------------------------------------------- typedef struct GMM_MIPTAIL_SLOT_OFFSET_REC { uint32_t X; uint32_t Y; uint32_t Z; }GMM_MIPTAIL_SLOT_OFFSET; #define GEN9_MIPTAIL_SLOT_OFFSET_1D_SURFACE { \ /* | 128 bpe | 64 bpe | 32 bpe | 16 bpe | 8 bpe | */ \ { { 2048, 0, 0 }, { 4096, 0, 0 }, { 8192, 0, 0 }, { 16384, 0, 0 }, { 32768, 0, 0 } }, \ { { 1024, 0, 0 }, { 2048, 0, 0 }, { 4096, 0, 0 }, { 8192, 0, 0 }, { 16384, 0, 0 } }, \ { { 512, 0, 0 }, { 1024, 0, 0 }, { 2048, 0, 0 }, { 4096, 0, 0 }, { 8192, 0, 0 } }, \ { { 256, 0, 0 }, { 512, 0, 0 }, { 1024, 0, 0 }, { 2048, 0, 0 }, { 4096, 0, 0 } }, \ { { 128, 0, 0 }, { 256, 0, 0 }, { 512, 0, 0 }, { 1024, 0, 0 }, { 2048, 0, 0 } }, \ { { 64, 0, 0 }, { 128, 0, 0 }, { 256, 0, 0 }, { 512, 0, 0 }, { 1024, 0, 0 } }, \ { { 48, 0, 0 }, { 96, 0, 0 }, { 192, 0, 0 }, { 384, 0, 0 }, { 768, 0, 0 } }, \ { { 32, 0, 0 }, { 64, 0, 0 }, { 128, 0, 0 }, { 256, 0, 0 }, { 512, 0, 0 } }, \ { { 28, 0, 0 }, { 56, 0, 0 }, { 112, 0, 0 }, { 224, 0, 0 }, { 448, 0, 0 } }, \ { { 24, 0, 0 }, { 48, 0, 0 }, { 96, 0, 0 }, { 192, 0, 0 }, { 384, 0, 0 } }, \ { { 20, 0, 0 }, { 40, 0, 0 }, { 80, 0, 0 }, { 160, 0, 0 }, { 320, 0, 0 } }, \ { { 16, 0, 0 }, { 32, 0, 0 }, { 64, 0, 0 }, { 128, 0, 0 }, { 256, 0, 0 } }, \ { { 12, 0, 0 }, { 24, 0, 0 }, { 48, 0, 0 }, { 96, 0, 0 }, { 192, 0, 0 } }, \ { { 8, 0, 0 }, { 16, 0, 0 }, { 32, 0, 0 }, { 64, 0, 0 }, { 128, 0, 0 } }, \ { { 4, 0, 0 }, { 8, 0, 0 }, { 16, 0, 0 }, { 32, 0, 0 }, { 64, 0, 0 } }, \ { { 0, 0, 0 }, { 0, 0, 0 }, { 0, 0, 0 }, { 0, 0, 0 }, { 0, 0, 0 } }, \ } #define GEN9_MIPTAIL_SLOT_OFFSET_2D_SURFACE { \ /* | 128 bpe | 64 bpe | 32 bpe | 16 bpe | 8 bpe | */\ { { 32, 0, 0 }, { 64, 0, 0 }, { 64, 0, 0 }, { 128, 0, 0 }, { 128, 0, 0 } }, \ { { 0, 32, 0 }, { 0, 32, 0 }, { 0, 64, 0 }, { 0, 64, 0 }, { 0, 128, 0 } }, \ { { 16, 0, 0 }, { 32, 0, 0 }, { 32, 0, 0 }, { 64, 0, 0 }, { 64, 0, 0 } }, \ { { 0, 16, 0 }, { 0, 16, 0 }, { 0, 32, 0 }, { 0, 32, 0 }, { 0, 64, 0 } }, \ { { 8, 0, 0 }, { 16, 0, 0 }, { 16, 0, 0 }, { 32, 0, 0 }, { 32, 0, 0 } }, \ { { 4, 8, 0 }, { 8, 8, 0 }, { 8, 16, 0 }, { 16, 16, 0 }, { 16, 32, 0 } }, \ { { 0, 12, 0 }, { 0, 12, 0 }, { 0, 24, 0 }, { 0, 24, 0 }, { 0, 48, 0 } }, \ { { 0, 8, 0 }, { 0, 8, 0 }, { 0, 16, 0 }, { 0, 16, 0 }, { 0, 32, 0 } }, \ { { 4, 4, 0 }, { 8, 4, 0 }, { 8, 8, 0 }, { 16, 8, 0 }, { 16, 16, 0 } }, \ { { 4, 0, 0 }, { 8, 0, 0 }, { 8, 0, 0 }, { 16, 0, 0 }, { 16, 0, 0 } }, \ { { 0, 4, 0 }, { 0, 4, 0 }, { 0, 8, 0 }, { 0, 8, 0 }, { 0, 16, 0 } }, \ { { 3, 0, 0 }, { 6, 0, 0 }, { 4, 4, 0 }, { 8, 4, 0 }, { 0, 12, 0 } }, \ { { 2, 0, 0 }, { 4, 0, 0 }, { 4, 0, 0 }, { 8, 0, 0 }, { 0, 8, 0 } }, \ { { 1, 0, 0 }, { 2, 0, 0 }, { 0, 4, 0 }, { 0, 4, 0 }, { 0, 4, 0 } }, \ { { 0, 0, 0 }, { 0, 0, 0 }, { 0, 0, 0 }, { 0, 0, 0 }, { 0, 0, 0 } }, \ } #define GEN9_MIPTAIL_SLOT_OFFSET_3D_SURFACE { \ /* | 128 bpe | 64 bpe | 32 bpe | 16 bpe | 8 bpe | */ \ { { 8, 0, 0 }, { 16, 0, 0 }, { 16, 0, 0 }, { 16, 0, 0 }, { 32, 0, 0 } }, \ { { 0, 8, 0 }, { 0, 8, 0 }, { 0, 16, 0 }, { 0, 16, 0 }, { 0, 16, 0 } }, \ { { 0, 0, 8 }, { 0, 0, 8 }, { 0, 0, 8 }, { 0, 0, 16 }, { 0, 0, 16 } }, \ { { 4, 0, 0 }, { 8, 0, 0 }, { 8, 0, 0 }, { 8, 0, 0 }, { 16, 0, 0 } }, \ { { 0, 4, 0 }, { 0, 4, 0 }, { 0, 8, 0 }, { 0, 8, 0 }, { 0, 8, 0 } }, \ { { 0, 0, 4 }, { 0, 0, 4 }, { 0, 0, 4 }, { 0, 0, 8 }, { 0, 0, 8 } }, \ { { 3, 0, 0 }, { 6, 0, 0 }, { 4, 4, 0 }, { 0, 4, 4 }, { 0, 4, 4 } }, \ { { 2, 0, 0 }, { 4, 0, 0 }, { 0, 4, 0 }, { 0, 4, 0 }, { 0, 4, 0 } }, \ { { 1, 0, 3 }, { 2, 0, 3 }, { 4, 0, 3 }, { 0, 0, 7 }, { 0, 0, 7 } }, \ { { 1, 0, 2 }, { 2, 0, 2 }, { 4, 0, 2 }, { 0, 0, 6 }, { 0, 0, 6 } }, \ { { 1, 0, 1 }, { 2, 0, 1 }, { 4, 0, 1 }, { 0, 0, 5 }, { 0, 0, 5 } }, \ { { 1, 0, 0 }, { 2, 0, 0 }, { 4, 0, 0 }, { 0, 0, 4 }, { 0, 0, 4 } }, \ { { 0, 0, 3 }, { 0, 0, 3 }, { 0, 0, 3 }, { 0, 0, 3 }, { 0, 0, 3 } }, \ { { 0, 0, 2 }, { 0, 0, 2 }, { 0, 0, 2 }, { 0, 0, 2 }, { 0, 0, 2 } }, \ { { 0, 0, 1 }, { 0, 0, 1 }, { 0, 0, 1 }, { 0, 0, 1 }, { 0, 0, 1 } }, \ { { 0, 0, 0 }, { 0, 0, 0 }, { 0, 0, 0 }, { 0, 0, 0 }, { 0, 0, 0 } }, \ } #define GEN10_MIPTAIL_SLOT_OFFSET_1D_SURFACE { \ /* | 128 bpe | 64 bpe | 32 bpe | 16 bpe | 8 bpe | */ \ { { 2048, 0, 0 }, { 4096, 0, 0 }, { 8192, 0, 0 }, { 16384, 0, 0 }, { 32768, 0, 0 } }, \ { { 1024, 0, 0 }, { 2048, 0, 0 }, { 4096, 0, 0 }, { 8192, 0, 0 }, { 16384, 0, 0 } }, \ { { 512, 0, 0 }, { 1024, 0, 0 }, { 2048, 0, 0 }, { 4096, 0, 0 }, { 8192, 0, 0 } }, \ { { 256, 0, 0 }, { 512, 0, 0 }, { 1024, 0, 0 }, { 2048, 0, 0 }, { 4096, 0, 0 } }, \ { { 128, 0, 0 }, { 256, 0, 0 }, { 512, 0, 0 }, { 1024, 0, 0 }, { 2048, 0, 0 } }, \ { { 96, 0, 0 }, { 192, 0, 0 }, { 384, 0, 0 }, { 768, 0, 0 }, { 1536, 0, 0 } }, \ { { 80, 0, 0 }, { 160, 0, 0 }, { 320, 0, 0 }, { 640, 0, 0 }, { 1280, 0, 0 } }, \ { { 64, 0, 0 }, { 128, 0, 0 }, { 256, 0, 0 }, { 512, 0, 0 }, { 1024, 0, 0 } }, \ { { 48, 0, 0 }, { 96, 0, 0 }, { 192, 0, 0 }, { 384, 0, 0 }, { 768, 0, 0 } }, \ { { 32, 0, 0 }, { 64, 0, 0 }, { 128, 0, 0 }, { 256, 0, 0 }, { 512, 0, 0 } }, \ { { 16, 0, 0 }, { 32, 0, 0 }, { 64, 0, 0 }, { 128, 0, 0 }, { 256, 0, 0 } }, \ { { 12, 0, 0 }, { 24, 0, 0 }, { 48, 0, 0 }, { 96, 0, 0 }, { 192, 0, 0 } }, \ { { 8, 0, 0 }, { 16, 0, 0 }, { 32, 0, 0 }, { 64, 0, 0 }, { 128, 0, 0 } }, \ { { 4, 0, 0 }, { 8, 0, 0 }, { 16, 0, 0 }, { 32, 0, 0 }, { 64, 0, 0 } }, \ { { 0, 0, 0 }, { 0, 0, 0 }, { 0, 0, 0 }, { 0, 0, 0 }, { 0, 0, 0 } }, \ } #define GEN10_MIPTAIL_SLOT_OFFSET_2D_SURFACE { \ /* | 128 bpe | 64 bpe | 32 bpe | 16 bpe | 8 bpe | */ \ { { 32, 0, 0 }, { 64, 0, 0 }, { 64, 0, 0 }, { 128, 0, 0 }, { 128, 0, 0 } }, \ { { 0, 32, 0 }, { 0, 32, 0 }, { 0, 64, 0 }, { 0, 64, 0 }, { 0, 128, 0 } }, \ { { 16, 0, 0 }, { 32, 0, 0 }, { 32, 0, 0 }, { 64, 0, 0 }, { 64, 0, 0 } }, \ { { 0, 16, 0 }, { 0, 16, 0 }, { 0, 32, 0 }, { 0, 32, 0 }, { 0, 64, 0 } }, \ { { 8, 0, 0 }, { 16, 0, 0 }, { 16, 0, 0 }, { 32, 0, 0 }, { 32, 0, 0 } }, \ { { 4, 8, 0 }, { 8, 8, 0 }, { 8, 16, 0 }, { 16, 16, 0 }, { 16, 32, 0 } }, \ { { 0, 12, 0 }, { 0, 12, 0 }, { 0, 24, 0 }, { 0, 24, 0 }, { 0, 48, 0 } }, \ { { 0, 8, 0 }, { 0, 8, 0 }, { 0, 16, 0 }, { 0, 16, 0 }, { 0, 32, 0 } }, \ { { 4, 4, 0 }, { 8, 4, 0 }, { 8, 8, 0 }, { 16, 8, 0 }, { 16, 16, 0 } }, \ { { 4, 0, 0 }, { 8, 0, 0 }, { 8, 0, 0 }, { 16, 0, 0 }, { 16, 0, 0 } }, \ { { 0, 4, 0 }, { 0, 4, 0 }, { 0, 8, 0 }, { 0, 8, 0 }, { 0, 16, 0 } }, \ { { 0, 0, 0 }, { 0, 0, 0 }, { 0, 0, 0 }, { 0, 0, 0 }, { 0, 0, 0 } }, \ { { 1, 0, 0 }, { 2, 0, 0 }, { 0, 4, 0 }, { 0, 4, 0 }, { 0, 4, 0 } }, \ { { 2, 0, 0 }, { 4, 0, 0 }, { 4, 0, 0 }, { 8, 0, 0 }, { 0, 8, 0 } }, \ { { 3, 0, 0 }, { 6, 0, 0 }, { 4, 4, 0 }, { 8, 4, 0 }, { 0, 12, 0 } }, \ } #define GEN10_MIPTAIL_SLOT_OFFSET_3D_SURFACE { \ /* | 128 bpe | 64 bpe | 32 bpe | 16 bpe | 8 bpe | */ \ { { 8, 0, 0 }, { 16, 0, 0 }, { 16, 0, 0 }, { 16, 0, 0 }, { 32, 0, 0 } }, \ { { 0, 8, 0 }, { 0, 8, 0 }, { 0, 16, 0 }, { 0, 16, 0 }, { 0, 16, 0 } }, \ { { 0, 0, 8 }, { 0, 0, 8 }, { 0, 0, 8 }, { 0, 0, 16 }, { 0, 0, 16 } }, \ { { 4, 0, 0 }, { 8, 0, 0 }, { 8, 0, 0 }, { 8, 0, 0 }, { 16, 0, 0 } }, \ { { 0, 4, 0 }, { 0, 4, 0 }, { 0, 8, 0 }, { 0, 8, 0 }, { 0, 8, 0 } }, \ { { 2, 0, 4 }, { 4, 0, 4 }, { 4, 0, 4 }, { 4, 0, 8 }, { 8, 0, 8 } }, \ { { 0, 2, 4 }, { 0, 2, 4 }, { 0, 4, 4 }, { 0, 4, 8 }, { 0, 4, 8 } }, \ { { 0, 0, 4 }, { 0, 0, 4 }, { 0, 0, 4 }, { 0, 0, 8 }, { 0, 0, 8 } }, \ { { 2, 2, 0 }, { 4, 2, 0 }, { 4, 4, 0 }, { 4, 4, 0 }, { 8, 4, 0 } }, \ { { 2, 0, 0 }, { 4, 0, 0 }, { 4, 0, 0 }, { 4, 0, 0 }, { 8, 0, 0 } }, \ { { 0, 2, 0 }, { 0, 2, 0 }, { 0, 4, 0 }, { 0, 4, 0 }, { 0, 4, 0 } }, \ { { 1, 0, 2 }, { 2, 0, 2 }, { 2, 0, 2 }, { 2, 0, 4 }, { 4, 0, 4 } }, \ { { 0, 0, 2 }, { 0, 0, 2 }, { 0, 0, 2 }, { 0, 0, 4 }, { 0, 0, 4 } }, \ { { 1, 0, 0 }, { 2, 0, 0 }, { 2, 0, 0 }, { 2, 0, 0 }, { 4, 0, 0 } }, \ { { 0, 0, 0 }, { 0, 0, 0 }, { 0, 0, 0 }, { 0, 0, 0 }, { 0, 0, 0 } }, \ } #define GEN11_MIPTAIL_SLOT_OFFSET_1D_SURFACE { \ /* | 128 bpe | 64 bpe | 32 bpe | 16 bpe | 8 bpe | */ \ { { 2048, 0, 0 }, { 4096, 0, 0 }, { 8192, 0, 0 }, { 16384, 0, 0 }, { 32768, 0, 0 } }, \ { { 1024, 0, 0 }, { 2048, 0, 0 }, { 4096, 0, 0 }, { 8192, 0, 0 }, { 16384, 0, 0 } }, \ { { 512, 0, 0 }, { 1024, 0, 0 }, { 2048, 0, 0 }, { 4096, 0, 0 }, { 8192, 0, 0 } }, \ { { 256, 0, 0 }, { 512, 0, 0 }, { 1024, 0, 0 }, { 2048, 0, 0 }, { 4096, 0, 0 } }, \ { { 128, 0, 0 }, { 256, 0, 0 }, { 512, 0, 0 }, { 1024, 0, 0 }, { 2048, 0, 0 } }, \ { { 96, 0, 0 }, { 192, 0, 0 }, { 384, 0, 0 }, { 768, 0, 0 }, { 1536, 0, 0 } }, \ { { 80, 0, 0 }, { 160, 0, 0 }, { 320, 0, 0 }, { 640, 0, 0 }, { 1280, 0, 0 } }, \ { { 64, 0, 0 }, { 128, 0, 0 }, { 256, 0, 0 }, { 512, 0, 0 }, { 1024, 0, 0 } }, \ { { 48, 0, 0 }, { 96, 0, 0 }, { 192, 0, 0 }, { 384, 0, 0 }, { 768, 0, 0 } }, \ { { 32, 0, 0 }, { 64, 0, 0 }, { 128, 0, 0 }, { 256, 0, 0 }, { 512, 0, 0 } }, \ { { 16, 0, 0 }, { 32, 0, 0 }, { 64, 0, 0 }, { 128, 0, 0 }, { 256, 0, 0 } }, \ { { 0, 0, 0 }, { 0, 0, 0 }, { 0, 0, 0 }, { 0, 0, 0 }, { 0, 0, 0 } }, \ { { 4, 0, 0 }, { 8, 0, 0 }, { 16, 0, 0 }, { 32, 0, 0 }, { 64, 0, 0 } }, \ { { 8, 0, 0 }, { 16, 0, 0 }, { 32, 0, 0 }, { 64, 0, 0 }, { 128, 0, 0 } }, \ { { 12, 0, 0 }, { 24, 0, 0 }, { 48, 0, 0 }, { 96, 0, 0 }, { 192, 0, 0 } }, \ } #define GEN11_MIPTAIL_SLOT_OFFSET_2D_SURFACE GEN10_MIPTAIL_SLOT_OFFSET_2D_SURFACE #define GEN11_MIPTAIL_SLOT_OFFSET_3D_SURFACE { \ /* | 128 bpe | 64 bpe | 32 bpe | 16 bpe | 8 bpe | */ \ { { 8, 0, 0 }, { 16, 0, 0 }, { 16, 0, 0 }, { 16, 0, 0 }, { 32, 0, 0 } }, \ { { 0, 8, 0 }, { 0, 8, 0 }, { 0, 16, 0 }, { 0, 16, 0 }, { 0, 16, 0 } }, \ { { 0, 0, 8 }, { 0, 0, 8 }, { 0, 0, 8 }, { 0, 0, 16 }, { 0, 0, 16 } }, \ { { 4, 0, 0 }, { 8, 0, 0 }, { 8, 0, 0 }, { 8, 0, 0 }, { 16, 0, 0 } }, \ { { 0, 4, 0 }, { 0, 4, 0 }, { 0, 8, 0 }, { 0, 8, 0 }, { 0, 8, 0 } }, \ { { 2, 0, 4 }, { 4, 0, 4 }, { 4, 0, 4 }, { 0, 4, 8 }, { 0, 4, 8 } }, \ { { 1, 0, 4 }, { 2, 0, 4 }, { 0, 4, 4 }, { 0, 0, 12 }, { 0, 0, 12 } }, \ { { 0, 0, 4 }, { 0, 0, 4 }, { 0, 0, 4 }, { 0, 0, 8 }, { 0, 0, 8 } }, \ { { 3, 0, 0 }, { 6, 0, 0 }, { 4, 4, 0 }, { 0, 4, 4 }, { 0, 4, 4 } }, \ { { 2, 0, 0 }, { 4, 0, 0 }, { 4, 0, 0 }, { 0, 4, 0 }, { 0, 4, 0 } }, \ { { 1, 0, 0 }, { 2, 0, 0 }, { 0, 4, 0 }, { 0, 0, 4 }, { 0, 0, 4 } }, \ { { 0, 0, 0 }, { 0, 0, 0 }, { 0, 0, 0 }, { 0, 0, 0 }, { 0, 0, 0 } }, \ { { 0, 0, 1 }, { 0, 0, 1 }, { 0, 0, 1 }, { 0, 0, 1 }, { 0, 0, 1 } }, \ { { 0, 0, 2 }, { 0, 0, 2 }, { 0, 0, 2 }, { 0, 0, 2 }, { 0, 0, 2 } }, \ { { 0, 0, 3 }, { 0, 0, 3 }, { 0, 0, 3 }, { 0, 0, 3 }, { 0, 0, 3 } }, \ } gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/Texture/GmmTextureAlloc.cpp000066400000000000000000001664261466655022700253120ustar00rootroot00000000000000/*============================================================================== Copyright(c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ============================================================================*/ #include "Internal/Common/GmmLibInc.h" ///////////////////////////////////////////////////////////////////////////////////// /// This functions sets the Tile Mode of the graphics surface /// /// @param[in] pTexInfo: Reference to ::GMM_TEXTURE_INFO /// ///////////////////////////////////////////////////////////////////////////////////// void GmmLib::GmmTextureCalc::SetTileMode(GMM_TEXTURE_INFO *pTexInfo) { const GMM_PLATFORM_INFO *pPlatform; pPlatform = GMM_OVERRIDE_PLATFORM_INFO(pTexInfo, pGmmLibContext); pTexInfo->TileMode = TILE_NONE; if(pTexInfo->Flags.Info.TiledYf || GMM_IS_64KB_TILE(pTexInfo->Flags)) { // clang-format off #define SET_TILE_MODE(Tile, Submode) \ { \ pTexInfo->TileMode = \ (pTexInfo->BitsPerPixel == 128) ? TILE_##Tile##_##Submode##_128bpe : \ (pTexInfo->BitsPerPixel == 64) ? TILE_##Tile##_##Submode##_64bpe : \ (pTexInfo->BitsPerPixel == 32) ? TILE_##Tile##_##Submode##_32bpe : \ (pTexInfo->BitsPerPixel == 16) ? TILE_##Tile##_##Submode##_16bpe : \ TILE_##Tile##_##Submode##_8bpe; \ } \ #define GENERATE_TILE_MODE(T, M1d, M2d, M2d_2x, M2d_4x, M2d_8x, M2d_16x, M3d) \ {\ switch (pTexInfo->Type)\ {\ case RESOURCE_1D:\ SET_TILE_MODE(T, M1d);\ break;\ case RESOURCE_2D:\ case RESOURCE_CUBE:\ switch (pTexInfo->MSAA.NumSamples)\ {\ case 1:\ SET_TILE_MODE(T, M2d);\ break;\ case 2:\ SET_TILE_MODE(T, M2d_2x);\ break;\ case 4:\ SET_TILE_MODE(T, M2d_4x);\ break;\ case 8:\ SET_TILE_MODE(T, M2d_8x);\ break;\ case 16:\ SET_TILE_MODE(T, M2d_16x);\ break;\ default:\ __GMM_ASSERT(0);\ }\ break;\ case RESOURCE_3D:\ SET_TILE_MODE(T, M3d);\ break;\ default:\ __GMM_ASSERT(0);\ }\ } // clang-format on if(pTexInfo->Flags.Info.TiledYf) { GENERATE_TILE_MODE(YF, 1D, 2D, 2D_2X, 2D_4X, 2D_8X, 2D_16X, 3D); pTexInfo->Flags.Info.TiledYf = 1; pTexInfo->Flags.Info.TiledYs = 0; } else { if(pGmmLibContext->GetSkuTable().FtrTileY) { GENERATE_TILE_MODE(YS, 1D, 2D, 2D_2X, 2D_4X, 2D_8X, 2D_16X, 3D); } else { if (pGmmLibContext->GetSkuTable().FtrXe2PlusTiling) { GENERATE_TILE_MODE(_64, 1D, 2D, 2D_2X, 2D_4X, 2D_8X, 2D_16X, 3D); } else { GENERATE_TILE_MODE(_64, 1D, 2D, 2D_2X, 2D_4X, 2D_4X, 2D_4X, 3D); } } pTexInfo->Flags.Info.TiledYf = 0; GMM_SET_64KB_TILE(pTexInfo->Flags, 1, pGmmLibContext); } GMM_SET_4KB_TILE(pTexInfo->Flags, pGmmLibContext->GetSkuTable().FtrTileY ? 1 : 0, pGmmLibContext); pTexInfo->Flags.Info.TiledX = 0; pTexInfo->Flags.Info.TiledW = 0; pTexInfo->Flags.Info.Linear = 0; #undef SET_TILE_MODE } else if(GMM_IS_4KB_TILE(pTexInfo->Flags)) { GMM_SET_4KB_TILE(pTexInfo->Flags, 1, pGmmLibContext); pTexInfo->Flags.Info.TiledYf = 0; pTexInfo->Flags.Info.TiledYs = 0; pTexInfo->Flags.Info.TiledX = 0; pTexInfo->Flags.Info.TiledW = 0; pTexInfo->Flags.Info.Linear = 0; GMM_SET_4KB_TILE_MODE(pTexInfo->TileMode, pGmmLibContext); } else if(pTexInfo->Flags.Info.TiledX) { pTexInfo->Flags.Info.TiledY = 0; pTexInfo->Flags.Info.TiledYf = 0; pTexInfo->Flags.Info.TiledYs = 0; pTexInfo->Flags.Info.TiledX = 1; pTexInfo->Flags.Info.TiledW = 0; pTexInfo->Flags.Info.Linear = 0; pTexInfo->TileMode = LEGACY_TILE_X; } else if(pTexInfo->Flags.Info.TiledW) { pTexInfo->Flags.Info.TiledY = 0; pTexInfo->Flags.Info.TiledYf = 0; pTexInfo->Flags.Info.TiledYs = 0; pTexInfo->Flags.Info.TiledX = 0; pTexInfo->Flags.Info.TiledW = 1; pTexInfo->Flags.Info.Linear = 0; pTexInfo->TileMode = LEGACY_TILE_Y; } else if(pTexInfo->Flags.Info.Linear) { pTexInfo->Flags.Info.TiledY = 0; pTexInfo->Flags.Info.TiledYf = 0; pTexInfo->Flags.Info.TiledYs = 0; pTexInfo->Flags.Info.TiledX = 0; pTexInfo->Flags.Info.TiledW = 0; pTexInfo->Flags.Info.Linear = 1; pTexInfo->TileMode = TILE_NONE; } else { GMM_ASSERTDPF(0, "No tiling preference set!"); } GMM_ASSERTDPF(pTexInfo->TileMode < GMM_TILE_MODES, "Invalid Tile Mode Set"); } ///////////////////////////////////////////////////////////////////////////////////// /// C Wrapper function for allocating a mip map or planar surface. The function /// outputs offset, size and pitch information by enforcing all the h/w alignment /// and restrictions. /// /// @param[in] pTexInfo: Reference to GMM_TEXTURE_INFO /// /// @return ::GMM_STATUS ///////////////////////////////////////////////////////////////////////////////////// #if(defined(__GMM_KMD__)) GMM_STATUS GmmTexAlloc(GMM_LIB_CONTEXT *pGmmLibContext, GMM_TEXTURE_INFO *pTexInfo) { GMM_TEXTURE_CALC *pTextureCalc = pGmmLibContext->GetTextureCalc(); return (pTextureCalc->AllocateTexture(pTexInfo)); } GMM_STATUS GmmTexLinearCCS(GMM_LIB_CONTEXT *pGmmLibContext, GMM_TEXTURE_INFO *pTexInfo, GMM_TEXTURE_INFO *pAuxTexInfo) { GMM_TEXTURE_CALC *pTextureCalc = pGmmLibContext->GetTextureCalc(); return (pTextureCalc->FillTexCCS(pTexInfo, pAuxTexInfo)); } #endif ///////////////////////////////////////////////////////////////////////////////////// /// Top level function for allocating a mip map or planar surface. The function /// outputs offset, size and pitch information by enforcing all the h/w alignment /// and restrictions. /// /// @param[in] pTexInfo: Reference to GMM_TEXTURE_INFO /// /// @return ::GMM_STATUS ///////////////////////////////////////////////////////////////////////////////////// GMM_STATUS GmmLib::GmmTextureCalc::AllocateTexture(GMM_TEXTURE_INFO *pTexInfo) { __GMM_BUFFER_TYPE Restrictions = {0}; GMM_STATUS Status; __GMM_ASSERTPTR(pTexInfo, GMM_ERROR); __GMM_ASSERTPTR(pGmmLibContext, GMM_ERROR); GMM_DPF_ENTER; GetTexRestrictions(pTexInfo, &Restrictions); if((Status = __GmmTexFillHAlignVAlign(pTexInfo, pGmmLibContext)) != GMM_SUCCESS) { return Status; } // Planar YUV resources treated special. Packed YUV treated like 2D/3D/Cube... if(GmmIsPlanar(pTexInfo->Format)) { Status = FillTexPlanar(pTexInfo, &Restrictions); if((Status == GMM_SUCCESS) && (ValidateTexInfo(pTexInfo, &Restrictions) == false)) { return GMM_ERROR; } if(GMM_SUCCESS != FillTexCCS(pTexInfo, pTexInfo)) { return GMM_ERROR; } return Status; } else { SetTileMode(pTexInfo); } switch(pTexInfo->Type) { case RESOURCE_2D: case RESOURCE_PRIMARY: case RESOURCE_SHADOW: case RESOURCE_STAGING: case RESOURCE_GDI: case RESOURCE_NNDI: case RESOURCE_HARDWARE_MBM: case RESOURCE_OVERLAY_INTERMEDIATE_SURFACE: case RESOURCE_IFFS_MAPTOGTT: #if _WIN32 case RESOURCE_WGBOX_ENCODE_DISPLAY: case RESOURCE_WGBOX_ENCODE_REFERENCE: #endif { Status = FillTex2D(pTexInfo, &Restrictions); break; } case RESOURCE_1D: { Status = FillTex1D(pTexInfo, &Restrictions); break; } case RESOURCE_3D: { Status = FillTex3D(pTexInfo, &Restrictions); break; } case RESOURCE_CUBE: { Status = FillTexCube(pTexInfo, &Restrictions); break; } case RESOURCE_SCRATCH: case RESOURCE_BUFFER: case RESOURCE_FBC: case RESOURCE_PWR_CONTEXT: case RESOURCE_KMD_BUFFER: case RESOURCE_NULL_CONTEXT_INDIRECT_STATE: case RESOURCE_PERF_DATA_QUEUE: case RESOURCE_HW_CONTEXT: case RESOURCE_TAG_PAGE: case RESOURCE_OVERLAY_DMA: case RESOURCE_GTT_TRANSFER_REGION: case RESOURCE_GLOBAL_BUFFER: case RESOURCE_CURSOR: case RESOURCE_GFX_CLIENT_BUFFER: #if _WIN32 case RESOURCE_WGBOX_ENCODE_STATE: case RESOURCE_WGBOX_ENCODE_TFD: #endif { Status = FillTexBlockMem(pTexInfo, &Restrictions); break; } default: { GMM_ASSERTDPF(0, "GmmTexAlloc: Unknown surface type!"); return GMM_INVALIDPARAM; } }; if(ValidateTexInfo(pTexInfo, &Restrictions) == false) { return GMM_ERROR; } if(GMM_SUCCESS != FillTexCCS(pTexInfo, pTexInfo)) { return GMM_ERROR; } return Status; } GMM_STATUS GmmLib::GmmTextureCalc::FillTexCCS(GMM_TEXTURE_INFO *pBaseSurf, GMM_TEXTURE_INFO *pTexInfo) { GMM_UNREFERENCED_PARAMETER(pBaseSurf); GMM_UNREFERENCED_PARAMETER(pTexInfo); return GMM_SUCCESS; } ///////////////////////////////////////////////////////////////////////////////////// /// This function will validate pTexInfo to make sure all the surface creation /// parameters are valid. /// /// @param[in] pTexInfo: Reference to ::GMM_TEXTURE_INFO /// @param[in] pRestrictions: Reference to surface alignment and size restrictions /// /// @return true/false ///////////////////////////////////////////////////////////////////////////////////// bool GmmLib::GmmTextureCalc::ValidateTexInfo(GMM_TEXTURE_INFO * pTexInfo, __GMM_BUFFER_TYPE *pRestrictions) { __GMM_ASSERTPTR(pTexInfo, false); __GMM_ASSERTPTR(pRestrictions, false); GMM_DPF_ENTER; if(pTexInfo->Pitch > pRestrictions->MaxPitch) { GMM_ASSERTDPF(0, "GmmLib::GmmTextureCalc::ValidateTexInfo: Pitch" "exceeds max HW pitch restriction.\r\n"); return false; } GMM_DPF_EXIT; return true; } ///////////////////////////////////////////////////////////////////////////////////// /// Sets the tiling type based on the required alignment parameters. /// /// @param[in] pTexInfo: Reference to ::GMM_TEXTURE_INFO /// @param[in] WidthBytesPhysical: Width in bytes of the surface /// @param[in] Height: Height of the surface /// @param[in] pBufferType: Reference to surface alignment and size restrictions /// /// @return ::GMM_STATUS ///////////////////////////////////////////////////////////////////////////////////// GMM_STATUS GmmLib::GmmTextureCalc::FillTexPitchAndSize(GMM_TEXTURE_INFO * pTexInfo, GMM_GFX_SIZE_T WidthBytesPhysical, uint32_t Height, __GMM_BUFFER_TYPE *pBufferType) { GMM_STATUS Status = GMM_SUCCESS; GMM_GFX_SIZE_T WidthBytesRender = 0; GMM_GFX_SIZE_T WidthBytesLock = 0; __GMM_ASSERTPTR(pTexInfo, GMM_ERROR); __GMM_ASSERTPTR(pBufferType, GMM_ERROR); GMM_DPF_ENTER; const GMM_PLATFORM_INFO *pPlatform = GMM_OVERRIDE_PLATFORM_INFO(pTexInfo, pGmmLibContext); // Make sure that we meet the minimum HW requirment for that buffer type WidthBytesPhysical = GFX_MAX(WidthBytesPhysical, pBufferType->MinPitch); if(pTexInfo->TileMode >= GMM_TILE_MODES) { GMM_ASSERTDPF(0, "Invalid parameter!"); return GMM_ERROR; } if(GMM_ISNOT_TILED(pPlatform->TileInfo[pTexInfo->TileMode])) { pTexInfo->LegacyFlags |= GMM_LINEAR; // For linear surace we need to make sure that physical pitch // meet the HW alignment (i.e DWORD or QWORD, ETC) WidthBytesPhysical = GFX_ALIGN(WidthBytesPhysical, pBufferType->PitchAlignment); WidthBytesRender = WidthBytesPhysical; WidthBytesLock = WidthBytesPhysical; } else { if(pTexInfo->Flags.Info.TiledY || pTexInfo->Flags.Info.TiledYf || pTexInfo->Flags.Info.TiledYs) { pTexInfo->LegacyFlags |= GMM_TILE_Y; } else if(pTexInfo->Flags.Info.TiledX == 1) { pTexInfo->LegacyFlags |= GMM_TILE_X; } else if(pTexInfo->Flags.Info.TiledW == 1) { pTexInfo->LegacyFlags |= GMM_TILE_W; } // Align Height to tile height boundary Height = GFX_ALIGN(Height, pPlatform->TileInfo[pTexInfo->TileMode].LogicalTileHeight); // Align Width to next tile boundary WidthBytesPhysical = GFX_ALIGN(WidthBytesPhysical, pPlatform->TileInfo[pTexInfo->TileMode].LogicalTileWidth); if(pTexInfo->Flags.Info.RenderCompressed || pTexInfo->Flags.Info.MediaCompressed) { if(!GMM_IS_64KB_TILE(pTexInfo->Flags) && !pGmmLibContext->GetSkuTable().FtrFlatPhysCCS) //Ys is naturally aligned to required 4 YF pages { // Align Pitch to 4-tile boundary WidthBytesPhysical = GFX_ALIGN(WidthBytesPhysical, 4 * pPlatform->TileInfo[pTexInfo->TileMode].LogicalTileWidth); } } // Calculate Alignment Restriction for rendering on the surface // NOTE: // WidthBytesPhysical == true physical pitch used to determine amount // of Pages need for a surface // WidthBytesRender == HW require pitch of a surface for rendering // (i.e. power2 // WidthBytesLock == Pitch when a surface is visible via Fence region. WidthBytesRender = WidthBytesLock = WidthBytesPhysical; // Align pitch to meet our HW requirment for each buffer WidthBytesRender = GFX_ALIGN(WidthBytesRender, pBufferType->RenderPitchAlignment); // Media Memory Compression : Allocate one memory tile wider than is required... pGmmLibContext->GetTextureCalc()->AllocateOneTileThanRequied(pTexInfo, WidthBytesRender, WidthBytesPhysical, WidthBytesLock); // check if locking a particular suface need to be power 2 or not if(pBufferType->NeedPow2LockAlignment) { WidthBytesLock = GFX_POW2_SIZE(WidthBytesPhysical); } // Align pitch to meet our HW requirment for each buffer // [1] 8K lock pitch is needed on Gen3 when we internally remap the // display surface in GmmGetDisplayStartAddress ( ). Gen4, // we don't remap due to Persurface tiling and stick to 64byte // lock pitch alignment. WidthBytesLock = GFX_ALIGN(WidthBytesLock, pBufferType->LockPitchAlignment); if((pTexInfo->Type == RESOURCE_PRIMARY) || pTexInfo->Flags.Gpu.FlipChain) { // [2] At creation time, we tell OS the Render size, not // SurfaceSizePhysical like other surfaces. Therefore, we change // the SurfaceSizePhysical to match render size for simplicity. WidthBytesPhysical = WidthBytesRender; } if(pGmmLibContext->GetWaTable().WaMsaa8xTileYDepthPitchAlignment && (pTexInfo->MSAA.NumSamples == 8) && GMM_IS_4KB_TILE(pTexInfo->Flags) && pTexInfo->Flags.Gpu.Depth) { WidthBytesLock = WidthBytesRender = WidthBytesPhysical = GFX_ALIGN(WidthBytesLock, GMM_BYTES(256)); } } __GMM_ASSERT(WidthBytesLock == WidthBytesPhysical && WidthBytesRender == WidthBytesPhysical && WidthBytesLock == WidthBytesRender); pTexInfo->Pitch = WidthBytesLock; //VirtualPadding override if(pTexInfo->Flags.Info.AllowVirtualPadding && pTexInfo->OverridePitch) { pTexInfo->Pitch = pTexInfo->OverridePitch; } // When lossless compression is enabled with plane width greater than 3840 and // horizontal panning, the surface pitch should be a multiple of 4 tiles. Since // GMM doesn't know about lossless compression status at allocation time, here // we apply the WA to all unified aux surfaces. if(pGmmLibContext->GetWaTable().WaLosslessCompressionSurfaceStride && pTexInfo->Flags.Gpu.UnifiedAuxSurface && (pTexInfo->BaseWidth > 3840)) { pTexInfo->Pitch = GFX_ALIGN(pTexInfo->Pitch, pPlatform->TileInfo[pTexInfo->TileMode].LogicalTileWidth * 4); } // If FBC is enabled with a linear surface, the surface pitch should be a multiple of // 8 cache lines (512 bytes). Since GMM doesn't know about FBC status, here we apply // the WA to all linear surfaces. // Xadapter surfaces has to be 128 Bytes aligned and hence we don't want this 512B alignment // for Xadapter. Eventually FBC will be disabled in case of Xadapter Linear surfaces if(pGmmLibContext->GetSkuTable().FtrFbc && pGmmLibContext->GetWaTable().WaFbcLinearSurfaceStride && pTexInfo->Flags.Gpu.FlipChain && pTexInfo->Flags.Info.Linear && !pTexInfo->Flags.Info.XAdapter) { if(pTexInfo->Flags.Gpu.FlipChainPreferred) { // Moderate down displayable flags if input parameters (.FlipChainPrefered) // deprioritise it, over Pitch alignement in this case. pTexInfo->Flags.Gpu.FlipChain = __GMM_IS_ALIGN(pTexInfo->Pitch, 512); } else { pTexInfo->Pitch = GFX_ALIGN(pTexInfo->Pitch, 512); } } // For CCS Aux Display Surf the surface stride should not exceed 8 times the LogicalTileWidth. if(pTexInfo->Flags.Gpu.CCS && pTexInfo->Flags.Gpu.__NonMsaaTileYCcs && pTexInfo->Flags.Gpu.FlipChain && (GFX_GET_CURRENT_RENDERCORE(pPlatform->Platform) >= IGFX_GEN9_CORE)) { __GMM_ASSERT(pTexInfo->Pitch <= (pPlatform->TileInfo[pTexInfo->TileMode].LogicalTileWidth * 8)); pTexInfo->Pitch = GFX_MIN(pTexInfo->Pitch, pPlatform->TileInfo[pTexInfo->TileMode].LogicalTileWidth * 8); } if(pTexInfo->Flags.Gpu.CCS && pTexInfo->Flags.Gpu.__NonMsaaTileYCcs && (pTexInfo->Pitch > pPlatform->TexAlign.CCS.MaxPitchinTiles * pPlatform->TileInfo[pTexInfo->TileMode].LogicalTileWidth)) { GMM_ASSERTDPF(0, "Aux Surface pitch too large!"); Status = GMM_ERROR; } if(pGmmLibContext->GetWaTable().Wa_15010089951) { // Default Tiling is set to Tile64 on FtrTileY disabled platforms uint8_t IsYUVSurface = ((GmmIsPlanar(pTexInfo->Format) && (!((pTexInfo->Format == GMM_FORMAT_BGRP) || (pTexInfo->Format == GMM_FORMAT_RGBP)))) || (GmmIsYUVPacked(pTexInfo->Format) && !((pTexInfo->Format == GMM_FORMAT_YVYU_2x1) || (pTexInfo->Format == GMM_FORMAT_UYVY_2x1) || (pTexInfo->Format == GMM_FORMAT_UYVY_2x1)))); //YCRCB* formats uint8_t IsYCrCbSurface = ((pTexInfo->Format == GMM_FORMAT_YCRCB_NORMAL) || (pTexInfo->Format == GMM_FORMAT_YCRCB_SWAPUV) || (pTexInfo->Format == GMM_FORMAT_YCRCB_SWAPUVY) || (pTexInfo->Format == GMM_FORMAT_YCRCB_SWAPY)); // Allocation needs to extend an extra tile in width when pitch is not an odd multiplication // of tile width which is 128 for Tile4 (YUV allocation is forced as Tile4). if(pTexInfo->Flags.Info.Tile4 && (IsYUVSurface || IsYCrCbSurface) && ((pTexInfo->Pitch / (pPlatform->TileInfo[pTexInfo->TileMode].LogicalTileWidth)) % 2 == 0)) { pTexInfo->Pitch = (pTexInfo->Pitch + (pPlatform->TileInfo[pTexInfo->TileMode].LogicalTileWidth)); } } // For NV12 Linear FlipChain surfaces, UV plane distance should be 4k Aligned. // Hence make the stride to align to 4k, so that UV distance will be 4k aligned. if(pGmmLibContext->GetWaTable().Wa4kAlignUVOffsetNV12LinearSurface && (pTexInfo->Format == GMM_FORMAT_NV12 || GmmIsP0xx(pTexInfo->Format)) && pTexInfo->Flags.Info.Linear && (!pTexInfo->Flags.Info.XAdapter) && ((pTexInfo->Type == RESOURCE_PRIMARY) || pTexInfo->Flags.Gpu.FlipChain)) { if(pTexInfo->Flags.Gpu.FlipChainPreferred) { // Moderate down displayable flags if input parameters (.FlipChainPrefered) // deprioritise it, over Pitch alignement in this case. pTexInfo->Flags.Gpu.FlipChain = __GMM_IS_ALIGN(pTexInfo->Pitch, GMM_KBYTE(4)); } else { pTexInfo->Pitch = GFX_ALIGN(pTexInfo->Pitch, GMM_KBYTE(4)); } } if((GFX_GET_CURRENT_PRODUCT(pPlatform->Platform) >= IGFX_METEORLAKE)) { pTexInfo->OffsetInfo.PlaneXe_LPG.PhysicalPitch = pTexInfo->Pitch; } { // Surface Sizes int64_t Size; if(pTexInfo->Flags.Gpu.S3d) { if(pGmmLibContext->GetSkuTable().FtrDisplayEngineS3d) // BDW+ Display Engine S3D (Tiled) { __GMM_ASSERT(!pTexInfo->Flags.Info.Linear); pTexInfo->S3d.BlankAreaOffset = 0; if(pTexInfo->Flags.Gpu.S3dDx && (pTexInfo->ArraySize == 2)) { pTexInfo->S3d.RFrameOffset = GFX_ULONG_CAST(pTexInfo->Pitch * pTexInfo->Alignment.QPitch); pTexInfo->S3d.TallBufferHeight = Height; } else { if(pTexInfo->Flags.Gpu.Overlay) { pTexInfo->S3d.RFrameOffset = GFX_ULONG_CAST(pTexInfo->Pitch * Height); Height = pTexInfo->S3d.TallBufferHeight = Height * 2; } else if(pTexInfo->Flags.Gpu.FlipChain) { pTexInfo->S3d.RFrameOffset = 0; pTexInfo->S3d.TallBufferHeight = Height; } else { // Something must be wrong. Not an S3D resource! __GMM_ASSERT(0); } } __GMM_ASSERT(__GMM_IS_ALIGN(pTexInfo->S3d.RFrameOffset, PAGE_SIZE)); } else if(pTexInfo->Flags.Gpu.S3dDx) // DX S3D (Tiled) { __GMM_ASSERT(!pTexInfo->Flags.Info.Linear || !pTexInfo->Flags.Gpu.Overlay); __GMM_ASSERT(pTexInfo->ArraySize <= 1); // S3D framebuffer arrays are not supported (pre-BDW). pTexInfo->S3d.BlankAreaOffset = GFX_ULONG_CAST(pTexInfo->Pitch * pTexInfo->BaseHeight); pTexInfo->S3d.RFrameOffset = GFX_ULONG_CAST(pTexInfo->Pitch * (pTexInfo->S3d.DisplayModeHeight + pTexInfo->S3d.NumBlankActiveLines)); Height = pTexInfo->S3d.TallBufferHeight = GFX_ALIGN( (pTexInfo->BaseHeight * 2) + pTexInfo->S3d.NumBlankActiveLines, pPlatform->TileInfo[pTexInfo->TileMode].LogicalTileHeight); } else // Legacy S3D { __GMM_ASSERT(pTexInfo->Flags.Info.Linear); pTexInfo->S3d.BlankAreaOffset = GFX_ULONG_CAST(pTexInfo->Pitch * pTexInfo->BaseHeight); pTexInfo->S3d.RFrameOffset = GFX_ULONG_CAST(pTexInfo->Pitch * (pTexInfo->S3d.DisplayModeHeight + pTexInfo->S3d.NumBlankActiveLines)); if(pTexInfo->Flags.Gpu.Overlay) { Height = pTexInfo->S3d.TallBufferHeight = pTexInfo->BaseHeight + pTexInfo->S3d.NumBlankActiveLines + pTexInfo->S3d.DisplayModeHeight; } else if(pTexInfo->Flags.Gpu.FlipChain) { __GMM_ASSERT(pTexInfo->S3d.DisplayModeHeight == pTexInfo->BaseHeight); pTexInfo->S3d.TallBufferHeight = (pTexInfo->BaseHeight * 2) + pTexInfo->S3d.NumBlankActiveLines; } else { // Something must be wrong. Not an S3D resource! __GMM_ASSERT(0); } __GMM_ASSERT(__GMM_IS_ALIGN(pTexInfo->S3d.RFrameOffset, PAGE_SIZE)); __GMM_ASSERT(__GMM_IS_ALIGN(pTexInfo->S3d.BlankAreaOffset, PAGE_SIZE)); } // Calculate surface size (physical). Size = pTexInfo->Pitch * Height; // Calculate tall buffer size (virtual). pTexInfo->S3d.TallBufferSize = GFX_ULONG_CAST(pTexInfo->Pitch * pTexInfo->S3d.TallBufferHeight); } else { Size = (int64_t)pTexInfo->Pitch * Height; if(pTexInfo->Type == RESOURCE_3D && !pTexInfo->Flags.Info.Linear) { Size *= pPlatform->TileInfo[pTexInfo->TileMode].LogicalTileDepth; } if((pTexInfo->Flags.Info.TiledYf || GMM_IS_64KB_TILE(pTexInfo->Flags)) && (pTexInfo->MSAA.NumSamples > 1) && (pTexInfo->Flags.Gpu.Depth == 0 && pTexInfo->Flags.Gpu.SeparateStencil == 0)) { // For color buffer (meaning not depth or stencil buffer) // The width/height for TileYf/Ys MSAA surfaces are not expanded (using GmmExpandWidth/Height functions) // because pitch for these surfaces is in their non-expanded dimensions. So, the pitch // is also non-expanded units. That's why, we multiply by the sample size here to get the correct size. if(pGmmLibContext->GetSkuTable().FtrTileY) { Size *= pTexInfo->MSAA.NumSamples; } else { //XeHP, DG2 if (!pGmmLibContext->GetSkuTable().FtrXe2PlusTiling && (pTexInfo->MSAA.NumSamples == 8 || pTexInfo->MSAA.NumSamples == 16)) { uint64_t SliceSize = pTexInfo->Pitch * Height; SliceSize *= 4; // multiple by samples per tile Size = (int64_t)SliceSize; } else { Size *= pTexInfo->MSAA.NumSamples; } } } if((pTexInfo->Flags.Info.TiledY && pTexInfo->Flags.Gpu.TiledResource)) { //Pad align surface to 64KB ie Tile size Size = GFX_ALIGN(Size, GMM_KBYTE(64)); } if (pGmmLibContext->GetSkuTable().FtrXe2Compression && pTexInfo->Flags.Info.Linear) { Size = GFX_ALIGN(Size, GMM_BYTES(256)); // for all linear resources starting Xe2, align overall size to compression block size. For subresources, 256B alignment is not needed, needed only for overall resource // on older platforms, all linear resources get Halign = 128B which ensures overall size to be a multiple of compression block size of 128B, // so this is needed only for linear resources on Xe2 where HAlign continues to be at 128B, but compression block size has doubled to 256B } // Buffer Sampler Padding... if((pTexInfo->Type == RESOURCE_BUFFER) && pGmmLibContext->GetWaTable().WaNoMinimizedTrivialSurfacePadding && !pTexInfo->Flags.Wa.NoBufferSamplerPadding && !pTexInfo->Flags.Info.ExistingSysMem && // <-- Currently using separate padding WA in OCL (and rarity/luck in other UMD's). // <-- Never sampled from. !pTexInfo->Flags.Gpu.Query && !pTexInfo->Flags.Gpu.HistoryBuffer && !pTexInfo->Flags.Gpu.State && !pTexInfo->Flags.Gpu.StateDx9ConstantBuffer) // These can be sampled from, so they need the padding... // pTexInfo->Flags.Gpu.Constant // pTexInfo->Flags.Gpu.Index // pTexInfo->Flags.Gpu.Stream // pTexInfo->Flags.Gpu.Vertex { uint32_t BufferSizeAlignment; uint32_t BufferSizePadding; // SURFTYPE_BUFFER's that can be sampled from must have their size // padded to a multiple of 256 buffer elements and then have an // additional 16 bytes of padding beyond that. Currently, the GMM // doesn't receive a buffer's element type/size, so (until that's // revamped) we'll assume the worst-case of 128-bit elements--which // means padding to 256 * 128 / 8 = 4KB and then adding 16 bytes. // In the case of BDW:A0, size is padded to a multiple of 512 buffer // elements instead of 256--which means padding to 8KB. BufferSizeAlignment = (GFX_GET_CURRENT_RENDERCORE(pPlatform->Platform) >= IGFX_GEN8_CORE) ? 8192 : 4096; BufferSizePadding = 16; Size = GFX_ALIGN(Size, BufferSizeAlignment) + BufferSizePadding; } // HiZ Clear Color requires some small data at the end of the allocation to // store the color data. if(pTexInfo->Flags.Gpu.HiZ && pTexInfo->Flags.Gpu.IndirectClearColor) { Size += GMM_HIZ_CLEAR_COLOR_SIZE; } if(pTexInfo->Flags.Info.ExistingSysMem && !pTexInfo->ExistingSysMem.IsGmmAllocated && !pTexInfo->ExistingSysMem.IsPageAligned) { // Do not modify Size } else { Size = GFX_ALIGN(Size, PAGE_SIZE); } } int64_t SurfaceMaxSize = 0; if(pTexInfo->Flags.Gpu.NoRestriction) { SurfaceMaxSize = pPlatform->NoRestriction.MaxWidth; } else if(pTexInfo->Flags.Gpu.TiledResource) { SurfaceMaxSize = GMM_TBYTE(1); } else { SurfaceMaxSize = pPlatform->SurfaceMaxSize; } if(Size <= SurfaceMaxSize) { pTexInfo->Size = Size; } else { #if defined(__GMM_KMD__) || defined(__linux__) GMM_ASSERTDPF(0, "Surface too large!"); #endif Status = GMM_ERROR; } } { uint64_t TotalAlignment = (((uint64_t)((uint32_t)(pTexInfo->Alignment.BaseAlignment))) * ((uint32_t)(pBufferType->Alignment))); if(!pTexInfo->Alignment.BaseAlignment || __GMM_IS_ALIGN(pBufferType->Alignment, pTexInfo->Alignment.BaseAlignment)) { pTexInfo->Alignment.BaseAlignment = pBufferType->Alignment; } else if(__GMM_IS_ALIGN(pTexInfo->Alignment.BaseAlignment, pBufferType->Alignment)) { // Do nothing: pTexInfo->Alignment.BaseAlignment is properly alighned } else if(TotalAlignment > 0xFFFFFFFF) { GMM_ASSERTDPF(0, "Client requested alignment is too high, failing the allocation to match HW requiremnets. \r\n"); Status = GMM_ERROR; } else { pTexInfo->Alignment.BaseAlignment = pTexInfo->Alignment.BaseAlignment * pBufferType->Alignment; GMM_ASSERTDPF(0, "Client requested alignment that is not properly aligned to HW requirements." "Alignment is going to be much higher to match both client and HW requirements.\r\n"); } } if((pTexInfo->Flags.Gpu.TilePool && (GFX_GET_CURRENT_RENDERCORE(pPlatform->Platform) >= IGFX_GEN9_CORE)) || (pTexInfo->Flags.Info.Undefined64KBSwizzle) || GMM_IS_64KB_TILE(pTexInfo->Flags)) { pTexInfo->Alignment.BaseAlignment = (GFX_IS_ALIGNED(pTexInfo->Alignment.BaseAlignment, GMM_KBYTE(64))) ? pTexInfo->Alignment.BaseAlignment : GMM_KBYTE(64); } if(pGmmLibContext->GetWaTable().WaCompressedResourceRequiresConstVA21 && pTexInfo->Flags.Gpu.MMC) { pTexInfo->Alignment.BaseAlignment = GMM_MBYTE(4); } GMM_DPF_EXIT; return (Status); } // FillTexPitchAndSize ///////////////////////////////////////////////////////////////////////////////////// /// This function will Setup a planar surface allocation. /// /// @param[in] pTexInfo: Reference to ::GMM_TEXTURE_INFO /// @param[in] pRestrictions: Reference to surface alignment and size restrictions. /// /// @return ::GMM_STATUS ///////////////////////////////////////////////////////////////////////////////////// GMM_STATUS GMM_STDCALL GmmLib::GmmTextureCalc::FillTexPlanar(GMM_TEXTURE_INFO * pTexInfo, __GMM_BUFFER_TYPE *pRestrictions) { uint32_t WidthBytesPhysical, Height, YHeight, VHeight; GMM_STATUS Status; bool UVPacked = false; GMM_DPF_ENTER; __GMM_ASSERTPTR(pTexInfo, GMM_ERROR); __GMM_ASSERTPTR(pRestrictions, GMM_ERROR); __GMM_ASSERT(!pTexInfo->Flags.Info.TiledW); pTexInfo->TileMode = TILE_NONE; const GMM_PLATFORM_INFO *pPlatform = GMM_OVERRIDE_PLATFORM_INFO(pTexInfo, pGmmLibContext); WidthBytesPhysical = GFX_ULONG_CAST(pTexInfo->BaseWidth) * pTexInfo->BitsPerPixel >> 3; Height = VHeight = 0; YHeight = pTexInfo->BaseHeight; switch(pTexInfo->Format) { case GMM_FORMAT_IMC1: // IMC1 = IMC3 with Swapped U/V case GMM_FORMAT_IMC3: case GMM_FORMAT_MFX_JPEG_YUV420: // Same as IMC3. // YYYYYYYY // YYYYYYYY // YYYYYYYY // YYYYYYYY // UUUU // UUUU // VVVV // VVVV case GMM_FORMAT_MFX_JPEG_YUV422V: // Similar to IMC3 but U/V are full width. // YYYYYYYY // YYYYYYYY // YYYYYYYY // YYYYYYYY // UUUUUUUU // UUUUUUUU // VVVVVVVV // VVVVVVVV { VHeight = GFX_ALIGN(GFX_CEIL_DIV(YHeight, 2), GMM_IMCx_PLANE_ROW_ALIGNMENT); YHeight = GFX_ALIGN(YHeight, GMM_IMCx_PLANE_ROW_ALIGNMENT); Height = YHeight + 2 * VHeight; // One VHeight for V and one for U. pTexInfo->OffsetInfo.Plane.NoOfPlanes = 3; break; } case GMM_FORMAT_MFX_JPEG_YUV411R_TYPE: //Similar to IMC3 but U/V are quarther height and full width. //YYYYYYYY //YYYYYYYY //YYYYYYYY //YYYYYYYY //UUUUUUUU //VVVVVVVV { VHeight = GFX_ALIGN(GFX_CEIL_DIV(YHeight, 4), GMM_IMCx_PLANE_ROW_ALIGNMENT); YHeight = GFX_ALIGN(YHeight, GMM_IMCx_PLANE_ROW_ALIGNMENT); Height = YHeight + 2 * VHeight; pTexInfo->OffsetInfo.Plane.NoOfPlanes = 3; break; } case GMM_FORMAT_MFX_JPEG_YUV411: // Similar to IMC3 but U/V are quarter width and full height. // YYYYYYYY // YYYYYYYY // YYYYYYYY // YYYYYYYY // UU // UU // UU // UU // VV // VV // VV // VV case GMM_FORMAT_MFX_JPEG_YUV422H: // Similar to IMC3 but U/V are full height. // YYYYYYYY // YYYYYYYY // YYYYYYYY // YYYYYYYY // UUUU // UUUU // UUUU // UUUU // VVVV // VVVV // VVVV // VVVV case GMM_FORMAT_MFX_JPEG_YUV444: // Similar to IMC3 but U/V are full size. #if _WIN32 case GMM_FORMAT_WGBOX_YUV444: case GMM_FORMAT_WGBOX_PLANAR_YUV444: #endif // YYYYYYYY // YYYYYYYY // YYYYYYYY // YYYYYYYY // UUUUUUUU // UUUUUUUU // UUUUUUUU // UUUUUUUU // VVVVVVVV // VVVVVVVV // VVVVVVVV // VVVVVVVV { YHeight = GFX_ALIGN(YHeight, GMM_IMCx_PLANE_ROW_ALIGNMENT); VHeight = YHeight; Height = YHeight + 2 * VHeight; pTexInfo->OffsetInfo.Plane.NoOfPlanes = 3; break; } case GMM_FORMAT_BGRP: case GMM_FORMAT_RGBP: { //For RGBP linear Tile keep resource Offset non aligned and for other Tile format to be 16-bit aligned if(pTexInfo->Flags.Info.Linear) { VHeight = YHeight; Height = YHeight + 2 * VHeight; pTexInfo->OffsetInfo.Plane.NoOfPlanes = 3; } else { YHeight = GFX_ALIGN(YHeight, GMM_IMCx_PLANE_ROW_ALIGNMENT); VHeight = YHeight; Height = YHeight + 2 * VHeight; pTexInfo->OffsetInfo.Plane.NoOfPlanes = 3; } break; } case GMM_FORMAT_IMC2: // IMC2 = IMC4 with Swapped U/V case GMM_FORMAT_IMC4: { // YYYYYYYY // YYYYYYYY // YYYYYYYY // YYYYYYYY // UUUUVVVV // UUUUVVVV YHeight = GFX_ALIGN(YHeight, GMM_IMCx_PLANE_ROW_ALIGNMENT); VHeight = GFX_CEIL_DIV(YHeight, 2); WidthBytesPhysical = GFX_ALIGN(WidthBytesPhysical, 2); // If odd YWidth, pitch bumps-up to fit rounded-up U/V planes. Height = YHeight + VHeight; // With SURFACE_STATE.XOffset support, the U-V interface has // much lighter restrictions--which will be naturally met by // surface pitch restrictions (i.e. dividing an IMC2/4 pitch // by 2--to get the U/V interface--will always produce a safe // XOffset value). // Not technically UV packed but sizing works out the same // if the resource is std swizzled UVPacked = true; pTexInfo->OffsetInfo.Plane.NoOfPlanes = 2; break; } case GMM_FORMAT_NV12: case GMM_FORMAT_NV21: case GMM_FORMAT_NV11: case GMM_FORMAT_P010: case GMM_FORMAT_P012: case GMM_FORMAT_P016: case GMM_FORMAT_P208: case GMM_FORMAT_P216: { // YYYYYYYY // YYYYYYYY // YYYYYYYY // YYYYYYYY // [UV-Packing] YHeight = GFX_ALIGN(pTexInfo->BaseHeight, __GMM_EVEN_ROW); if((pTexInfo->Format == GMM_FORMAT_NV12) || (pTexInfo->Format == GMM_FORMAT_NV21) || (pTexInfo->Format == GMM_FORMAT_P010) || (pTexInfo->Format == GMM_FORMAT_P012) || (pTexInfo->Format == GMM_FORMAT_P016)) { VHeight = GFX_CEIL_DIV(YHeight, 2); // U/V plane half of Y Height = YHeight + VHeight; } else { VHeight = YHeight; // U/V plane is same as Y Height = YHeight + VHeight; } if((pTexInfo->Format == GMM_FORMAT_NV12) || (pTexInfo->Format == GMM_FORMAT_NV21) || (pTexInfo->Format == GMM_FORMAT_P010) || (pTexInfo->Format == GMM_FORMAT_P012) || (pTexInfo->Format == GMM_FORMAT_P016) || (pTexInfo->Format == GMM_FORMAT_P208) || (pTexInfo->Format == GMM_FORMAT_P216)) { WidthBytesPhysical = GFX_ALIGN(WidthBytesPhysical, 2); // If odd YWidth, pitch bumps-up to fit rounded-up U/V planes. } else //if(pTexInfo->Format == GMM_FORMAT_NV11) { // Tiling not supported, since YPitch != UVPitch... pTexInfo->Flags.Info.TiledY = 0; pTexInfo->Flags.Info.TiledYf = 0; pTexInfo->Flags.Info.TiledYs = 0; pTexInfo->Flags.Info.TiledX = 0; pTexInfo->Flags.Info.Linear = 1; } UVPacked = true; pTexInfo->OffsetInfo.Plane.NoOfPlanes = 2; break; } case GMM_FORMAT_I420: // IYUV & I420: are identical to YV12 except, case GMM_FORMAT_IYUV: // U & V pl.s are reversed. case GMM_FORMAT_YV12: case GMM_FORMAT_YVU9: { // YYYYYYYY // YYYYYYYY // YYYYYYYY // YYYYYYYY // VVVVVV.. <-- V and U planes follow the Y plane, as linear // ..UUUUUU arrays--without respect to pitch. uint32_t YSize, UVSize, YVSizeRShift; uint32_t YSizeForUVPurposes, YSizeForUVPurposesDimensionalAlignment; YSize = WidthBytesPhysical * YHeight; // YVU9 has one U/V pixel for each 4x4 Y block. // The others have one U/V pixel for each 2x2 Y block. // YVU9 has a Y:V size ratio of 16 (4x4 --> 1). // The others have a ratio of 4 (2x2 --> 1). YVSizeRShift = (pTexInfo->Format != GMM_FORMAT_YVU9) ? 2 : 4; // If a Y plane isn't fully-aligned to its Y-->U/V block size, the // extra/unaligned Y pixels still need corresponding U/V pixels--So // for the purpose of computing the UVSize, we must consider a // dimensionally "rounded-up" YSize. (E.g. a 13x5 YVU9 Y plane would // require 4x2 U/V planes--the same UVSize as a fully-aligned 16x8 Y.) YSizeForUVPurposesDimensionalAlignment = (pTexInfo->Format != GMM_FORMAT_YVU9) ? 2 : 4; YSizeForUVPurposes = GFX_ALIGN(WidthBytesPhysical, YSizeForUVPurposesDimensionalAlignment) * GFX_ALIGN(YHeight, YSizeForUVPurposesDimensionalAlignment); UVSize = 2 * // <-- U + V (YSizeForUVPurposes >> YVSizeRShift); Height = GFX_CEIL_DIV(YSize + UVSize, WidthBytesPhysical); // Tiling not supported, since YPitch != UVPitch... pTexInfo->Flags.Info.TiledY = 0; pTexInfo->Flags.Info.TiledYf = 0; pTexInfo->Flags.Info.TiledYs = 0; pTexInfo->Flags.Info.TiledX = 0; pTexInfo->Flags.Info.Linear = 1; pTexInfo->OffsetInfo.Plane.NoOfPlanes = 1; break; } default: { GMM_ASSERTDPF(0, "Unexpected format"); return GMM_ERROR; } } // Align Height to even row to avoid hang if HW over-fetch Height = GFX_ALIGN(Height, __GMM_EVEN_ROW); SetTileMode(pTexInfo); // MMC is not supported for linear formats. if(pTexInfo->Flags.Gpu.MMC) { if(!(pTexInfo->Flags.Info.TiledY || pTexInfo->Flags.Info.TiledYf || pTexInfo->Flags.Info.TiledYs)) { pTexInfo->Flags.Gpu.MMC = 0; } } // Legacy Planar "Linear Video" Restrictions... if(pTexInfo->Flags.Info.Linear && !pTexInfo->Flags.Wa.NoLegacyPlanarLinearVideoRestrictions) { pRestrictions->LockPitchAlignment = GFX_MAX(pRestrictions->LockPitchAlignment, GMM_BYTES(64)); pRestrictions->MinPitch = GFX_MAX(pRestrictions->MinPitch, GMM_BYTES(64)); pRestrictions->PitchAlignment = GFX_MAX(pRestrictions->PitchAlignment, GMM_BYTES(64)); pRestrictions->RenderPitchAlignment = GFX_MAX(pRestrictions->RenderPitchAlignment, GMM_BYTES(64)); } // Multiply overall pitch alignment for surfaces whose U/V planes have a // pitch down-scaled from that of Y--Since the U/V pitches must meet the // original restriction, the Y pitch must meet a scaled-up multiple. if((pTexInfo->Format == GMM_FORMAT_I420) || (pTexInfo->Format == GMM_FORMAT_IYUV) || (pTexInfo->Format == GMM_FORMAT_NV11) || (pTexInfo->Format == GMM_FORMAT_YV12) || (pTexInfo->Format == GMM_FORMAT_YVU9)) { uint32_t LShift = (pTexInfo->Format != GMM_FORMAT_YVU9) ? 1 : // UVPitch = 1/2 YPitch 2; // UVPitch = 1/4 YPitch pRestrictions->LockPitchAlignment <<= LShift; pRestrictions->MinPitch <<= LShift; pRestrictions->PitchAlignment <<= LShift; pRestrictions->RenderPitchAlignment <<= LShift; } // For Tiled Planar surfaces, the planes must be tile-boundary aligned. // Actual alignment is handled in FillPlanarOffsetAddress, but height // and width must be adjusted for correct size calculation if(GMM_IS_TILED(pPlatform->TileInfo[pTexInfo->TileMode])) { uint32_t TileHeight = pGmmLibContext->GetPlatformInfo().TileInfo[pTexInfo->TileMode].LogicalTileHeight; uint32_t TileWidth = pGmmLibContext->GetPlatformInfo().TileInfo[pTexInfo->TileMode].LogicalTileWidth; pTexInfo->OffsetInfo.Plane.IsTileAlignedPlanes = true; Height = GFX_ALIGN(YHeight, TileHeight) + (GFX_ALIGN(VHeight, TileHeight) * (UVPacked ? 1 : 2)); if(pTexInfo->Format == GMM_FORMAT_IMC2 || // IMC2, IMC4 needs even tile columns pTexInfo->Format == GMM_FORMAT_IMC4) { // If the UV planes are packed then the surface pitch must be // padded out so that the tile-aligned UV data will fit. // This means that an odd Y plane width must be padded out // with an additional tile. Even widths do not need padding uint32_t TileCols = GFX_CEIL_DIV(WidthBytesPhysical, TileWidth); if(TileCols % 2) { WidthBytesPhysical = (TileCols + 1) * TileWidth; } } if(pTexInfo->Flags.Info.TiledYs || pTexInfo->Flags.Info.TiledYf) { pTexInfo->Flags.Info.RedecribedPlanes = true; } } //Special case LKF MMC compressed surfaces if(pTexInfo->Flags.Gpu.MMC && pTexInfo->Flags.Gpu.UnifiedAuxSurface && pTexInfo->Flags.Info.TiledY) { uint32_t TileHeight = pGmmLibContext->GetPlatformInfo().TileInfo[pTexInfo->TileMode].LogicalTileHeight; Height = GFX_ALIGN(YHeight, TileHeight) + GFX_ALIGN(VHeight, TileHeight); } // Vary wide planar tiled planar formats do not support MMC pre gen11. All formats do not support // MMC above 16k bytes wide, while Yf NV12 does not support above 8k - 128 bytes. if((GFX_GET_CURRENT_RENDERCORE(pPlatform->Platform) <= IGFX_GEN10_CORE) && (pTexInfo->Flags.Info.TiledY || pTexInfo->Flags.Info.TiledYf || pTexInfo->Flags.Info.TiledYs)) { if(((pTexInfo->BaseWidth * pTexInfo->BitsPerPixel / 8) >= GMM_KBYTE(16)) || (pTexInfo->Format == GMM_FORMAT_NV12 && pTexInfo->Flags.Info.TiledYf && (pTexInfo->BaseWidth * pTexInfo->BitsPerPixel / 8) >= (GMM_KBYTE(8) - 128))) { pTexInfo->Flags.Gpu.MMC = 0; } } if(pTexInfo->Flags.Info.RedecribedPlanes) { if(false == RedescribeTexturePlanes(pTexInfo, &WidthBytesPhysical)) { __GMM_ASSERT(false); } } if((Status = // <-- Note assignment. FillTexPitchAndSize( pTexInfo, WidthBytesPhysical, Height, pRestrictions)) == GMM_SUCCESS) { FillPlanarOffsetAddress(pTexInfo); } // Planar & hybrid 2D arrays supported in DX11.1+ spec but not HW. Memory layout // is defined by SW requirements; Y plane must be 4KB aligned. if(pTexInfo->ArraySize > 1) { GMM_GFX_SIZE_T ElementSizeBytes = pTexInfo->Size; int64_t LargeSize; // Size should always be page aligned. __GMM_ASSERT((pTexInfo->Size % PAGE_SIZE) == 0); if((LargeSize = (int64_t)ElementSizeBytes * pTexInfo->ArraySize) <= pPlatform->SurfaceMaxSize) { pTexInfo->OffsetInfo.Plane.ArrayQPitch = ElementSizeBytes; pTexInfo->Size = LargeSize; } else { GMM_ASSERTDPF(0, "Surface too large!"); Status = GMM_ERROR; } } GMM_DPF_EXIT; return (Status); } // FillTexPlanar ///////////////////////////////////////////////////////////////////////////////////// /// This function calculates the size and pitch for the linear buffer based on h/w /// alignment and size restrictions. /// /// @param[in] pTexInfo: Reference to ::GMM_TEXTURE_INFO /// @param[in] pRestrictions: Reference to surface alignment and size restrictions /// /// @return ::GMM_STATUS ///////////////////////////////////////////////////////////////////////////////////// GMM_STATUS GmmLib::GmmTextureCalc::FillTexBlockMem(GMM_TEXTURE_INFO * pTexInfo, __GMM_BUFFER_TYPE *pRestrictions) { GMM_GFX_SIZE_T WidthBytesPhysical; uint32_t BitsPerPixel; GMM_STATUS Status; __GMM_ASSERTPTR(pTexInfo, GMM_ERROR); __GMM_ASSERTPTR(pRestrictions, GMM_ERROR); __GMM_ASSERT(pTexInfo->BitsPerPixel == GMM_BITS(8) || (pTexInfo->Flags.Info.AllowVirtualPadding)); __GMM_ASSERT(pTexInfo->BaseHeight == 1); __GMM_ASSERT(pTexInfo->Flags.Info.Linear == 1); __GMM_ASSERT(pTexInfo->Flags.Info.TiledW == 0); __GMM_ASSERT(pTexInfo->Flags.Info.TiledX == 0); __GMM_ASSERT(pTexInfo->Flags.Info.TiledY == 0); __GMM_ASSERT(pTexInfo->Flags.Info.TiledYf == 0); __GMM_ASSERT(pTexInfo->Flags.Info.TiledYs == 0); GMM_DPF_ENTER; // Width interpreted in bytes. BitsPerPixel = pTexInfo->BitsPerPixel; WidthBytesPhysical = pTexInfo->BaseWidth * BitsPerPixel >> 3; Status = GMM_SUCCESS; // Clients can allocate Buffers and Structured Buffers by specifying either // total size (in BaseWidth) or as an array of structs with the ArraySize // and BaseWidth parameters (where BaseWidth = size of the arrayed struct). if((pTexInfo->Type == RESOURCE_BUFFER) && (pTexInfo->ArraySize > 1)) { uint64_t __WidthBytesPhysical = WidthBytesPhysical; __WidthBytesPhysical *= pTexInfo->ArraySize; if(__WidthBytesPhysical <= pRestrictions->MaxPitch) { WidthBytesPhysical = (GMM_GFX_SIZE_T)__WidthBytesPhysical; } else { GMM_ASSERTDPF(0, "Surface too large!"); Status = GMM_ERROR; } } if(Status == GMM_SUCCESS) { // Make sure minimum width and alignment is met. WidthBytesPhysical = GFX_MAX(WidthBytesPhysical, pRestrictions->MinPitch); WidthBytesPhysical = GFX_ALIGN(WidthBytesPhysical, pRestrictions->PitchAlignment); Status = FillTexPitchAndSize(pTexInfo, WidthBytesPhysical, pTexInfo->BaseHeight, pRestrictions); } GMM_DPF_EXIT; return (Status); } ///////////////////////////////////////////////////////////////////////////////////// /// This function does any special-case conversion from client-provided pseudo creation /// parameters to actual parameters for CCS. /// /// @param[in] pTexInfo: Reference to ::GMM_TEXTURE_INFO /// /// @return ::GMM_STATUS ///////////////////////////////////////////////////////////////////////////////////// GMM_STATUS GMM_STDCALL GmmLib::GmmTextureCalc::MSAACCSUsage(GMM_TEXTURE_INFO *pTexInfo) { GMM_STATUS Status = GMM_SUCCESS; //const GMM_PLATFORM_INFO *pPlatform = GMM_OVERRIDE_PLATFORM_INFO(pTexInfo); if(pTexInfo->MSAA.NumSamples > 1) // CCS for MSAA Compression { Status = MSAACompression(pTexInfo); } else // Non-MSAA CCS Use (i.e. Render Target Fast Clear) { if(!pTexInfo->Flags.Info.TiledW && ((!pTexInfo->Flags.Info.Linear) || (GMM_IS_4KB_TILE(pTexInfo->Flags) || GMM_IS_64KB_TILE(pTexInfo->Flags) || (pTexInfo->Type == RESOURCE_BUFFER && pTexInfo->Flags.Info.Linear))) && //!Yf - deprecate Yf ((pTexInfo->MaxLod == 0) && (pTexInfo->ArraySize <= 1)) && (((pTexInfo->BitsPerPixel == 32) || (pTexInfo->BitsPerPixel == 64) || (pTexInfo->BitsPerPixel == 128)))) { // For non-MSAA CCS usage, the four tables of // requirements: // (1) RT Alignment (GMM Don't Care: Occurs Naturally) // (2) ClearRect Alignment // (3) ClearRect Scaling (GMM Don't Care: GHAL3D Matter) // (4) Non-MSAA CCS Sizing // Gen8+: // Since mip-mapped and arrayed surfaces are supported, we // deal with alignment later at per mip level. Here, we set // tiling type only. TileX is not supported on Gen9+. // Pre-Gen8: // (!) For all the above, there are separate entries for // 32/64/128bpp--and then deals with PIXEL widths--Here, // though, we will unify by considering 8bpp table entries // (unlisted--i.e. do the math)--and deal with BYTE widths. // (1) RT Alignment -- The surface width and height don't // need to be padded to RT CL granularity. On HSW, all tiled // RT's will have appropriate alignment (given 4KB surface // base and no mip-map support) and appropriate padding // (due to tile padding). On BDW+, GMM uses H/VALIGN that // will guarantee the MCS RT alignment for all subresources. // (2) ClearRect Alignment -- I.e. FastClears must be done // with certain granularity: // TileY: 512 Bytes x 128 Lines // TileX: 1024 Bytes x 64 Lines // So a CCS must be sized to match that granularity (though // the RT itself need not be fully padded to that // granularity to use FastClear). // (4) Non-MSAA CCS Sizing -- CCS sizing is based on the // size of the FastClear (with granularity padding) for the // paired RT. CCS's (byte widths and heights) are scaled // down from their RT's by: // TileY: 32 x 32 // TileX: 64 x 16 // ### Example ############################################# // RT: 800x600, 32bpp, TileY // 8bpp: 3200x600 // FastClear: 3584x640 (for TileY FastClear Granularity of 512x128) // CCS: 112x20 (for TileY RT:CCS Sizing Downscale of 32x32) uint32_t AlignmentFactor = pGmmLibContext->GetWaTable().WaDoubleFastClearWidthAlignment ? 2 : 1; pTexInfo->BaseWidth = pTexInfo->BaseWidth * pTexInfo->BitsPerPixel / 8; pTexInfo->BitsPerPixel = 8; pTexInfo->Format = GMM_FORMAT_R8_UINT; if(GMM_IS_4KB_TILE(pTexInfo->Flags)) //-------- Fast Clear Granularity { // /--- RT:CCS Sizing Downscale pTexInfo->BaseWidth = GFX_ALIGN(pTexInfo->BaseWidth, 512 * AlignmentFactor) / 32; pTexInfo->BaseHeight = GFX_ALIGN(pTexInfo->BaseHeight, 128) / 32; } else //if(pTexInfo->Flags.Info.TiledX) { pTexInfo->BaseWidth = GFX_ALIGN(pTexInfo->BaseWidth, 1024 * AlignmentFactor) / 64; pTexInfo->BaseHeight = GFX_ALIGN(pTexInfo->BaseHeight, 64) / 16; } } else { GMM_ASSERTDPF(0, "Illegal CCS creation parameters!"); Status = GMM_ERROR; } } return Status; } ///////////////////////////////////////////////////////////////////////////////////// /// This function does any special-case conversion from client-provided pseudo creation /// parameters to actual parameters for CCS for MSAA Compression. /// /// @param[in] pTexInfo: Reference to ::GMM_TEXTURE_INFO /// /// @return ::GMM_STATUS ///////////////////////////////////////////////////////////////////////////////////// GMM_STATUS GmmLib::GmmTextureCalc::MSAACompression(GMM_TEXTURE_INFO *pTexInfo) { GMM_STATUS Status = GMM_SUCCESS; if((pTexInfo->MSAA.NumSamples == 2) || (pTexInfo->MSAA.NumSamples == 4)) { pTexInfo->BitsPerPixel = 8; pTexInfo->Format = GMM_FORMAT_R8_UINT; } else if(pTexInfo->MSAA.NumSamples == 8) { pTexInfo->BitsPerPixel = 32; pTexInfo->Format = GMM_FORMAT_R32_UINT; } else //if(pTexInfo->MSAA.NumSamples == 16) { pTexInfo->BitsPerPixel = 64; pTexInfo->Format = GMM_FORMAT_GENERIC_64BIT; } if((Status = __GmmTexFillHAlignVAlign(pTexInfo, pGmmLibContext)) != GMM_SUCCESS) // Need to get our alignment (matching RT) before overwriting our RT's MSAA setting. { return Status; } pTexInfo->MSAA.NumSamples = 1; // CCS itself isn't MSAA'ed. pTexInfo->Flags.Gpu.__MsaaTileMcs = 1; return Status; } ///////////////////////////////////////////////////////////////////////////////////// ///Allocate one memory tile wider than is required for Media Memory Compression /// /// @param[in] See function definition. /// /// @return :: ///////////////////////////////////////////////////////////////////////////////////// void GMM_STDCALL GmmLib::GmmTextureCalc::AllocateOneTileThanRequied(GMM_TEXTURE_INFO *pTexInfo, GMM_GFX_SIZE_T & WidthBytesRender, GMM_GFX_SIZE_T & WidthBytesPhysical, GMM_GFX_SIZE_T & WidthBytesLock) { const GMM_PLATFORM_INFO *pPlatform = GMM_OVERRIDE_PLATFORM_INFO(pTexInfo, pGmmLibContext); if(pTexInfo->Flags.Gpu.MMC && !pTexInfo->Flags.Gpu.UnifiedAuxSurface) { WidthBytesRender += pPlatform->TileInfo[pTexInfo->TileMode].LogicalTileWidth; WidthBytesPhysical = WidthBytesLock = WidthBytesRender; } } gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/Texture/GmmTextureOffset.cpp000066400000000000000000001111351466655022700254710ustar00rootroot00000000000000/*============================================================================== Copyright(c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ============================================================================*/ #include "Internal/Common/GmmLibInc.h" ///////////////////////////////////////////////////////////////////////////////////// /// GMM Interface to return lock or render aligned offset to a mip map /// /// @param[in] pTexInfo: ptr to ::GMM_TEXTURE_INFO /// @param[in] pReqInfo: ptr to GMM_REQ_OFFSET_INFO to store offset info /// /// @return ::GMM_STATUS ///////////////////////////////////////////////////////////////////////////////////// GMM_STATUS GmmTexGetMipMapOffset(GMM_TEXTURE_INFO * pTexInfo, GMM_REQ_OFFSET_INFO *pReqInfo, GMM_LIB_CONTEXT * pGmmLibContext) { GMM_STATUS Status = GMM_SUCCESS; bool RestoreRenderReq = false; bool RestoreLockReq = false; GMM_TEXTURE_CALC *pTextureCalc; GMM_DPF_ENTER; __GMM_ASSERTPTR(pTexInfo, GMM_ERROR); __GMM_ASSERTPTR(pReqInfo, GMM_ERROR); __GMM_ASSERT(pReqInfo->CubeFace <= __GMM_NO_CUBE_MAP); pTextureCalc = GMM_OVERRIDE_TEXTURE_CALC(pTexInfo, pGmmLibContext); if((pReqInfo->Plane >= GMM_MAX_PLANE) || (pReqInfo->Plane < GMM_NO_PLANE) || (pReqInfo->MipLevel >= GMM_MAX_MIPMAP)) { GMM_ASSERTDPF(0, "Invalid parameter!"); return GMM_ERROR; } if((pTexInfo->TileMode >= GMM_TILE_MODES) || (pTexInfo->TileMode < TILE_NONE)) { GMM_ASSERTDPF(0, "Invalid parameter!"); return GMM_ERROR; } // Retrieve offset info at pReqInfo->MipLevel if(pReqInfo->ReqLock) { if(pReqInfo->ReqRender) { pReqInfo->ReqRender = 0; RestoreRenderReq = true; } if(pTextureCalc->GetTexLockOffset(pTexInfo, pReqInfo) != GMM_SUCCESS) { GMM_ASSERTDPF(0, "ReqLock failed!"); Status = GMM_ERROR; } } if(RestoreRenderReq == true) pReqInfo->ReqRender = 1; if(pReqInfo->ReqLock) { pReqInfo->ReqLock = 0; RestoreLockReq = 1; } if(pReqInfo->ReqRender) { if(pTextureCalc->GetTexRenderOffset(pTexInfo, pReqInfo) != GMM_SUCCESS) { GMM_ASSERTDPF(0, "ReqRender failed!"); Status = GMM_ERROR; } } if(RestoreLockReq) { pReqInfo->ReqLock = 1; } if(pReqInfo->ReqStdLayout) { if(pTextureCalc->GetTexStdLayoutOffset(pTexInfo, pReqInfo) != GMM_SUCCESS) { GMM_ASSERTDPF(0, "ReqStdLayout failed!"); Status = GMM_ERROR; } } GMM_DPF_EXIT; return Status; } ///////////////////////////////////////////////////////////////////////////////////// /// Calculates StdLayout offsets and related pitches of /// subresource.. /// /// @param[in] pTexInfo: ptr to ::GMM_TEXTURE_INFO /// @param[in] pReqInfo: ptr to GMM_REQ_OFFSET_INFO to store offset info /// /// @return ::GMM_STATUS ///////////////////////////////////////////////////////////////////////////////////// GMM_STATUS GmmLib::GmmTextureCalc::GetTexStdLayoutOffset(GMM_TEXTURE_INFO * pTexInfo, GMM_REQ_OFFSET_INFO *pReqInfo) { uint32_t ReqArrayIndex; bool NeedSurfaceSize = false; __GMM_ASSERT(pTexInfo); __GMM_ASSERT(GMM_IS_64KB_TILE(pTexInfo->Flags) || pTexInfo->Flags.Info.TiledYf); __GMM_ASSERT( (pTexInfo->Type == RESOURCE_2D) || (pTexInfo->Type == RESOURCE_3D) || (pTexInfo->Type == RESOURCE_CUBE)); __GMM_ASSERT(GmmIsPlanar(pTexInfo->Format) == false); // Planar not support if(pReqInfo->StdLayout.Offset == -1) // Special Req for Surface Size { NeedSurfaceSize = true; ReqArrayIndex = // TODO(Medium): Add planar support. (pTexInfo->ArraySize * ((pTexInfo->Type == RESOURCE_CUBE) ? 6 : 1)); } else { ReqArrayIndex = (pReqInfo->ArrayIndex * ((pTexInfo->Type == RESOURCE_CUBE) ? 6 : 1)); } { uint32_t TileSize = 0; // TileYs (64) and TileYf (4) if(GMM_IS_64KB_TILE(pTexInfo->Flags)) { TileSize = GMM_KBYTE(64); } else if(GMM_IS_4KB_TILE(pTexInfo->Flags)) { TileSize = GMM_KBYTE(4); } const GMM_PLATFORM_INFO *pPlatform = GMM_OVERRIDE_PLATFORM_INFO(pTexInfo, pGmmLibContext); uint32_t BytesPerElement = pTexInfo->BitsPerPixel / CHAR_BIT; GMM_TILE_MODE TileMode = pTexInfo->TileMode; struct { uint32_t Width, Height, Depth; } Element, Tile; __GMM_ASSERT(TileMode < GMM_TILE_MODES); GetCompressionBlockDimensions( pTexInfo->Format, &Element.Width, &Element.Height, &Element.Depth); Tile.Width = (pPlatform->TileInfo[TileMode].LogicalTileWidth / BytesPerElement) * Element.Width; Tile.Height = pPlatform->TileInfo[TileMode].LogicalTileHeight * Element.Height; Tile.Depth = pPlatform->TileInfo[TileMode].LogicalTileDepth * Element.Depth; { GMM_GFX_ADDRESS TargetLodOffset = 0; GMM_GFX_SIZE_T PrevMipSize = 0; GMM_GFX_SIZE_T SliceOffset = 0; GMM_GFX_SIZE_T SlicePitch = 0; uint32_t Lod; uint32_t EffectiveMaxLod = (ReqArrayIndex == 0) ? pReqInfo->MipLevel : GFX_MIN(pTexInfo->MaxLod, pTexInfo->Alignment.MipTailStartLod); pReqInfo->StdLayout.Offset = 0; for(Lod = 0; Lod <= EffectiveMaxLod; Lod++) { GMM_GFX_SIZE_T MipWidth = GmmTexGetMipWidth(pTexInfo, Lod); uint32_t MipHeight = GmmTexGetMipHeight(pTexInfo, Lod); uint32_t MipDepth = GmmTexGetMipDepth(pTexInfo, Lod); uint32_t MipCols = GFX_ULONG_CAST( GFX_CEIL_DIV( MipWidth, Tile.Width)); uint32_t MipRows = GFX_CEIL_DIV( MipHeight, Tile.Height); uint32_t MipDepthTiles = GFX_CEIL_DIV( MipDepth, Tile.Depth); uint32_t RowPitch = MipCols * TileSize; // Bytes from one tile row to the next. uint32_t DepthPitch = RowPitch * MipRows; // Bytes from one depth slice of tiles to the next. if(Lod <= pTexInfo->Alignment.MipTailStartLod) { pReqInfo->StdLayout.Offset += PrevMipSize; } if(Lod == pReqInfo->MipLevel) { TargetLodOffset = pReqInfo->StdLayout.Offset; pReqInfo->StdLayout.TileRowPitch = RowPitch; pReqInfo->StdLayout.TileDepthPitch = DepthPitch; } PrevMipSize = (GMM_GFX_SIZE_T)DepthPitch * MipDepthTiles; SlicePitch += DepthPitch; } if(pReqInfo->Slice > 0) { SliceOffset = SlicePitch * pReqInfo->Slice; } if(!NeedSurfaceSize && pReqInfo->MipLevel >= pTexInfo->Alignment.MipTailStartLod) { pReqInfo->StdLayout.Offset += (ReqArrayIndex * (pReqInfo->StdLayout.Offset + PrevMipSize)) + GetMipTailByteOffset(pTexInfo, pReqInfo->MipLevel); } else { pReqInfo->StdLayout.Offset = ReqArrayIndex * (pReqInfo->StdLayout.Offset + PrevMipSize) + TargetLodOffset; } pReqInfo->StdLayout.Offset += SliceOffset; } } return GMM_SUCCESS; } ///////////////////////////////////////////////////////////////////////////////////// /// Calculates offset address of a sub resource(i.e. Mip Map, Cube face, volume texture) /// /// @param[in] pTexInfo: ptr to ::GMM_TEXTURE_INFO /// @param[in] pReqInfo: ptr to GMM_REQ_OFFSET_INFO to store offset info /// /// @return ::GMM_STATUS ///////////////////////////////////////////////////////////////////////////////////// GMM_STATUS GmmLib::GmmTextureCalc::GetTexLockOffset(GMM_TEXTURE_INFO * pTexInfo, GMM_REQ_OFFSET_INFO *pReqInfo) { GMM_STATUS Result = GMM_SUCCESS; GMM_GFX_SIZE_T AddressOffset; uint32_t Pitch, Slice; uint32_t MipHeight, MipWidth, MipLevel; uint32_t NumberOfMipsInSingleRow, SliceRow; __GMM_ASSERTPTR(pTexInfo, GMM_ERROR); __GMM_ASSERTPTR(pReqInfo, GMM_ERROR); const GMM_PLATFORM_INFO *pPlatform = GMM_OVERRIDE_PLATFORM_INFO(pTexInfo, pGmmLibContext); // set default value AddressOffset = 0; Pitch = GFX_ULONG_CAST(pTexInfo->Pitch); MipLevel = pReqInfo->MipLevel; Slice = pReqInfo->Slice; if(GmmIsPlanar(pTexInfo->Format)) { AddressOffset = GetMipMapByteAddress(pTexInfo, pReqInfo); pReqInfo->Lock.Offset64 = AddressOffset; pReqInfo->Lock.Pitch = Pitch; // Adjust returned pitch for non-uniform-pitch U/V queries... if((pReqInfo->Plane == GMM_PLANE_U) || (pReqInfo->Plane == GMM_PLANE_V)) { switch(pTexInfo->Format) { case GMM_FORMAT_I420: case GMM_FORMAT_IYUV: case GMM_FORMAT_YV12: case GMM_FORMAT_NV11: pReqInfo->Lock.Pitch /= 2; break; case GMM_FORMAT_YVU9: pReqInfo->Lock.Pitch /= 4; break; default: //Cool--Constant pitch across all planes. break; } } return Result; } switch(pTexInfo->Type) { case RESOURCE_3D: { if(GFX_GET_CURRENT_RENDERCORE(pPlatform->Platform) >= IGFX_GEN9_CORE) { AddressOffset = GFX_ULONG_CAST(GetMipMapByteAddress(pTexInfo, pReqInfo)); // Bytes from one slice to the next... pReqInfo->Lock.Gen9PlusSlicePitch = GFX_ULONG_CAST(pTexInfo->OffsetInfo.Texture2DOffsetInfo.ArrayQPitchLock); } else { MipHeight = pTexInfo->BaseHeight >> MipLevel; MipWidth = GFX_ULONG_CAST(pTexInfo->BaseWidth) >> MipLevel; AlignTexHeightWidth(pTexInfo, &MipHeight, &MipWidth); // See how many mip can fit in one row NumberOfMipsInSingleRow = GFX_2_TO_POWER_OF(MipLevel); SliceRow = Slice / NumberOfMipsInSingleRow; // get the base address + Slice pitch AddressOffset = pTexInfo->OffsetInfo.Texture3DOffsetInfo.Offset[MipLevel]; pReqInfo->Lock.Mip0SlicePitch = GFX_ULONG_CAST(pTexInfo->OffsetInfo.Texture3DOffsetInfo.Mip0SlicePitch); // Actual address is offset based on requested slice AddressOffset += (GMM_GFX_SIZE_T)SliceRow * MipHeight * Pitch; // Get to particular slice if(Slice % NumberOfMipsInSingleRow) { AddressOffset += (((GMM_GFX_SIZE_T)(Slice % NumberOfMipsInSingleRow) * MipWidth * pTexInfo->BitsPerPixel) >> 3); } } break; } case RESOURCE_CUBE: case RESOURCE_2D: case RESOURCE_1D: { AddressOffset = GetMipMapByteAddress(pTexInfo, pReqInfo); break; } default: { // These resources dont' have multiple levels of detail AddressOffset = 0; break; } } pReqInfo->Lock.Offset64 = AddressOffset; pReqInfo->Lock.Pitch = Pitch; return Result; } ///////////////////////////////////////////////////////////////////////////////////// /// Function used to align width and height of texture so that it satisfy our HW /// restriction /// /// @param[in] pTexInfo: ptr to ::GMM_TEXTURE_INFO /// @param[in] pHeight: ptr to height of mip /// @param[in] pWidth: ptr to width of mip /// ///////////////////////////////////////////////////////////////////////////////////// void GmmLib::GmmTextureCalc::AlignTexHeightWidth(GMM_TEXTURE_INFO *pTexInfo, uint32_t * pHeight, uint32_t * pWidth) { uint32_t MipWidth = 0; uint32_t MipHeight = 0; uint32_t UnitAlignHeight = 0; uint32_t UnitAlignWidth = 0; uint8_t Compress = 0; __GMM_ASSERTPTR(pTexInfo, VOIDRETURN); __GMM_ASSERTPTR(pWidth, VOIDRETURN); __GMM_ASSERTPTR(pHeight, VOIDRETURN); __GMM_ASSERTPTR(pGmmLibContext, VOIDRETURN); MipWidth = *pWidth; MipHeight = *pHeight; UnitAlignWidth = pTexInfo->Alignment.HAlign; UnitAlignHeight = pTexInfo->Alignment.VAlign; Compress = GmmIsCompressed(pGmmLibContext, pTexInfo->Format); MipWidth = GFX_MAX(MipWidth, UnitAlignWidth); MipHeight = GFX_MAX(MipHeight, UnitAlignHeight); MipWidth = GFX_ALIGN(MipWidth, UnitAlignWidth); MipHeight = GFX_ALIGN(MipHeight, UnitAlignHeight); if(Compress) { uint32_t CompressHeight, CompressWidth, CompressDepth; GetCompressionBlockDimensions(pTexInfo->Format, &CompressWidth, &CompressHeight, &CompressDepth); MipWidth /= CompressWidth; MipHeight /= CompressHeight; } else if(pTexInfo->Flags.Gpu.SeparateStencil && pTexInfo->Flags.Info.TiledW) { MipWidth *= 2; MipHeight /= 2; } *pHeight = MipHeight; *pWidth = MipWidth; } ///////////////////////////////////////////////////////////////////////////////////// /// Function used to calculate the render aligned offset of a given surface /// /// @param[in] pTexInfo: ptr to ::GMM_TEXTURE_INFO /// @param[in] pReqInfo: ptr to GMM_REQ_OFFSET_INFO /// /// @return ::GMM_STATUS ///////////////////////////////////////////////////////////////////////////////////// GMM_STATUS GmmLib::GmmTextureCalc::GetTexRenderOffset(GMM_TEXTURE_INFO * pTexInfo, GMM_REQ_OFFSET_INFO *pReqInfo) { const GMM_TILE_INFO * pTileInfo = NULL; GMM_GFX_SIZE_T AddressOffset = 0; GMM_GFX_SIZE_T RenderAlignOffset = 0; uint32_t OffsetX = 0; uint32_t OffsetY = 0; uint32_t OffsetZ = 0; const GMM_PLATFORM_INFO *pPlatform = NULL; __GMM_ASSERTPTR(pTexInfo, GMM_ERROR); __GMM_ASSERTPTR(pReqInfo, GMM_ERROR); pPlatform = GMM_OVERRIDE_PLATFORM_INFO(pTexInfo, pGmmLibContext); pTileInfo = &pPlatform->TileInfo[pTexInfo->TileMode]; AddressOffset = GetMipMapByteAddress(pTexInfo, pReqInfo); if(GMM_IS_TILED(*pTileInfo)) { uint32_t TileAlignedOffsetX = 0; uint32_t TileAlignedOffsetY = 0; GMM_GFX_SIZE_T MipTailByteOffset = 0; //--- Compute Tile-Aligned Offset, and Corresponding X/Y Offsets ------- // Render/Tiled-Aligned offsets and corresponding X/Y offsets are used // to program the Surface Base Address and X/Y Offset fields of a // SURFACE_STATE. For a given subresource, the tiled-aligned offset // addresses the tile containing the base of the subresource; the X/Y // offsets then give the additional offsets into the tile of the // subresource base. (Though in SURFACE_STATE, X Offset is specified in // pixels, this function will return the X Offset in bytes. Y Offset is // in pixel rows.) if((pTexInfo->Flags.Info.TiledYf || GMM_IS_64KB_TILE(pTexInfo->Flags)) && (pReqInfo->MipLevel >= pTexInfo->Alignment.MipTailStartLod)) { MipTailByteOffset = GetMipTailByteOffset(pTexInfo, pReqInfo->MipLevel); // For MipTail, Offset is really with respect to start of MipTail, // so taking out individual Mipoffset within miptail region to get correct Tile aligned offset. AddressOffset -= MipTailByteOffset; } if(!pTexInfo->Flags.Info.RedecribedPlanes) { GMM_GFX_SIZE_T Pitch = pTexInfo->Pitch; if(!pTexInfo->Pitch) { // If no pitch exists, but the surface is still marked as tiled, then it is a 1D TileYf/Ys surface. // Technically no pitch exists for 1D surfaces, but we will fake it to make calculations work below. // Since 1D surfaces only have an X-dimension, this Pitch calculation is only used for OffsetX calculation. Pitch = pTexInfo->Size; } if(pTexInfo->Flags.Gpu.SeparateStencil && pTexInfo->Flags.Info.TiledW) { OffsetX = GFX_ULONG_CAST(AddressOffset % Pitch); TileAlignedOffsetX = GFX_ALIGN_FLOOR(OffsetX, pTileInfo->LogicalTileWidth / 2); OffsetX -= TileAlignedOffsetX; } else { OffsetX = GFX_ULONG_CAST(AddressOffset % Pitch); TileAlignedOffsetX = GFX_ALIGN_FLOOR(OffsetX, pTileInfo->LogicalTileWidth); OffsetX -= TileAlignedOffsetX; } if(pTexInfo->Pitch) { if(pTexInfo->Flags.Gpu.SeparateStencil && pTexInfo->Flags.Info.TiledW) { //Expt: YOffset ignore row-interleave -- verify both 2d/3d mips OffsetY = GFX_ULONG_CAST(AddressOffset / pTexInfo->Pitch); OffsetY *= 2; TileAlignedOffsetY = GFX_ALIGN_FLOOR(OffsetY, pTileInfo->LogicalTileHeight * 2 * pTileInfo->LogicalTileDepth); OffsetY -= TileAlignedOffsetY; TileAlignedOffsetY /= 2; } else { OffsetY = GFX_ULONG_CAST(AddressOffset / pTexInfo->Pitch); TileAlignedOffsetY = GFX_ALIGN_FLOOR(OffsetY, pTileInfo->LogicalTileHeight * pTileInfo->LogicalTileDepth); OffsetY -= TileAlignedOffsetY; } } RenderAlignOffset = TileAlignedOffsetY * pTexInfo->Pitch + (TileAlignedOffsetX / pTileInfo->LogicalTileWidth) * pTileInfo->LogicalSize; // For Gen9+, Miptail Lods should be reported in a way that // - Base Address equals tile-aligned "Miptail start address" // - OffsetX equals to offset (in bytes) from "Miptail start Lod" to "current Lod" in geometric X direction // - OffsetY and OffsetZ are their pixel distance from "Miptail start Lod" to "current Lod" in geometric Y, Z directions // Note: only Tile Yf and TileYs have Miptails and their Mips are always "tile aligned" if((pTexInfo->Flags.Info.TiledYf || GMM_IS_64KB_TILE(pTexInfo->Flags)) && (pReqInfo->MipLevel >= pTexInfo->Alignment.MipTailStartLod) && // Planar surfaces do not support MIPs !GmmIsPlanar(pTexInfo->Format)) { GetMipTailGeometryOffset(pTexInfo, pReqInfo->MipLevel, &OffsetX, &OffsetY, &OffsetZ); } } else { // Std swizzled and UV packed planes begin at tile-aligned // offsets and do not support MIPs, so no adjustment is needed RenderAlignOffset = AddressOffset; OffsetX = OffsetY = OffsetZ = 0; } } else { // Linear case make sure Render address is DWORD aligned. RenderAlignOffset = GFX_ALIGN_FLOOR(AddressOffset, GMM_BYTES(4)); if(pTexInfo->Pitch) { OffsetX = GFX_ULONG_CAST((AddressOffset - RenderAlignOffset) % pTexInfo->Pitch); OffsetY = GFX_ULONG_CAST((AddressOffset - RenderAlignOffset) / pTexInfo->Pitch); } else { // One-dimensional textures (no height) OffsetX = GFX_ULONG_CAST(AddressOffset - RenderAlignOffset); OffsetY = 0; } } pReqInfo->Render.Offset64 = RenderAlignOffset; pReqInfo->Render.XOffset = GFX_ULONG_CAST(OffsetX); pReqInfo->Render.YOffset = GFX_ULONG_CAST(OffsetY); pReqInfo->Render.ZOffset = GFX_ULONG_CAST(OffsetZ); return GMM_SUCCESS; } // __GmmGetRenderAlignAddress ///////////////////////////////////////////////////////////////////////////////////// /// Function used to calculate byte address of a specified mip map /// /// @param[in] pTexInfo: ptr to ::GMM_TEXTURE_INFO /// @param[in] pReqInfo: ptr to GMM_REQ_OFFSET_INFO /// /// @return ::GMM_GFX_SIZE_T byte offset ///////////////////////////////////////////////////////////////////////////////////// GMM_GFX_SIZE_T GmmLib::GmmTextureCalc::GetMipMapByteAddress(GMM_TEXTURE_INFO * pTexInfo, GMM_REQ_OFFSET_INFO *pReqInfo) { GMM_GFX_SIZE_T ArrayQPitch, MipMapByteAddress, Pitch; uint32_t MipLevel; __GMM_ASSERTPTR(pTexInfo, GMM_ERROR); __GMM_ASSERTPTR(pReqInfo, GMM_ERROR); __GMM_ASSERT(!(pTexInfo->Flags.Gpu.CCS && !pTexInfo->Flags.Gpu.UnifiedAuxSurface)); __GMM_ASSERT(pReqInfo->Plane < GMM_MAX_PLANE); MipLevel = pReqInfo->MipLevel; Pitch = pTexInfo->Pitch; ArrayQPitch = pReqInfo->ReqRender ? pTexInfo->OffsetInfo.Texture2DOffsetInfo.ArrayQPitchRender : pTexInfo->OffsetInfo.Texture2DOffsetInfo.ArrayQPitchLock; const GMM_PLATFORM_INFO *pPlatform = GMM_OVERRIDE_PLATFORM_INFO(pTexInfo, pGmmLibContext); if(pTexInfo->Type == RESOURCE_3D && !pTexInfo->Flags.Info.Linear) { ArrayQPitch *= pPlatform->TileInfo[pTexInfo->TileMode].LogicalTileDepth; } if((GFX_GET_CURRENT_RENDERCORE(pPlatform->Platform) >= IGFX_GEN8_CORE) && ((pTexInfo->MSAA.NumSamples > 1) && !(pTexInfo->Flags.Gpu.Depth || pTexInfo->Flags.Gpu.SeparateStencil || GMM_IS_64KB_TILE(pTexInfo->Flags) || pTexInfo->Flags.Info.TiledYf))) { ArrayQPitch *= pTexInfo->MSAA.NumSamples; } if(GmmIsPlanar(pTexInfo->Format)) { uint32_t Plane = pReqInfo->Plane; uint32_t OffsetX = 0; uint32_t OffsetY = 0; if(Plane < GMM_MAX_PLANE) { OffsetX = GFX_ULONG_CAST(pTexInfo->OffsetInfo.Plane.X[Plane]); OffsetY = GFX_ULONG_CAST(pTexInfo->OffsetInfo.Plane.Y[Plane]); ArrayQPitch = pTexInfo->OffsetInfo.Plane.ArrayQPitch; } MipMapByteAddress = (OffsetY * Pitch) + OffsetX; __GMM_ASSERT(!pReqInfo->ArrayIndex || (pReqInfo->ArrayIndex < pTexInfo->ArraySize)); MipMapByteAddress += (ArrayQPitch * pReqInfo->ArrayIndex); } else { switch(pTexInfo->Type) { case RESOURCE_CUBE: { uint32_t CubeFace = pReqInfo->CubeFace; GMM_ASSERTDPF( // Validate Cube Map Params... (!pReqInfo->ArrayIndex || (pReqInfo->ArrayIndex < pTexInfo->ArraySize)) && (pReqInfo->CubeFace < __GMM_MAX_CUBE_FACE) && (pReqInfo->CubeFace != __GMM_NO_CUBE_MAP) && (pReqInfo->Plane == GMM_NO_PLANE) && (pReqInfo->Slice == 0), "Invalid parameter!"); // Support for CubeMap Arrays using 2D Arrays MipMapByteAddress = pTexInfo->OffsetInfo.Texture2DOffsetInfo.Offset[MipLevel]; MipMapByteAddress += (ArrayQPitch * ((6 * pReqInfo->ArrayIndex) + CubeFace)); break; } case RESOURCE_2D: case RESOURCE_1D: { MipMapByteAddress = pTexInfo->OffsetInfo.Texture2DOffsetInfo.Offset[MipLevel]; if(pReqInfo->ArrayIndex) { MipMapByteAddress += (ArrayQPitch * pReqInfo->ArrayIndex); } break; } case RESOURCE_3D: { if(GFX_GET_CURRENT_RENDERCORE(pPlatform->Platform) >= IGFX_GEN9_CORE) { MipMapByteAddress = pTexInfo->OffsetInfo.Texture2DOffsetInfo.Offset[MipLevel]; if(pReqInfo->Slice) { MipMapByteAddress += (ArrayQPitch * pReqInfo->Slice); } } else { MipMapByteAddress = Get3DMipByteAddress(pTexInfo, pReqInfo); } break; } default: { // These resources don't have multiple levels of detail MipMapByteAddress = 0; break; } } } MipMapByteAddress += pTexInfo->Flags.Gpu.S3d ? GetDisplayFrameOffset(pTexInfo, pReqInfo) : 0; return MipMapByteAddress; } ///////////////////////////////////////////////////////////////////////////////////// /// Utility function used to calculate byte address to a mip slice /// /// @param[in] pTexInfo: ptr to ::GMM_TEXTURE_INFO /// @param[in] pReqInfo: ptr to GMM_REQ_OFFSET_INFO /// /// @return byte offset ///////////////////////////////////////////////////////////////////////////////////// GMM_GFX_SIZE_T GmmLib::GmmTextureCalc::Get3DMipByteAddress(GMM_TEXTURE_INFO * pTexInfo, GMM_REQ_OFFSET_INFO *pReqInfo) { uint32_t MipsInThisRow, PlaneRows; uint32_t MipHeight, MipWidth; uint32_t UnitAlignHeight, UnitAlignWidth; GMM_GFX_SIZE_T MipMapByteAddress, ExtraBytes; uint32_t Slice, MipLevel, Pitch; uint8_t Compress; GMM_RESOURCE_FORMAT GenericFormat; uint32_t CompressHeight, CompressWidth, CompressDepth; __GMM_ASSERTPTR(pGmmLibContext, 0); GenericFormat = pTexInfo->Format; Slice = pReqInfo->Slice; MipLevel = pReqInfo->MipLevel; Pitch = GFX_ULONG_CAST(pTexInfo->Pitch); // For slice 0 for any mip address is simple and stored in table if(Slice == 0) { MipMapByteAddress = pTexInfo->OffsetInfo.Texture3DOffsetInfo.Offset[MipLevel]; } // For any slice else { MipMapByteAddress = pTexInfo->OffsetInfo.Texture3DOffsetInfo.Offset[MipLevel]; // See how many mip can fit in one row MipsInThisRow = GFX_2_TO_POWER_OF(MipLevel); PlaneRows = Slice / MipsInThisRow; // make sure we get the height and mip of base level MipWidth = GFX_ULONG_CAST(pTexInfo->BaseWidth); MipHeight = pTexInfo->BaseHeight; MipWidth >>= MipLevel; MipHeight >>= MipLevel; UnitAlignWidth = pTexInfo->Alignment.HAlign; UnitAlignHeight = pTexInfo->Alignment.VAlign; Compress = GmmIsCompressed(pGmmLibContext, pTexInfo->Format); GetCompressionBlockDimensions(pTexInfo->Format, &CompressWidth, &CompressHeight, &CompressDepth); // clamp such that mip height is at least min height MipHeight = GFX_MAX(MipHeight, UnitAlignHeight); MipHeight = GFX_ALIGN(MipHeight, UnitAlignHeight); // clamp such that mip width is at least min width MipWidth = GFX_MAX(MipWidth, UnitAlignWidth); MipWidth = GFX_ALIGN(MipWidth, UnitAlignWidth); if(Compress) { MipWidth /= CompressWidth; MipHeight /= CompressHeight; } else if(pTexInfo->Flags.Gpu.SeparateStencil) { MipWidth *= 2; MipHeight /= 2; } ExtraBytes = (GMM_GFX_SIZE_T)PlaneRows * MipHeight * Pitch; ExtraBytes += ((GMM_GFX_SIZE_T)(Slice % MipsInThisRow) * MipWidth * pTexInfo->BitsPerPixel) >> 3; // get address offset MipMapByteAddress += ExtraBytes; } return MipMapByteAddress; } ///////////////////////////////////////////////////////////////////////////////////// /// Utility function calculates a byte offset from the base of the allocation // to L frame, R frame, or blank region. /// /// @param[in] pTexInfo: ptr to ::GMM_TEXTURE_INFO /// @param[in] pReqInfo: ptr to GMM_REQ_OFFSET_INFO /// /// @return byte offset ///////////////////////////////////////////////////////////////////////////////////// uint32_t GmmLib::GmmTextureCalc::GetDisplayFrameOffset(GMM_TEXTURE_INFO * pTexInfo, GMM_REQ_OFFSET_INFO *pReqInfo) { uint32_t Offset; __GMM_ASSERTPTR(pTexInfo, GMM_ERROR); __GMM_ASSERTPTR(pReqInfo, GMM_ERROR); switch(pReqInfo->Frame) { case GMM_DISPLAY_L: Offset = 0; break; case GMM_DISPLAY_R: Offset = pTexInfo->S3d.RFrameOffset; break; case GMM_DISPLAY_BLANK_AREA: Offset = pTexInfo->S3d.BlankAreaOffset; break; default: Offset = 0; GMM_ASSERTDPF(0, "Unknown Frame Type!"); break; } return Offset; } void GmmLib::GmmTextureCalc::SetPlanarOffsetInfo(GMM_TEXTURE_INFO *pTexInfo, GMM_RESCREATE_CUSTOM_PARAMS &CreateParams) { const GMM_PLATFORM_INFO *pPlatform; pPlatform = GMM_OVERRIDE_PLATFORM_INFO(pTexInfo, pGmmLibContext); if(GMM_IS_TILED(pPlatform->TileInfo[pTexInfo->TileMode])) { pTexInfo->OffsetInfo.Plane.IsTileAlignedPlanes = true; } for(uint8_t i = 1; i <= CreateParams.NoOfPlanes; i++) { pTexInfo->OffsetInfo.Plane.X[i] = CreateParams.PlaneOffset.X[i]; pTexInfo->OffsetInfo.Plane.Y[i] = CreateParams.PlaneOffset.Y[i]; } pTexInfo->OffsetInfo.Plane.NoOfPlanes = CreateParams.NoOfPlanes; } #ifndef __GMM_KMD__ void GmmLib::GmmTextureCalc::SetPlanarOffsetInfo_2(GMM_TEXTURE_INFO *pTexInfo, GMM_RESCREATE_CUSTOM_PARAMS_2 &CreateParams) { const GMM_PLATFORM_INFO *pPlatform; pPlatform = GMM_OVERRIDE_PLATFORM_INFO(pTexInfo, pGmmLibContext); if(GMM_IS_TILED(pPlatform->TileInfo[pTexInfo->TileMode])) { pTexInfo->OffsetInfo.Plane.IsTileAlignedPlanes = true; } for(uint8_t i = 1; i <= CreateParams.NoOfPlanes; i++) { pTexInfo->OffsetInfo.Plane.X[i] = CreateParams.PlaneOffset.X[i]; pTexInfo->OffsetInfo.Plane.Y[i] = CreateParams.PlaneOffset.Y[i]; } pTexInfo->OffsetInfo.Plane.NoOfPlanes = CreateParams.NoOfPlanes; } #endif void GmmLib::GmmTextureCalc::SetPlaneUnAlignedTexOffsetInfo(GMM_TEXTURE_INFO *pTexInfo, uint32_t YHeight, uint32_t VHeight) { uint32_t UmdUHeight = 0, UmdVHeight = 0; pTexInfo->OffsetInfo.Plane.UnAligned.Height[GMM_PLANE_Y] = YHeight; if(pTexInfo->OffsetInfo.Plane.NoOfPlanes == 2) { pTexInfo->OffsetInfo.Plane.UnAligned.Height[GMM_PLANE_U] = VHeight; UmdUHeight = (GMM_GLOBAL_GFX_SIZE_T)((pTexInfo->Size / pTexInfo->Pitch) - pTexInfo->OffsetInfo.Plane.Y[GMM_PLANE_U]); } else if(pTexInfo->OffsetInfo.Plane.NoOfPlanes == 3) { pTexInfo->OffsetInfo.Plane.UnAligned.Height[GMM_PLANE_U] = pTexInfo->OffsetInfo.Plane.UnAligned.Height[GMM_PLANE_V] = VHeight; UmdUHeight = (GMM_GLOBAL_GFX_SIZE_T)(pTexInfo->OffsetInfo.Plane.Y[GMM_PLANE_V] - pTexInfo->OffsetInfo.Plane.Y[GMM_PLANE_U]); UmdVHeight = (GMM_GLOBAL_GFX_SIZE_T)(((pTexInfo->Size / pTexInfo->Pitch) - pTexInfo->OffsetInfo.Plane.Y[GMM_PLANE_U]) / 2); __GMM_ASSERTPTR((UmdUHeight == UmdVHeight), VOIDRETURN); } __GMM_ASSERTPTR(((pTexInfo->OffsetInfo.Plane.Y[GMM_PLANE_U] == YHeight) && (UmdUHeight == VHeight)), VOIDRETURN); } uint32_t GmmLib::GmmTextureCalc::IsTileAlignedPlanes(GMM_TEXTURE_INFO *pTexInfo) { return pTexInfo->OffsetInfo.Plane.IsTileAlignedPlanes; } uint32_t GmmLib::GmmTextureCalc::GetNumberOfPlanes(GMM_TEXTURE_INFO *pTexInfo) { return pTexInfo->OffsetInfo.Plane.NoOfPlanes; } void GmmLib::GmmTextureCalc::GetPlaneIdForCpuBlt(GMM_TEXTURE_INFO *pTexInfo, GMM_RES_COPY_BLT *pBlt, uint32_t *PlaneId) { uint32_t TotalHeight = 0; if(pTexInfo->OffsetInfo.Plane.NoOfPlanes == 2) { TotalHeight = GFX_ULONG_CAST(pTexInfo->OffsetInfo.Plane.UnAligned.Height[GMM_PLANE_Y] + pTexInfo->OffsetInfo.Plane.UnAligned.Height[GMM_PLANE_U]); } else if(pTexInfo->OffsetInfo.Plane.NoOfPlanes == 3) { TotalHeight = GFX_ULONG_CAST(pTexInfo->OffsetInfo.Plane.UnAligned.Height[GMM_PLANE_Y] + pTexInfo->OffsetInfo.Plane.UnAligned.Height[GMM_PLANE_U] + pTexInfo->OffsetInfo.Plane.UnAligned.Height[GMM_PLANE_V]); } else { TotalHeight = GFX_ULONG_CAST(pTexInfo->OffsetInfo.Plane.UnAligned.Height[GMM_PLANE_Y]); //YV12 exception } // Determine if BLT rectange is for monolithic surface or contained in specific Y/UV plane if(((pBlt->Gpu.OffsetY + pBlt->Blt.Height <= pTexInfo->OffsetInfo.Plane.Y[GMM_PLANE_U]) || pTexInfo->OffsetInfo.Plane.NoOfPlanes == 1) && (pBlt->Gpu.OffsetX + pBlt->Blt.Width <= pTexInfo->BaseWidth)) { *PlaneId = GMM_PLANE_Y; } else if(pBlt->Gpu.OffsetY >= pTexInfo->OffsetInfo.Plane.Y[GMM_PLANE_U] && (pBlt->Gpu.OffsetY + pBlt->Blt.Height <= (pTexInfo->OffsetInfo.Plane.Y[GMM_PLANE_U] + pTexInfo->OffsetInfo.Plane.UnAligned.Height[GMM_PLANE_U])) && (pBlt->Gpu.OffsetX + pBlt->Blt.Width <= pTexInfo->BaseWidth)) { *PlaneId = GMM_PLANE_U; } else if(pBlt->Gpu.OffsetY >= pTexInfo->OffsetInfo.Plane.Y[GMM_PLANE_V] && (pBlt->Gpu.OffsetY + pBlt->Blt.Height <= (pTexInfo->OffsetInfo.Plane.Y[GMM_PLANE_V] + pTexInfo->OffsetInfo.Plane.UnAligned.Height[GMM_PLANE_U])) && (pBlt->Gpu.OffsetX + pBlt->Blt.Width <= pTexInfo->BaseWidth)) { *PlaneId = GMM_PLANE_V; } // For smaller surface, BLT rect may fall in Y Plane due to tile alignment but user may have requested monolithic BLT if(pBlt->Gpu.OffsetX == 0 && pBlt->Gpu.OffsetY == 0 && pBlt->Blt.Height >= TotalHeight) { *PlaneId = GMM_MAX_PLANE; } } void GmmLib::GmmTextureCalc::GetBltInfoPerPlane(GMM_TEXTURE_INFO *pTexInfo, GMM_RES_COPY_BLT *pBlt, uint32_t PlaneId) { if(PlaneId == GMM_PLANE_Y) { pBlt->Gpu.OffsetX = GFX_ULONG_CAST(pTexInfo->OffsetInfo.Plane.X[GMM_PLANE_Y]); pBlt->Gpu.OffsetY = GFX_ULONG_CAST(pTexInfo->OffsetInfo.Plane.Y[GMM_PLANE_Y]); pBlt->Blt.Height = GFX_ULONG_CAST(pTexInfo->OffsetInfo.Plane.UnAligned.Height[GMM_PLANE_Y]); } else if(PlaneId == GMM_PLANE_U) { pBlt->Gpu.OffsetX = GFX_ULONG_CAST(pTexInfo->OffsetInfo.Plane.X[GMM_PLANE_U]); pBlt->Gpu.OffsetY = GFX_ULONG_CAST(pTexInfo->OffsetInfo.Plane.Y[GMM_PLANE_U]); pBlt->Sys.pData = (char *)pBlt->Sys.pData + uint32_t(pBlt->Blt.Height * pBlt->Sys.RowPitch); pBlt->Blt.Height = GFX_ULONG_CAST(pTexInfo->OffsetInfo.Plane.UnAligned.Height[GMM_PLANE_U]); if(pTexInfo->Flags.Info.RedecribedPlanes) { __GMM_ASSERT(0); } } else { pBlt->Gpu.OffsetX = GFX_ULONG_CAST(pTexInfo->OffsetInfo.Plane.X[GMM_PLANE_V]); pBlt->Gpu.OffsetY = GFX_ULONG_CAST(pTexInfo->OffsetInfo.Plane.Y[GMM_PLANE_V]); pBlt->Blt.Height = GFX_ULONG_CAST(pTexInfo->OffsetInfo.Plane.UnAligned.Height[GMM_PLANE_U]); pBlt->Sys.pData = (char *)pBlt->Sys.pData + uint32_t(pBlt->Blt.Height * pBlt->Sys.RowPitch); } } gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/Texture/GmmTextureSpecialCases.cpp000066400000000000000000000453461466655022700266140ustar00rootroot00000000000000/*============================================================================== Copyright(c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ============================================================================*/ #include "Internal/Common/GmmLibInc.h" ///////////////////////////////////////////////////////////////////////////////////// /// This function does any special-case conversion from client-provided pseudo creation /// parameters to actual parameters for Hiz, CCS, SeparateStencil and Depth buffers. /// /// @param[in] pTexInfo: Reference to ::GMM_TEXTURE_INFO /// ///////////////////////////////////////////////////////////////////////////////////// GMM_STATUS GmmLib::GmmTextureCalc::PreProcessTexSpecialCases(GMM_TEXTURE_INFO *pTexInfo) { GMM_STATUS Status = GMM_SUCCESS; const GMM_PLATFORM_INFO *pPlatform = GMM_OVERRIDE_PLATFORM_INFO(pTexInfo, pGmmLibContext); if(!pTexInfo->Flags.Gpu.CCS && !pTexInfo->Flags.Gpu.MCS && !pTexInfo->Flags.Gpu.HiZ && !pTexInfo->Flags.Gpu.SeparateStencil && !pTexInfo->Flags.Gpu.MMC) { // Fast-out for non-special-cases. } else if(pTexInfo->Flags.Gpu.HiZ) // ###################################### { // With HiZ surface creation, clients send the size/etc. parameters of // the associated Depth Buffer--and here we convert to the appropriate // HiZ creation parameters... if((pTexInfo->BaseWidth > 0) && (pTexInfo->BaseWidth <= pPlatform->HiZ.MaxWidth) && (pTexInfo->BaseHeight > 0) && (pTexInfo->BaseHeight <= pPlatform->HiZ.MaxHeight) && (pTexInfo->Depth <= ((pTexInfo->Type == RESOURCE_3D) ? pPlatform->HiZ.MaxDepth : 1)) && (pTexInfo->ArraySize <= ((pTexInfo->Type == RESOURCE_3D) ? 1 : (pTexInfo->Type == RESOURCE_CUBE) ? pPlatform->HiZ.MaxArraySize / 6 : pPlatform->HiZ.MaxArraySize)) && // SKL+ does not support HiZ surfaces for 1D and 3D surfaces ((GFX_GET_CURRENT_RENDERCORE(pPlatform->Platform) < IGFX_GEN9_CORE) || (pTexInfo->Type != RESOURCE_1D && pTexInfo->Type != RESOURCE_3D))) { uint32_t Z_Width, Z_Height, Z_Depth; // Latch Z_[Width/Height/Depth]... Z_Width = GFX_ULONG_CAST(pTexInfo->BaseWidth); Z_Height = pTexInfo->BaseHeight; if((pTexInfo->Type == RESOURCE_1D) || (pTexInfo->Type == RESOURCE_2D)) { Z_Depth = GFX_MAX(pTexInfo->ArraySize, 1); } else if(pTexInfo->Type == RESOURCE_3D) { Z_Depth = pTexInfo->Depth; } else if(pTexInfo->Type == RESOURCE_CUBE) { // HW doesn't allow HiZ cube arrays, but GMM is allowing because // clients will redescribe depth/HiZ cube arrays as 2D arrays. Z_Depth = 6 * GFX_MAX(pTexInfo->ArraySize, 1); } else { __GMM_ASSERT(0); // Illegal--Should have caught at upper IF check. Z_Depth = 0; } // HZ_[Width/Height/QPitch] Calculation... { uint32_t h0, h1, hL, i, NumSamples, QPitch, Z_HeightL; uint32_t HZ_HAlign = 16, HZ_VAlign = 8; uint8_t HZ_DepthRows = pPlatform->HiZPixelsPerByte; // HZ operates in pixel space starting from SKL. So, it does not care // whether the depth buffer is in MSAA mode or not. NumSamples = (GFX_GET_CURRENT_RENDERCORE(pPlatform->Platform) >= IGFX_GEN9_CORE) ? 1 : pTexInfo->MSAA.NumSamples; pTexInfo->BaseWidth = ExpandWidth(Z_Width, HZ_HAlign, NumSamples); h0 = ExpandHeight(Z_Height, HZ_VAlign, NumSamples); Z_Height = GmmTexGetMipHeight(pTexInfo, 1); h1 = ExpandHeight(Z_Height, HZ_VAlign, NumSamples); if(GFX_GET_CURRENT_RENDERCORE(pPlatform->Platform) >= IGFX_GEN8_CORE) { if(pTexInfo->Type == RESOURCE_3D) { for(i = 0, Z_HeightL = 0; i <= pTexInfo->MaxLod; i++) { Z_Height = GmmTexGetMipHeight(pTexInfo, i); hL = ExpandHeight(Z_Height, HZ_VAlign, NumSamples); Z_HeightL += (hL * GFX_MAX(1, (Z_Depth / GFX_2_TO_POWER_OF(i)))); } pTexInfo->ArraySize = 0; pTexInfo->BaseHeight = Z_HeightL / 2; } else { for(i = 2, Z_HeightL = 0; i <= pTexInfo->MaxLod; i++) { Z_Height = GmmTexGetMipHeight(pTexInfo, i); Z_HeightL += ExpandHeight(Z_Height, HZ_VAlign, NumSamples); } QPitch = (pTexInfo->MaxLod > 0) ? (h0 + GFX_MAX(h1, Z_HeightL)) : h0; QPitch /= HZ_DepthRows; pTexInfo->ArraySize = Z_Depth; pTexInfo->BaseHeight = QPitch; } pTexInfo->Alignment.HAlign = HZ_HAlign; pTexInfo->Alignment.VAlign = HZ_VAlign / HZ_DepthRows; } else //if (GFX_GET_CURRENT_RENDERCORE(pPlatform->Platform) >= IGFX_GEN7_CORE) { if(pTexInfo->Type == RESOURCE_3D) { for(i = 0, Z_HeightL = 0; i <= pTexInfo->MaxLod; i++) { hL = ExpandHeight(Z_Height >> i, HZ_VAlign, NumSamples); Z_HeightL += (hL * GFX_MAX(1, (Z_Depth / GFX_2_TO_POWER_OF(i)))); } pTexInfo->BaseHeight = Z_HeightL / 2; } else { QPitch = h0 + h1 + 12 * HZ_VAlign; pTexInfo->BaseHeight = GFX_CEIL_DIV((QPitch * Z_Depth / 2), 8) * 8; } pTexInfo->ArraySize = 1; } } /// Native HZ Params ////////////////////////////////////////////////// pTexInfo->BitsPerPixel = 8; pTexInfo->Depth = 1; pTexInfo->Format = GMM_FORMAT_GENERIC_8BIT; pTexInfo->MaxLod = 0; pTexInfo->MSAA.NumSamples = 1; pTexInfo->MSAA.SamplePattern = GMM_MSAA_DISABLED; pTexInfo->Type = RESOURCE_2D; // HiZ Always Tile-Y pTexInfo->Flags.Info.Linear = 0; pTexInfo->Flags.Info.TiledW = 0; pTexInfo->Flags.Info.TiledX = 0; pTexInfo->Flags.Info.TiledYf = 0; GMM_SET_64KB_TILE(pTexInfo->Flags, 0, pGmmLibContext); GMM_SET_4KB_TILE(pTexInfo->Flags, 1, pGmmLibContext); } else { GMM_ASSERTDPF(0, "Illegal HiZ creation parameters!"); Status = GMM_ERROR; } } // HiZ else if(pTexInfo->Flags.Gpu.CCS || pTexInfo->Flags.Gpu.MCS) // ###################################### { // With CCS surface creation, clients send height, width, depth, etc. of // the associated RenderTarget--and here we convert to the appropriate CCS // creation parameters... __GMM_ASSERT((!pGmmLibContext->GetSkuTable().FtrTileY || (pTexInfo->Flags.Info.Linear + pTexInfo->Flags.Info.TiledW + pTexInfo->Flags.Info.TiledX + pTexInfo->Flags.Info.TiledY)) == 1); __GMM_ASSERT((pGmmLibContext->GetSkuTable().FtrTileY || (pTexInfo->Flags.Info.Linear + pTexInfo->Flags.Info.Tile4 + pTexInfo->Flags.Info.Tile64)) == 1); __GMM_ASSERT((pTexInfo->MSAA.NumSamples == 1) || (pTexInfo->MSAA.NumSamples == 2) || (pTexInfo->MSAA.NumSamples == 4) || (pTexInfo->MSAA.NumSamples == 8) || (pTexInfo->MSAA.NumSamples == 16)); Status = pGmmLibContext->GetTextureCalc()->MSAACCSUsage(pTexInfo); if(!pTexInfo->Flags.Gpu.__NonMsaaLinearCCS) { // CCS Always Tile-Y (Even for Non-MSAA FastClear.) pTexInfo->Flags.Info.Linear = 0; pTexInfo->Flags.Info.TiledW = 0; pTexInfo->Flags.Info.TiledX = 0; pTexInfo->Flags.Info.TiledYf = 0; GMM_SET_64KB_TILE(pTexInfo->Flags, 0, pGmmLibContext); GMM_SET_4KB_TILE(pTexInfo->Flags, 1, pGmmLibContext); //Clear compression request in CCS pTexInfo->Flags.Info.RenderCompressed = 0; pTexInfo->Flags.Info.MediaCompressed = 0; } } // CCS else if(pTexInfo->Flags.Gpu.SeparateStencil) // ########################## { // Seperate stencil sizing is based on the associated depth buffer // size, however UMD manages this sizing, and GMM will allocate any // arbitrarily sized stencil. Stencils do have specific tiling // requirements however, which is handled below. if((pTexInfo->BaseWidth > 0) && (pTexInfo->BaseHeight > 0)) { __GMM_ASSERT(pTexInfo->BitsPerPixel == 8); if(GFX_GET_CURRENT_RENDERCORE(pPlatform->Platform) < IGFX_GEN7_CORE) { GMM_ASSERTDPF((pTexInfo->MaxLod == 0), "Stencil Buffer LOD's not supported!"); } if(pGmmLibContext->GetSkuTable().FtrTileY) { // Separate Stencil Tile-W Gen8-Gen11, otherwise Tile-Y pTexInfo->Flags.Info.Linear = 0; pTexInfo->Flags.Info.TiledX = 0; pTexInfo->Flags.Info.TiledYf = 0; pTexInfo->Flags.Info.TiledW = 0; GMM_SET_4KB_TILE(pTexInfo->Flags, 0, pGmmLibContext); GMM_SET_64KB_TILE(pTexInfo->Flags, 0, pGmmLibContext); if(GFX_GET_CURRENT_RENDERCORE(pPlatform->Platform) >= IGFX_GEN8_CORE && GFX_GET_CURRENT_RENDERCORE(pPlatform->Platform) <= IGFX_GEN11_CORE) { pTexInfo->Flags.Info.TiledW = 1; } else { GMM_SET_4KB_TILE(pTexInfo->Flags, 1, pGmmLibContext); } } else { __GMM_ASSERT(pTexInfo->Flags.Info.Tile4 + pTexInfo->Flags.Info.Tile64 == 1); } } else { GMM_ASSERTDPF(0, "Illegal Separate Stencil creation parameters!"); Status = GMM_ERROR; } } // Separate Stencil else if(pTexInfo->Flags.Gpu.MMC && pTexInfo->Flags.Gpu.UnifiedAuxSurface) { pTexInfo->Flags.Gpu.__NonMsaaLinearCCS = 1; pTexInfo->Flags.Info.Linear = 1; } return Status; } ///////////////////////////////////////////////////////////////////////////////////// /// This function performs rough estimate of memory requirement between 4KB Tile vs /// 64KB Tile surfaces and if the memory wastage due to padding/alignment exceeds /// configured threshold, then optimize to demote the surface to 4KB Tile. /// /// @param[in] pTexInfo: Reference to ::GMM_TEXTURE_INFO /// returns 1 if optimization to demote to 4KB tile is required otherwise 0 /// ///////////////////////////////////////////////////////////////////////////////////// uint8_t GmmLib::GmmTextureCalc::SurfaceRequires64KBTileOptimization(GMM_TEXTURE_INFO *pTexInfo) { GMM_STATUS Status = GMM_SUCCESS; const GMM_PLATFORM_INFO *pPlatform = GMM_OVERRIDE_PLATFORM_INFO(pTexInfo, pGmmLibContext); uint32_t Size4KbTile, Size64KbTile; // Discard the surface if not eligible for 4KB Tile. // All YUV formats restricted with default Tile64 across clients if((pTexInfo->MSAA.NumSamples > 1) || pTexInfo->Flags.Gpu.TiledResource || pTexInfo->Flags.Gpu.HiZ || (!pTexInfo->Flags.Info.Tile64)) { return 0; } // Calc Surf size for 64KB Tile. // Ignoring the CCS/AuxSurf dimensions since its proportional to main surface size { GMM_TEXTURE_INFO Surf = {}; uint32_t ExpandedArraySize, BitsPerPixel; uint32_t SliceHeight, SliceWidth, Pitch; uint32_t BlockHeight = 0; uint32_t HAlign, VAlign, DAlign, CompressHeight, CompressWidth, CompressDepth; Surf = *pTexInfo; //Get HAlign/VAlign if((Status = __GmmTexFillHAlignVAlign(&Surf, pGmmLibContext)) != GMM_SUCCESS) { __GMM_ASSERT(0); return 0; } HAlign = Surf.Alignment.HAlign; VAlign = Surf.Alignment.VAlign; DAlign = Surf.Alignment.DAlign; // Set Tile Mode SetTileMode(&Surf); BitsPerPixel = Surf.BitsPerPixel; ExpandedArraySize = GFX_MAX(Surf.ArraySize, 1) * ((Surf.Type == RESOURCE_CUBE) ? 6 : 1) * // Cubemaps simply 6-element, 2D arrays. ((Surf.Type == RESOURCE_3D) ? GFX_MAX(Surf.Depth, 1) : 1); // 3D's simply 2D arrays for sizing. if(GMM_IS_64KB_TILE(Surf.Flags)) { ExpandedArraySize = GFX_CEIL_DIV(ExpandedArraySize, pPlatform->TileInfo[Surf.TileMode].LogicalTileDepth); } // For Mipped Surface, Approx SliceHeight = VAlign(Lod0Height) * Mipped ? 1.5 : 1; SliceHeight = GFX_ALIGN(Surf.BaseHeight, VAlign); if(Surf.MaxLod > 1) { SliceHeight = (GFX_ALIGN(Surf.BaseHeight, VAlign) * 3) / 2; } uint8_t Compress = GmmIsCompressed(pGmmLibContext, Surf.Format); GetCompressionBlockDimensions(Surf.Format, &CompressWidth, &CompressHeight, &CompressDepth); SliceWidth = __GMM_EXPAND_WIDTH(this, GFX_ULONG_CAST(Surf.BaseWidth), HAlign, &Surf); BlockHeight = SliceHeight * ExpandedArraySize; if(Compress) { SliceWidth = GFX_CEIL_DIV(SliceWidth, CompressWidth); BlockHeight = GFX_CEIL_DIV(BlockHeight, CompressHeight); } // Default pitch Pitch = SliceWidth * BitsPerPixel >> 3; if(GMM_IS_TILED(pPlatform->TileInfo[Surf.TileMode])) { Pitch = GFX_ALIGN(Pitch, pPlatform->TileInfo[Surf.TileMode].LogicalTileWidth); BlockHeight = GFX_ALIGN(BlockHeight, pPlatform->TileInfo[Surf.TileMode].LogicalTileHeight); } // Calculate Tile aligned size. Size64KbTile = BlockHeight * Pitch; if(pTexInfo->Type == RESOURCE_3D && !pTexInfo->Flags.Info.Linear) { Size64KbTile *= pPlatform->TileInfo[Surf.TileMode].LogicalTileDepth; } } // Calc Surf size for 4KB Tile // Ignoring the CCS/AuxSurf dimensions since its proportional to main surface size { GMM_TEXTURE_INFO Surf = {}; uint32_t ExpandedArraySize, BitsPerPixel; uint32_t SliceHeight, SliceWidth, Pitch; uint32_t BlockHeight = 0; uint32_t HAlign, VAlign, DAlign, CompressHeight, CompressWidth, CompressDepth; Surf = *pTexInfo; Surf.Flags.Info.Tile4 = 1; Surf.Flags.Info.Tile64 = 0; //Get HAlign/VAlign if((Status = __GmmTexFillHAlignVAlign(&Surf, pGmmLibContext)) != GMM_SUCCESS) { Status = GMM_ERROR; return Status; } HAlign = Surf.Alignment.HAlign; VAlign = Surf.Alignment.VAlign; DAlign = Surf.Alignment.DAlign; // Set Tile Mode SetTileMode(&Surf); BitsPerPixel = Surf.BitsPerPixel; ExpandedArraySize = GFX_MAX(Surf.ArraySize, 1) * ((Surf.Type == RESOURCE_CUBE) ? 6 : 1) * // Cubemaps simply 6-element, 2D arrays. ((Surf.Type == RESOURCE_3D) ? GFX_MAX(Surf.Depth, 1) : 1); // 3D's simply 2D arrays for sizing. if(GMM_IS_64KB_TILE(Surf.Flags)) { ExpandedArraySize = GFX_CEIL_DIV(ExpandedArraySize, pPlatform->TileInfo[Surf.TileMode].LogicalTileDepth); } // For Mipped Surface, Approx SliceHeight = VAlign(Lod0Height) * Mipped ? 1.5 : 1; SliceHeight = GFX_ALIGN(Surf.BaseHeight, VAlign); if(Surf.MaxLod > 1) { SliceHeight = (GFX_ALIGN(Surf.BaseHeight, VAlign) * 3) / 2; } uint8_t Compress = GmmIsCompressed(pGmmLibContext, Surf.Format); GetCompressionBlockDimensions(Surf.Format, &CompressWidth, &CompressHeight, &CompressDepth); SliceWidth = __GMM_EXPAND_WIDTH(this, GFX_ULONG_CAST(Surf.BaseWidth), HAlign, &Surf); BlockHeight = SliceHeight * ExpandedArraySize; if(Compress) { SliceWidth = GFX_CEIL_DIV(SliceWidth, CompressWidth); BlockHeight = GFX_CEIL_DIV(BlockHeight, CompressHeight); } // Default pitch Pitch = SliceWidth * BitsPerPixel >> 3; if(GMM_IS_TILED(pPlatform->TileInfo[Surf.TileMode])) { Pitch = GFX_ALIGN(Pitch, pPlatform->TileInfo[Surf.TileMode].LogicalTileWidth); BlockHeight = GFX_ALIGN(BlockHeight, pPlatform->TileInfo[Surf.TileMode].LogicalTileHeight); } // Calculate Tile aligned size. Size4KbTile = BlockHeight * Pitch; } // check if 64KB tiled resource size exceeds memory wastage threshold. if(((Size4KbTile * (100 + (GMM_GFX_SIZE_T)pGmmLibContext->GetAllowedPaddingFor64KBTileSurf())) / 100) < Size64KbTile) { return 1; } return 0; } gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/Texture/GmmXe_LPGTexture.cpp000066400000000000000000001571601466655022700253310ustar00rootroot00000000000000/*============================================================================== Copyright(c) 2022 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ============================================================================*/ #include "Internal/Common/GmmLibInc.h" #include "Internal/Common/Texture/GmmGen10TextureCalc.h" #include "Internal/Common/Texture/GmmGen11TextureCalc.h" #include "Internal/Common/Texture/GmmGen12TextureCalc.h" #include "Internal/Common/Texture/GmmXe_LPGTextureCalc.h" ///////////////////////////////////////////////////////////////////////////////////// /// This function will Setup a planar surface allocation. /// /// @param[in] pTexInfo: Reference to ::GMM_TEXTURE_INFO /// @param[in] pRestrictions: Reference to surface alignment and size restrictions. /// /// @return ::GMM_STATUS ///////////////////////////////////////////////////////////////////////////////////// GMM_STATUS GMM_STDCALL GmmLib::GmmXe_LPGTextureCalc::FillTexPlanar(GMM_TEXTURE_INFO * pTexInfo, __GMM_BUFFER_TYPE *pRestrictions) { uint32_t WidthBytesPhysical, Height, YHeight, VHeight; uint32_t AdjustedVHeight = 0; GMM_STATUS Status; bool UVPacked = false; uint32_t BitsPerPixel, AlignedWidth; GMM_DPF_ENTER; __GMM_ASSERTPTR(pTexInfo, GMM_ERROR); __GMM_ASSERTPTR(pRestrictions, GMM_ERROR); __GMM_ASSERT(!pTexInfo->Flags.Info.TiledW); const GMM_PLATFORM_INFO *pPlatform = GMM_OVERRIDE_PLATFORM_INFO(pTexInfo, pGmmLibContext); BitsPerPixel = pTexInfo->BitsPerPixel; AlignedWidth = GFX_ULONG_CAST(pTexInfo->BaseWidth); if(!pTexInfo->Flags.Gpu.__NonMsaaTileYCcs) { pTexInfo->TileMode = TILE_NONE; } else { pTexInfo->TileMode = LEGACY_TILE_Y; } WidthBytesPhysical = AlignedWidth * BitsPerPixel >> 3; Height = VHeight = 0; YHeight = pTexInfo->BaseHeight; switch(pTexInfo->Format) { case GMM_FORMAT_IMC1: // IMC1 = IMC3 with Swapped U/V case GMM_FORMAT_IMC3: case GMM_FORMAT_MFX_JPEG_YUV420: // Same as IMC3. // YYYYYYYY // YYYYYYYY // YYYYYYYY // YYYYYYYY // UUUU // UUUU // VVVV // VVVV case GMM_FORMAT_MFX_JPEG_YUV422V: // Similar to IMC3 but U/V are full width. // YYYYYYYY // YYYYYYYY // YYYYYYYY // YYYYYYYY // UUUUUUUU // UUUUUUUU // VVVVVVVV // VVVVVVVV { VHeight = GFX_ALIGN(GFX_CEIL_DIV(YHeight, 2), GMM_IMCx_PLANE_ROW_ALIGNMENT); YHeight = GFX_ALIGN(YHeight, GMM_IMCx_PLANE_ROW_ALIGNMENT); Height = YHeight + 2 * VHeight; // One VHeight for V and one for U. pTexInfo->OffsetInfo.PlaneXe_LPG.NoOfPlanes = 3; break; } case GMM_FORMAT_MFX_JPEG_YUV411R_TYPE: //Similar to IMC3 but U/V are quarther height and full width. //YYYYYYYY //YYYYYYYY //YYYYYYYY //YYYYYYYY //UUUUUUUU //VVVVVVVV { VHeight = GFX_ALIGN(GFX_CEIL_DIV(YHeight, 4), GMM_IMCx_PLANE_ROW_ALIGNMENT); YHeight = GFX_ALIGN(YHeight, GMM_IMCx_PLANE_ROW_ALIGNMENT); Height = YHeight + 2 * VHeight; pTexInfo->OffsetInfo.PlaneXe_LPG.NoOfPlanes = 3; break; } case GMM_FORMAT_MFX_JPEG_YUV411: // Similar to IMC3 but U/V are quarter width and full height. // YYYYYYYY // YYYYYYYY // YYYYYYYY // YYYYYYYY // UU // UU // UU // UU // VV // VV // VV // VV case GMM_FORMAT_MFX_JPEG_YUV422H: // Similar to IMC3 but U/V are full height. // YYYYYYYY // YYYYYYYY // YYYYYYYY // YYYYYYYY // UUUU // UUUU // UUUU // UUUU // VVVV // VVVV // VVVV // VVVV case GMM_FORMAT_MFX_JPEG_YUV444: // Similar to IMC3 but U/V are full size. #if _WIN32 case GMM_FORMAT_WGBOX_YUV444: case GMM_FORMAT_WGBOX_PLANAR_YUV444: #endif // YYYYYYYY // YYYYYYYY // YYYYYYYY // YYYYYYYY // UUUUUUUU // UUUUUUUU // UUUUUUUU // UUUUUUUU // VVVVVVVV // VVVVVVVV // VVVVVVVV // VVVVVVVV { YHeight = GFX_ALIGN(YHeight, GMM_IMCx_PLANE_ROW_ALIGNMENT); VHeight = YHeight; Height = YHeight + 2 * VHeight; pTexInfo->OffsetInfo.PlaneXe_LPG.NoOfPlanes = 3; break; } case GMM_FORMAT_BGRP: case GMM_FORMAT_RGBP: { //For RGBP linear Tile keep resource Offset non aligned and for other Tile format to be 16-bit aligned if(pTexInfo->Flags.Info.Linear) { VHeight = YHeight; Height = YHeight + 2 * VHeight; pTexInfo->OffsetInfo.PlaneXe_LPG.NoOfPlanes = 3; } else { YHeight = GFX_ALIGN(YHeight, GMM_IMCx_PLANE_ROW_ALIGNMENT); VHeight = YHeight; Height = YHeight + 2 * VHeight; pTexInfo->OffsetInfo.PlaneXe_LPG.NoOfPlanes = 3; } break; } case GMM_FORMAT_IMC2: // IMC2 = IMC4 with Swapped U/V case GMM_FORMAT_IMC4: { // YYYYYYYY // YYYYYYYY // YYYYYYYY // YYYYYYYY // UUUUVVVV // UUUUVVVV YHeight = GFX_ALIGN(YHeight, GMM_IMCx_PLANE_ROW_ALIGNMENT); VHeight = GFX_CEIL_DIV(YHeight, 2); WidthBytesPhysical = GFX_ALIGN(WidthBytesPhysical, 2); // If odd YWidth, pitch bumps-up to fit rounded-up U/V planes. Height = YHeight + VHeight; // With SURFACE_STATE.XOffset support, the U-V interface has // much lighter restrictions--which will be naturally met by // surface pitch restrictions (i.e. dividing an IMC2/4 pitch // by 2--to get the U/V interface--will always produce a safe // XOffset value). // Not technically UV packed but sizing works out the same // if the resource is std swizzled UVPacked = true; pTexInfo->OffsetInfo.PlaneXe_LPG.NoOfPlanes = 2; break; } case GMM_FORMAT_NV12: case GMM_FORMAT_NV21: case GMM_FORMAT_NV11: case GMM_FORMAT_P010: case GMM_FORMAT_P012: case GMM_FORMAT_P016: case GMM_FORMAT_P208: case GMM_FORMAT_P216: { // YYYYYYYY // YYYYYYYY // YYYYYYYY // YYYYYYYY // [UV-Packing] if((pTexInfo->Format == GMM_FORMAT_NV12) || (pTexInfo->Format == GMM_FORMAT_NV21) || (pTexInfo->Format == GMM_FORMAT_P010) || (pTexInfo->Format == GMM_FORMAT_P012) || (pTexInfo->Format == GMM_FORMAT_P016)) { VHeight = GFX_CEIL_DIV(YHeight, 2); // U/V plane half of Y Height = YHeight + VHeight; } else { VHeight = YHeight; // U/V plane is same as Y Height = YHeight + VHeight; } if((pTexInfo->Format == GMM_FORMAT_NV12) || (pTexInfo->Format == GMM_FORMAT_NV21) || (pTexInfo->Format == GMM_FORMAT_P010) || (pTexInfo->Format == GMM_FORMAT_P012) || (pTexInfo->Format == GMM_FORMAT_P016) || (pTexInfo->Format == GMM_FORMAT_P208) || (pTexInfo->Format == GMM_FORMAT_P216)) { WidthBytesPhysical = GFX_ALIGN(WidthBytesPhysical, 2); // If odd YWidth, pitch bumps-up to fit rounded-up U/V planes. pTexInfo->OffsetInfo.PlaneXe_LPG.NoOfPlanes = 2; } else //if(pTexInfo->Format == GMM_FORMAT_NV11) { // Tiling not supported, since YPitch != UVPitch... pTexInfo->Flags.Info.TiledYf = 0; pTexInfo->Flags.Info.TiledX = 0; pTexInfo->Flags.Info.Linear = 1; GMM_SET_64KB_TILE(pTexInfo->Flags, 0, pGmmLibContext); GMM_SET_4KB_TILE(pTexInfo->Flags, 0, pGmmLibContext); } UVPacked = true; break; } case GMM_FORMAT_I420: // IYUV & I420: are identical to YV12 except, case GMM_FORMAT_IYUV: // U & V pl.s are reversed. case GMM_FORMAT_YV12: case GMM_FORMAT_YVU9: { // YYYYYYYY // YYYYYYYY // YYYYYYYY // YYYYYYYY // VVVVVV.. <-- V and U planes follow the Y plane, as linear // ..UUUUUU arrays--without respect to pitch. uint32_t YSize, UVSize, YVSizeRShift; uint32_t YSizeForUVPurposes, YSizeForUVPurposesDimensionalAlignment; YSize = WidthBytesPhysical * YHeight; // YVU9 has one U/V pixel for each 4x4 Y block. // The others have one U/V pixel for each 2x2 Y block. // YVU9 has a Y:V size ratio of 16 (4x4 --> 1). // The others have a ratio of 4 (2x2 --> 1). YVSizeRShift = (pTexInfo->Format != GMM_FORMAT_YVU9) ? 2 : 4; // If a Y plane isn't fully-aligned to its Y-->U/V block size, the // extra/unaligned Y pixels still need corresponding U/V pixels--So // for the purpose of computing the UVSize, we must consider a // dimensionally "rounded-up" YSize. (E.g. a 13x5 YVU9 Y plane would // require 4x2 U/V planes--the same UVSize as a fully-aligned 16x8 Y.) YSizeForUVPurposesDimensionalAlignment = (pTexInfo->Format != GMM_FORMAT_YVU9) ? 2 : 4; YSizeForUVPurposes = GFX_ALIGN(WidthBytesPhysical, YSizeForUVPurposesDimensionalAlignment) * GFX_ALIGN(YHeight, YSizeForUVPurposesDimensionalAlignment); UVSize = 2 * // <-- U + V (YSizeForUVPurposes >> YVSizeRShift); Height = GFX_CEIL_DIV(YSize + UVSize, WidthBytesPhysical); // Tiling not supported, since YPitch != UVPitch... pTexInfo->Flags.Info.TiledYf = 0; pTexInfo->Flags.Info.TiledX = 0; pTexInfo->Flags.Info.Linear = 1; pTexInfo->OffsetInfo.PlaneXe_LPG.NoOfPlanes = 1; GMM_SET_64KB_TILE(pTexInfo->Flags, 0, pGmmLibContext); GMM_SET_4KB_TILE(pTexInfo->Flags, 0, pGmmLibContext); break; } default: { GMM_ASSERTDPF(0, "Unexpected format"); return GMM_ERROR; } } // Align Height to even row to avoid hang if HW over-fetch Height = GFX_ALIGN(Height, __GMM_EVEN_ROW); SetTileMode(pTexInfo); // If the Surface has Odd height dimension, we will fall back to Linear Format. // If MMC is enabled, disable MMC during such cases. if(pTexInfo->Flags.Gpu.MMC) { if(!(GMM_IS_4KB_TILE(pTexInfo->Flags) || GMM_IS_64KB_TILE(pTexInfo->Flags))) { pTexInfo->Flags.Gpu.MMC = 0; } } // If the Surface has Odd height dimension, we will fall back to Linear Format. // If MMC is enabled, disable .CCS/UnifiedAuxSurface during such cases. if(pTexInfo->Flags.Gpu.CCS) { if(!(GMM_IS_4KB_TILE(pTexInfo->Flags) || GMM_IS_64KB_TILE(pTexInfo->Flags)) && !(pTexInfo->Flags.Gpu.__NonMsaaTileYCcs && GMM_IS_4KB_TILE(pTexInfo->Flags))) { pTexInfo->Flags.Gpu.MMC = 0; pTexInfo->Flags.Gpu.CCS = 0; pTexInfo->Flags.Gpu.UnifiedAuxSurface = 0; pTexInfo->Flags.Gpu.__NonMsaaTileYCcs = 0; } } // Legacy Planar "Linear Video" Restrictions... if(pTexInfo->Flags.Info.Linear && !pTexInfo->Flags.Wa.NoLegacyPlanarLinearVideoRestrictions) { pRestrictions->LockPitchAlignment = GFX_MAX(pRestrictions->LockPitchAlignment, GMM_BYTES(64)); pRestrictions->MinPitch = GFX_MAX(pRestrictions->MinPitch, GMM_BYTES(64)); pRestrictions->PitchAlignment = GFX_MAX(pRestrictions->PitchAlignment, GMM_BYTES(64)); pRestrictions->RenderPitchAlignment = GFX_MAX(pRestrictions->RenderPitchAlignment, GMM_BYTES(64)); } // Multiply overall pitch alignment for surfaces whose U/V planes have a // pitch down-scaled from that of Y--Since the U/V pitches must meet the // original restriction, the Y pitch must meet a scaled-up multiple. if((pTexInfo->Format == GMM_FORMAT_I420) || (pTexInfo->Format == GMM_FORMAT_IYUV) || (pTexInfo->Format == GMM_FORMAT_NV11) || (pTexInfo->Format == GMM_FORMAT_YV12) || (pTexInfo->Format == GMM_FORMAT_YVU9)) { uint32_t LShift = (pTexInfo->Format != GMM_FORMAT_YVU9) ? 1 : // UVPitch = 1/2 YPitch 2; // UVPitch = 1/4 YPitch pRestrictions->LockPitchAlignment <<= LShift; pRestrictions->MinPitch <<= LShift; pRestrictions->PitchAlignment <<= LShift; pRestrictions->RenderPitchAlignment <<= LShift; } AdjustedVHeight = VHeight; FindMipTailStartLod(pTexInfo); // In case of Planar surfaces, only the last Plane has to be aligned to 64 for LCU access if(pGmmLibContext->GetWaTable().WaAlignYUVResourceToLCU && GmmIsYUVFormatLCUAligned(pTexInfo->Format) && VHeight > 0) { AdjustedVHeight = GFX_ALIGN(VHeight, GMM_SCANLINES(GMM_MAX_LCU_SIZE)); Height += AdjustedVHeight - VHeight; } // For std swizzled and UV packed tile Ys/Yf cases, the planes // must be tile-boundary aligned. Actual alignment is handled // in FillPlanarOffsetAddress, but height and width must // be adjusted for correct size calculation if(GMM_IS_TILED(pPlatform->TileInfo[pTexInfo->TileMode]) && !pTexInfo->Flags.Gpu.__NonMsaaTileYCcs) { uint32_t TileHeight = pGmmLibContext->GetPlatformInfo().TileInfo[pTexInfo->TileMode].LogicalTileHeight; uint32_t TileWidth = pGmmLibContext->GetPlatformInfo().TileInfo[pTexInfo->TileMode].LogicalTileWidth; pTexInfo->OffsetInfo.PlaneXe_LPG.IsTileAlignedPlanes = true; if(pTexInfo->Flags.Gpu.CCS && !pGmmLibContext->GetSkuTable().FtrFlatPhysCCS) // alignment adjustment needed only for aux tables { if(GMM_IS_64KB_TILE(pTexInfo->Flags)) { TileHeight *= (!WA64K(pGmmLibContext) && !WA16K(pGmmLibContext)) ? 16 : 1; // For 64Kb Tile mode: Multiply TileHeight by 16 for 1 MB alignment } else { TileHeight *= (WA16K(pGmmLibContext) ? 1 : WA64K(pGmmLibContext) ? 4 : 64); // For 4k Tile: Multiply TileHeight by 4 and Pitch by 4 for 64kb alignment, multiply TileHeight by 64 and Pitch by 4 for 1 MB alignment } } if(pTexInfo->Format == GMM_FORMAT_IMC2 || // IMC2, IMC4 needs even tile columns pTexInfo->Format == GMM_FORMAT_IMC4) { // If the U & V planes are side-by-side then the surface pitch must be // padded out so that U and V planes will being on a tile boundary. // This means that an odd Y plane width must be padded out // with an additional tile. Even widths do not need padding uint32_t TileCols = GFX_CEIL_DIV(WidthBytesPhysical, TileWidth); if(TileCols % 2) { WidthBytesPhysical = (TileCols + 1) * TileWidth; } } Height = GFX_ALIGN(YHeight, TileHeight) + (UVPacked ? GFX_ALIGN(AdjustedVHeight, TileHeight) : (GFX_ALIGN(VHeight, TileHeight) + GFX_ALIGN(AdjustedVHeight, TileHeight))); if(GMM_IS_64KB_TILE(pTexInfo->Flags) || pTexInfo->Flags.Info.TiledYf) { pTexInfo->Flags.Info.RedecribedPlanes = true; } } else if(pTexInfo->Flags.Gpu.__NonMsaaTileYCcs) { uint32_t TileHeight = pGmmLibContext->GetPlatformInfo().TileInfo[pTexInfo->TileMode].LogicalTileHeight; BitsPerPixel = 8; if(pTexInfo->Format == GMM_FORMAT_IMC2 || // IMC2, IMC4 needs even tile columns pTexInfo->Format == GMM_FORMAT_IMC4) { // If the U & V planes are side-by-side then the surface pitch must be // padded out so that U and V planes will being on a tile boundary. // This means that an odd Y plane width must be padded out // with an additional tile. Even widths do not need padding // CCS must use padded main surface width, so get main surface TileWidth #define CCSMODE_TO_TILEMODE(y) ((y + TILE_YF_2D_8bpe) < TILE_YS_1D_8bpe) ? (y + TILE_YF_2D_8bpe) : \ ((y + TILE_YF_2D_8bpe + 5) >= TILE_YS_1D_128bpe) ? (y + TILE_YF_2D_8bpe + 5) : TILE_NONE uint32_t BaseTileWidth = pPlatform->TileInfo[CCSMODE_TO_TILEMODE(pTexInfo->CCSModeAlign)].LogicalTileWidth; WidthBytesPhysical = GFX_ALIGN(WidthBytesPhysical, 2 * BaseTileWidth); } AlignedWidth = GFX_ULONG_CAST(WidthBytesPhysical / (pTexInfo->BitsPerPixel >> 3)); WidthBytesPhysical = __GMM_EXPAND_WIDTH(this, AlignedWidth, pTexInfo->Alignment.HAlign, pTexInfo); WidthBytesPhysical = ScaleTextureWidth(pTexInfo, WidthBytesPhysical); //Should both YAux and UVAux use same CCModeALign (ie using common bpe?) //If different, then copy Aux info from per-plane Aux? HW has separate bpe or common? YHeight = __GMM_EXPAND_HEIGHT(this, YHeight, pTexInfo->Alignment.VAlign, pTexInfo); YHeight = ScaleTextureHeight(pTexInfo, YHeight); YHeight = GFX_ALIGN(YHeight, TileHeight); VHeight = __GMM_EXPAND_HEIGHT(this, VHeight, pTexInfo->Alignment.VAlign, pTexInfo); VHeight = ScaleTextureHeight(pTexInfo, VHeight); VHeight = GFX_ALIGN(VHeight, TileHeight); Height = YHeight + VHeight; } if(pTexInfo->Flags.Info.RedecribedPlanes) { if(false == RedescribeTexturePlanes(pTexInfo, &WidthBytesPhysical)) { __GMM_ASSERT(false); } } if((Status = // <-- Note assignment. FillTexPitchAndSize( pTexInfo, WidthBytesPhysical, Height, pRestrictions)) == GMM_SUCCESS) { FillPlanarOffsetAddress(pTexInfo); } // Planar & hybrid 2D arrays supported in DX11.1+ spec but not HW. Memory layout // is defined by SW requirements; Y plane must be 4KB aligned. if(pTexInfo->ArraySize > 1) { GMM_GFX_SIZE_T ElementSizeBytes = pTexInfo->Size; int64_t LargeSize; // Size should always be page aligned. __GMM_ASSERT((pTexInfo->Size % PAGE_SIZE) == 0); if((LargeSize = (int64_t)ElementSizeBytes * pTexInfo->ArraySize) <= pPlatform->SurfaceMaxSize) { pTexInfo->OffsetInfo.PlaneXe_LPG.ArrayQPitch = ElementSizeBytes; pTexInfo->Size = LargeSize; } else { GMM_ASSERTDPF(0, "Surface too large!"); Status = GMM_ERROR; } } GMM_DPF_EXIT; return (Status); } // FillTexPlanar ///////////////////////////////////////////////////////////////////////////////////// /// This function calculates the (X,Y) address of each given plane. X is in bytes /// and Y is in scanlines. /// /// @param[in] pTexInfo: ptr to ::GMM_TEXTURE_INFO /// ///////////////////////////////////////////////////////////////////////////////////// void GmmLib::GmmXe_LPGTextureCalc::FillPlanarOffsetAddress(GMM_TEXTURE_INFO *pTexInfo) { GMM_GFX_SIZE_T *pUOffsetX, *pUOffsetY; GMM_GFX_SIZE_T *pVOffsetX, *pVOffsetY; uint32_t YHeight = 0, VHeight = 0; bool UVPacked = false; uint32_t Height; uint32_t WidthBytesPhysical = GFX_ULONG_CAST(pTexInfo->BaseWidth) * pTexInfo->BitsPerPixel >> 3; #define SWAP_UV() \ { \ GMM_GFX_SIZE_T *pTemp; \ \ pTemp = pUOffsetX; \ pUOffsetX = pVOffsetX; \ pVOffsetX = pTemp; \ \ pTemp = pUOffsetY; \ pUOffsetY = pVOffsetY; \ pVOffsetY = pTemp; \ } __GMM_ASSERTPTR(pTexInfo, VOIDRETURN); __GMM_ASSERTPTR(((pTexInfo->TileMode < GMM_TILE_MODES) && (pTexInfo->TileMode >= TILE_NONE)), VOIDRETURN); GMM_DPF_ENTER; const GMM_PLATFORM_INFO *pPlatform = GMM_OVERRIDE_PLATFORM_INFO(pTexInfo, pGmmLibContext); // GMM_PLANE_Y always at (0, 0)... pTexInfo->OffsetInfo.PlaneXe_LPG.X[GMM_PLANE_Y] = 0; pTexInfo->OffsetInfo.PlaneXe_LPG.Y[GMM_PLANE_Y] = 0; pTexInfo->OffsetInfo.PlaneXe_LPG.UnAligned.Height[GMM_PLANE_Y] = 0; pTexInfo->OffsetInfo.PlaneXe_LPG.UnAligned.Height[GMM_PLANE_Y] = 0; Height = pTexInfo->BaseHeight; if(pTexInfo->Flags.Gpu.__NonMsaaTileYCcs) { Height = __GMM_EXPAND_HEIGHT(this, Height, pTexInfo->Alignment.VAlign, pTexInfo); Height = ScaleTextureHeight(pTexInfo, Height); if(pTexInfo->Flags.Gpu.UnifiedAuxSurface) { pTexInfo->OffsetInfo.PlaneXe_LPG.Y[GMM_PLANE_Y] = 0; } } // GMM_PLANE_U/V Planes... pUOffsetX = &pTexInfo->OffsetInfo.PlaneXe_LPG.X[GMM_PLANE_U]; pUOffsetY = &pTexInfo->OffsetInfo.PlaneXe_LPG.Y[GMM_PLANE_U]; pVOffsetX = &pTexInfo->OffsetInfo.PlaneXe_LPG.X[GMM_PLANE_V]; pVOffsetY = &pTexInfo->OffsetInfo.PlaneXe_LPG.Y[GMM_PLANE_V]; switch(pTexInfo->Format) { case GMM_FORMAT_IMC1: SWAP_UV(); // IMC1 = IMC3 with Swapped U/V case GMM_FORMAT_IMC3: case GMM_FORMAT_MFX_JPEG_YUV420: // Same as IMC3. // YYYYYYYY // YYYYYYYY // YYYYYYYY // YYYYYYYY // UUUU // UUUU // VVVV // VVVV case GMM_FORMAT_MFX_JPEG_YUV422V: // Similar to IMC3 but U/V are full width. // YYYYYYYY // YYYYYYYY // YYYYYYYY // YYYYYYYY // UUUUUUUU // UUUUUUUU // VVVVVVVV // VVVVVVVV { *pUOffsetX = 0; YHeight = GFX_ALIGN(pTexInfo->BaseHeight, GMM_IMCx_PLANE_ROW_ALIGNMENT); *pUOffsetY = GFX_ALIGN(pTexInfo->BaseHeight, GMM_IMCx_PLANE_ROW_ALIGNMENT); *pVOffsetX = 0; VHeight = GFX_ALIGN(GFX_CEIL_DIV(pTexInfo->BaseHeight, 2), GMM_IMCx_PLANE_ROW_ALIGNMENT); *pVOffsetY = GFX_ALIGN(pTexInfo->BaseHeight, GMM_IMCx_PLANE_ROW_ALIGNMENT) + GFX_ALIGN(GFX_CEIL_DIV(pTexInfo->BaseHeight, 2), GMM_IMCx_PLANE_ROW_ALIGNMENT); break; } case GMM_FORMAT_MFX_JPEG_YUV411R_TYPE: //Similar to IMC3 but U/V are quarther height and full width. //YYYYYYYY //YYYYYYYY //YYYYYYYY //YYYYYYYY //UUUUUUUU //VVVVVVVV { *pUOffsetX = 0; YHeight = GFX_ALIGN(pTexInfo->BaseHeight, GMM_IMCx_PLANE_ROW_ALIGNMENT); *pUOffsetY = GFX_ALIGN(pTexInfo->BaseHeight, GMM_IMCx_PLANE_ROW_ALIGNMENT); *pVOffsetX = 0; VHeight = GFX_ALIGN(GFX_CEIL_DIV(pTexInfo->BaseHeight, 4), GMM_IMCx_PLANE_ROW_ALIGNMENT); *pVOffsetY = GFX_ALIGN(pTexInfo->BaseHeight, GMM_IMCx_PLANE_ROW_ALIGNMENT) + GFX_ALIGN(GFX_CEIL_DIV(pTexInfo->BaseHeight, 4), GMM_IMCx_PLANE_ROW_ALIGNMENT); break; } case GMM_FORMAT_MFX_JPEG_YUV411: // Similar to IMC3 but U/V are quarter width and full height. // YYYYYYYY // YYYYYYYY // YYYYYYYY // YYYYYYYY // UU // UU // UU // UU // VV // VV // VV // VV case GMM_FORMAT_MFX_JPEG_YUV422H: // Similar to IMC3 but U/V are full height. // YYYYYYYY // YYYYYYYY // YYYYYYYY // YYYYYYYY // UUUU // UUUU // UUUU // UUUU // VVVV // VVVV // VVVV // VVVV case GMM_FORMAT_MFX_JPEG_YUV444: // Similar to IMC3 but U/V are full size. // YYYYYYYY // YYYYYYYY // YYYYYYYY // YYYYYYYY // UUUUUUUU // UUUUUUUU // UUUUUUUU // UUUUUUUU // VVVVVVVV // VVVVVVVV // VVVVVVVV // VVVVVVVV { *pUOffsetX = 0; YHeight = GFX_ALIGN(pTexInfo->BaseHeight, GMM_IMCx_PLANE_ROW_ALIGNMENT); *pUOffsetY = GFX_ALIGN(pTexInfo->BaseHeight, GMM_IMCx_PLANE_ROW_ALIGNMENT); *pVOffsetX = 0; VHeight = GFX_ALIGN(pTexInfo->BaseHeight, GMM_IMCx_PLANE_ROW_ALIGNMENT); *pVOffsetY = GFX_ALIGN(pTexInfo->BaseHeight, GMM_IMCx_PLANE_ROW_ALIGNMENT) * 2; break; } case GMM_FORMAT_BGRP: case GMM_FORMAT_RGBP: { //For RGBP linear Tile keep resource Offset non aligned and for other Tile format to be 16-bit aligned if(pTexInfo->Flags.Info.Linear) { *pUOffsetX = 0; YHeight = pTexInfo->BaseHeight; *pUOffsetY = pTexInfo->BaseHeight; *pVOffsetX = 0; VHeight = pTexInfo->BaseHeight; *pVOffsetY = (GMM_GFX_SIZE_T)pTexInfo->BaseHeight * 2; } else //Tiled { *pUOffsetX = 0; YHeight = GFX_ALIGN(pTexInfo->BaseHeight, GMM_IMCx_PLANE_ROW_ALIGNMENT); *pUOffsetY = GFX_ALIGN(pTexInfo->BaseHeight, GMM_IMCx_PLANE_ROW_ALIGNMENT); *pVOffsetX = 0; VHeight = GFX_ALIGN(pTexInfo->BaseHeight, GMM_IMCx_PLANE_ROW_ALIGNMENT); *pVOffsetY = (GMM_GFX_SIZE_T)GFX_ALIGN(pTexInfo->BaseHeight, GMM_IMCx_PLANE_ROW_ALIGNMENT) * 2; } break; } case GMM_FORMAT_IMC2: SWAP_UV(); // IMC2 = IMC4 with Swapped U/V case GMM_FORMAT_IMC4: { // YYYYYYYY // YYYYYYYY // YYYYYYYY // YYYYYYYY // UUUUVVVV // UUUUVVVV __GMM_ASSERT((pTexInfo->Pitch & 1) == 0); *pUOffsetX = 0; YHeight = GFX_ALIGN(pTexInfo->BaseHeight, GMM_IMCx_PLANE_ROW_ALIGNMENT); *pUOffsetY = GFX_ALIGN(pTexInfo->BaseHeight, GMM_IMCx_PLANE_ROW_ALIGNMENT); *pVOffsetX = pTexInfo->Pitch / 2; VHeight = GFX_CEIL_DIV(YHeight, 2); *pVOffsetY = GFX_ALIGN(pTexInfo->BaseHeight, GMM_IMCx_PLANE_ROW_ALIGNMENT); // Not technically UV packed but sizing works out the same UVPacked = true; break; } case GMM_FORMAT_I420: // I420 = IYUV case GMM_FORMAT_IYUV: SWAP_UV(); // I420/IYUV = YV12 with Swapped U/V case GMM_FORMAT_YV12: case GMM_FORMAT_YVU9: { // YYYYYYYY // YYYYYYYY // YYYYYYYY // YYYYYYYY // VVVVVV.. <-- V and U planes follow the Y plane, as linear // ..UUUUUU arrays--without respect to pitch. uint32_t YSize, YVSizeRShift, VSize, UOffset; uint32_t YSizeForUVPurposes, YSizeForUVPurposesDimensionalAlignment; YSize = GFX_ULONG_CAST(pTexInfo->Pitch) * pTexInfo->BaseHeight; // YVU9 has one U/V pixel for each 4x4 Y block. // The others have one U/V pixel for each 2x2 Y block. // YVU9 has a Y:V size ratio of 16 (4x4 --> 1). // The others have a ratio of 4 (2x2 --> 1). YVSizeRShift = (pTexInfo->Format != GMM_FORMAT_YVU9) ? 2 : 4; // If a Y plane isn't fully-aligned to its Y-->U/V block size, the // extra/unaligned Y pixels still need corresponding U/V pixels--So // for the purpose of computing the UVSize, we must consider a // dimensionally "rounded-up" YSize. (E.g. a 13x5 YVU9 Y plane would // require 4x2 U/V planes--the same UVSize as a fully-aligned 16x8 Y.) YSizeForUVPurposesDimensionalAlignment = (pTexInfo->Format != GMM_FORMAT_YVU9) ? 2 : 4; YSizeForUVPurposes = GFX_ALIGN(GFX_ULONG_CAST(pTexInfo->Pitch), YSizeForUVPurposesDimensionalAlignment) * GFX_ALIGN(pTexInfo->BaseHeight, YSizeForUVPurposesDimensionalAlignment); VSize = (YSizeForUVPurposes >> YVSizeRShift); UOffset = YSize + VSize; *pVOffsetX = 0; *pVOffsetY = pTexInfo->BaseHeight; *pUOffsetX = UOffset % pTexInfo->Pitch; *pUOffsetY = UOffset / pTexInfo->Pitch; YHeight = GFX_CEIL_DIV(YSize + 2 * VSize, WidthBytesPhysical); break; } case GMM_FORMAT_NV12: case GMM_FORMAT_NV21: case GMM_FORMAT_NV11: case GMM_FORMAT_P010: case GMM_FORMAT_P012: case GMM_FORMAT_P016: case GMM_FORMAT_P208: case GMM_FORMAT_P216: { // YYYYYYYY // YYYYYYYY // YYYYYYYY // YYYYYYYY // [UV-Packing] *pUOffsetX = *pVOffsetX = 0; YHeight = GFX_ALIGN(Height, __GMM_EVEN_ROW); *pUOffsetY = *pVOffsetY = YHeight; if((pTexInfo->Format == GMM_FORMAT_NV12) || (pTexInfo->Format == GMM_FORMAT_NV21) || (pTexInfo->Format == GMM_FORMAT_P010) || (pTexInfo->Format == GMM_FORMAT_P012) || (pTexInfo->Format == GMM_FORMAT_P016)) { VHeight = GFX_CEIL_DIV(Height, 2); } else { VHeight = YHeight; // U/V plane is same as Y } UVPacked = true; break; } default: { GMM_ASSERTDPF(0, "Unknown Video Format U\n"); break; } } pTexInfo->OffsetInfo.PlaneXe_LPG.UnAligned.Height[GMM_PLANE_Y] = YHeight; if(pTexInfo->OffsetInfo.PlaneXe_LPG.NoOfPlanes == 2) { pTexInfo->OffsetInfo.PlaneXe_LPG.UnAligned.Height[GMM_PLANE_U] = VHeight; } else if(pTexInfo->OffsetInfo.PlaneXe_LPG.NoOfPlanes == 3) { pTexInfo->OffsetInfo.PlaneXe_LPG.UnAligned.Height[GMM_PLANE_U] = pTexInfo->OffsetInfo.PlaneXe_LPG.UnAligned.Height[GMM_PLANE_V] = VHeight; } if(GMM_IS_TILED(pPlatform->TileInfo[pTexInfo->TileMode]) || pTexInfo->Flags.Gpu.__NonMsaaTileYCcs) { uint32_t TileHeight = pPlatform->TileInfo[pTexInfo->TileMode].LogicalTileHeight; uint32_t TileWidth = pPlatform->TileInfo[pTexInfo->TileMode].LogicalTileWidth; uint32_t PhysicalTileHeight = TileHeight; if(GFX_GET_CURRENT_RENDERCORE(pPlatform->Platform) > IGFX_GEN11LP_CORE) { if(pTexInfo->Flags.Gpu.CCS && !pGmmLibContext->GetSkuTable().FtrFlatPhysCCS) { //U/V must be aligned to AuxT granularity, 4x pitchalign enforces 16K-align for 4KB tile, //add extra padding for 64K AuxT, 1MB AuxT if(GMM_IS_64KB_TILE(pTexInfo->Flags)) { TileHeight *= (!WA64K(pGmmLibContext) && !WA16K(pGmmLibContext)) ? 16 : 1; // For 64Kb Tile mode: Multiply TileHeight by 16 for 1 MB alignment } else { PhysicalTileHeight *= (WA16K(pGmmLibContext) ? 1 : WA64K(pGmmLibContext) ? 4 : 1); // for 1 MB AuxT granularity, we do 1 MB alignment only in VA space and not in physical space, so do not multiply PhysicalTileHeight with 64 here TileHeight *= (WA16K(pGmmLibContext) ? 1 : WA64K(pGmmLibContext) ? 4 : 64); // For 4k Tile: Multiply TileHeight by 4 and Pitch by 4 for 64kb alignment, multiply TileHeight by 64 and Pitch by 4 for 1 MB alignment } if(!WA64K(pGmmLibContext) && !WA16K(pGmmLibContext)) { pTexInfo->OffsetInfo.PlaneXe_LPG.Is1MBAuxTAlignedPlanes = true; pTexInfo->OffsetInfo.PlaneXe_LPG.Physical.Height[GMM_PLANE_Y] = GFX_ALIGN(YHeight, PhysicalTileHeight); // confirm tilealignment is needed for physivcal backing, else calculate size from unaligned offset and use the same if(pTexInfo->OffsetInfo.PlaneXe_LPG.NoOfPlanes == 2) { pTexInfo->OffsetInfo.PlaneXe_LPG.Physical.Height[GMM_PLANE_U] = GFX_ALIGN(VHeight, PhysicalTileHeight); } else if(pTexInfo->OffsetInfo.PlaneXe_LPG.NoOfPlanes == 3) { pTexInfo->OffsetInfo.PlaneXe_LPG.Physical.Height[GMM_PLANE_U] = pTexInfo->OffsetInfo.PlaneXe_LPG.Physical.Height[GMM_PLANE_V] = GFX_ALIGN(VHeight, PhysicalTileHeight); } } } } *pUOffsetX = GFX_ALIGN(*pUOffsetX, TileWidth); *pUOffsetY = GFX_ALIGN(*pUOffsetY, TileHeight); *pVOffsetX = GFX_ALIGN(*pVOffsetX, TileWidth); *pVOffsetY = UVPacked ? GFX_ALIGN(*pVOffsetY, TileHeight) : GFX_ALIGN(YHeight, TileHeight) + GFX_ALIGN(VHeight, TileHeight); if(pTexInfo->Flags.Gpu.UnifiedAuxSurface && pTexInfo->Flags.Gpu.__NonMsaaTileYCcs) { *pUOffsetY += pTexInfo->OffsetInfo.PlaneXe_LPG.Y[GMM_PLANE_Y]; *pVOffsetY = *pUOffsetY; } // This is needed for FtrDisplayPageTables if(pGmmLibContext->GetSkuTable().FtrDisplayPageTables) { if(pTexInfo->OffsetInfo.PlaneXe_LPG.Is1MBAuxTAlignedPlanes) { pTexInfo->OffsetInfo.PlaneXe_LPG.Aligned.Height[GMM_PLANE_Y] = GFX_ALIGN(YHeight, PhysicalTileHeight); // confirm tilealignment is needed for physivcal backing, else calculate size from unaligned offset and use the same if(pTexInfo->OffsetInfo.PlaneXe_LPG.NoOfPlanes == 2) { pTexInfo->OffsetInfo.PlaneXe_LPG.Aligned.Height[GMM_PLANE_U] = GFX_ALIGN(VHeight, PhysicalTileHeight); } else if(pTexInfo->OffsetInfo.PlaneXe_LPG.NoOfPlanes == 3) { pTexInfo->OffsetInfo.PlaneXe_LPG.Aligned.Height[GMM_PLANE_U] = pTexInfo->OffsetInfo.PlaneXe_LPG.Aligned.Height[GMM_PLANE_V] = GFX_ALIGN(VHeight, PhysicalTileHeight); } } else { pTexInfo->OffsetInfo.PlaneXe_LPG.Aligned.Height[GMM_PLANE_Y] = GFX_ALIGN(YHeight, TileHeight); if(pTexInfo->OffsetInfo.PlaneXe_LPG.NoOfPlanes == 2) { pTexInfo->OffsetInfo.PlaneXe_LPG.Aligned.Height[GMM_PLANE_U] = GFX_ALIGN(VHeight, TileHeight); } else if(pTexInfo->OffsetInfo.PlaneXe_LPG.NoOfPlanes == 3) { pTexInfo->OffsetInfo.PlaneXe_LPG.Aligned.Height[GMM_PLANE_U] = pTexInfo->OffsetInfo.PlaneXe_LPG.Aligned.Height[GMM_PLANE_V] = GFX_ALIGN(VHeight, TileHeight); } } } } //Special case LKF MMC compressed surfaces if(pTexInfo->Flags.Gpu.MMC && pTexInfo->Flags.Gpu.UnifiedAuxSurface && pTexInfo->Flags.Info.TiledY) { GMM_GFX_SIZE_T TileHeight = pGmmLibContext->GetPlatformInfo().TileInfo[pTexInfo->TileMode].LogicalTileHeight; GMM_GFX_SIZE_T TileWidth = pGmmLibContext->GetPlatformInfo().TileInfo[pTexInfo->TileMode].LogicalTileWidth; *pUOffsetX = GFX_ALIGN(*pUOffsetX, TileWidth); *pUOffsetY = GFX_ALIGN(*pUOffsetY, TileHeight); *pVOffsetX = GFX_ALIGN(*pVOffsetX, TileWidth); *pVOffsetY = GFX_ALIGN(*pVOffsetY, TileHeight); } GMM_DPF_EXIT; #undef SWAP_UV } //////////////////////////////////////////////////////////////////////////////////// /// Calculates offset address of a sub resource(i.e. Mip Map, Cube face, volume texture) /// /// @param[in] pTexInfo: ptr to ::GMM_TEXTURE_INFO /// @param[in] pReqInfo: ptr to GMM_REQ_OFFSET_INFO to store offset info /// /// @return ::GMM_STATUS ///////////////////////////////////////////////////////////////////////////////////// GMM_STATUS GmmLib::GmmXe_LPGTextureCalc::GetTexLockOffset(GMM_TEXTURE_INFO * pTexInfo, GMM_REQ_OFFSET_INFO *pReqInfo) { GMM_STATUS Result = GMM_SUCCESS; GMM_GFX_SIZE_T AddressOffset; uint32_t Pitch, Slice; uint32_t MipHeight, MipWidth, MipLevel; uint32_t NumberOfMipsInSingleRow, SliceRow; __GMM_ASSERTPTR(pTexInfo, GMM_ERROR); __GMM_ASSERTPTR(pReqInfo, GMM_ERROR); const GMM_PLATFORM_INFO *pPlatform = GMM_OVERRIDE_PLATFORM_INFO(pTexInfo, pGmmLibContext); // set default value AddressOffset = 0; Pitch = GFX_ULONG_CAST(pTexInfo->Pitch); MipLevel = pReqInfo->MipLevel; Slice = pReqInfo->Slice; if(GmmIsPlanar(pTexInfo->Format)) { AddressOffset = GetMipMapByteAddress(pTexInfo, pReqInfo); pReqInfo->Lock.Offset64 = AddressOffset; pReqInfo->Lock.Pitch = pTexInfo->OffsetInfo.PlaneXe_LPG.Is1MBAuxTAlignedPlanes ? GFX_ULONG_CAST(pTexInfo->OffsetInfo.PlaneXe_LPG.PhysicalPitch) : Pitch; // Adjust returned pitch for non-uniform-pitch U/V queries... if((pReqInfo->Plane == GMM_PLANE_U) || (pReqInfo->Plane == GMM_PLANE_V)) { switch(pTexInfo->Format) { case GMM_FORMAT_I420: case GMM_FORMAT_IYUV: case GMM_FORMAT_YV12: case GMM_FORMAT_NV11: pReqInfo->Lock.Pitch /= 2; break; case GMM_FORMAT_YVU9: pReqInfo->Lock.Pitch /= 4; break; default: //Cool--Constant pitch across all planes. break; } } return Result; } switch(pTexInfo->Type) { case RESOURCE_3D: { if(GFX_GET_CURRENT_RENDERCORE(pPlatform->Platform) >= IGFX_GEN9_CORE) { AddressOffset = GFX_ULONG_CAST(GetMipMapByteAddress(pTexInfo, pReqInfo)); // Bytes from one slice to the next... pReqInfo->Lock.Gen9PlusSlicePitch = GFX_ULONG_CAST(pTexInfo->OffsetInfo.Texture2DOffsetInfo.ArrayQPitchLock); } else { MipHeight = pTexInfo->BaseHeight >> MipLevel; MipWidth = GFX_ULONG_CAST(pTexInfo->BaseWidth) >> MipLevel; AlignTexHeightWidth(pTexInfo, &MipHeight, &MipWidth); // See how many mip can fit in one row NumberOfMipsInSingleRow = GFX_2_TO_POWER_OF(MipLevel); SliceRow = Slice / NumberOfMipsInSingleRow; // get the base address + Slice pitch AddressOffset = pTexInfo->OffsetInfo.Texture3DOffsetInfo.Offset[MipLevel]; pReqInfo->Lock.Mip0SlicePitch = GFX_ULONG_CAST(pTexInfo->OffsetInfo.Texture3DOffsetInfo.Mip0SlicePitch); // Actual address is offset based on requested slice AddressOffset += (GMM_GFX_SIZE_T)SliceRow * MipHeight * Pitch; // Get to particular slice if(Slice % NumberOfMipsInSingleRow) { AddressOffset += (((GMM_GFX_SIZE_T)(Slice % NumberOfMipsInSingleRow) * MipWidth * pTexInfo->BitsPerPixel) >> 3); } } break; } case RESOURCE_CUBE: case RESOURCE_2D: case RESOURCE_1D: { AddressOffset = GetMipMapByteAddress(pTexInfo, pReqInfo); break; } default: { // These resources dont' have multiple levels of detail AddressOffset = 0; break; } } pReqInfo->Lock.Offset64 = AddressOffset; pReqInfo->Lock.Pitch = Pitch; return Result; } ///////////////////////////////////////////////////////////////////////////////////// /// Function used to calculate byte address of a specified mip map /// /// @param[in] pTexInfo: ptr to ::GMM_TEXTURE_INFO /// @param[in] pReqInfo: ptr to GMM_REQ_OFFSET_INFO /// /// @return ::GMM_GFX_SIZE_T byte offset ///////////////////////////////////////////////////////////////////////////////////// GMM_GFX_SIZE_T GmmLib::GmmXe_LPGTextureCalc::GetMipMapByteAddress(GMM_TEXTURE_INFO * pTexInfo, GMM_REQ_OFFSET_INFO *pReqInfo) { GMM_GFX_SIZE_T ArrayQPitch, MipMapByteAddress, Pitch; uint32_t MipLevel; __GMM_ASSERTPTR(pTexInfo, GMM_ERROR); __GMM_ASSERTPTR(pReqInfo, GMM_ERROR); __GMM_ASSERT(!(pTexInfo->Flags.Gpu.CCS && !pTexInfo->Flags.Gpu.UnifiedAuxSurface)); __GMM_ASSERT(pReqInfo->Plane < GMM_MAX_PLANE); MipLevel = pReqInfo->MipLevel; Pitch = pTexInfo->Pitch; ArrayQPitch = pReqInfo->ReqRender ? pTexInfo->OffsetInfo.Texture2DOffsetInfo.ArrayQPitchRender : pTexInfo->OffsetInfo.Texture2DOffsetInfo.ArrayQPitchLock; const GMM_PLATFORM_INFO *pPlatform = GMM_OVERRIDE_PLATFORM_INFO(pTexInfo, pGmmLibContext); if(pTexInfo->Type == RESOURCE_3D && !pTexInfo->Flags.Info.Linear) { ArrayQPitch *= pPlatform->TileInfo[pTexInfo->TileMode].LogicalTileDepth; } if((GFX_GET_CURRENT_RENDERCORE(pPlatform->Platform) >= IGFX_GEN8_CORE) && ((pTexInfo->MSAA.NumSamples > 1) && !(pTexInfo->Flags.Gpu.Depth || pTexInfo->Flags.Gpu.SeparateStencil || GMM_IS_64KB_TILE(pTexInfo->Flags) || pTexInfo->Flags.Info.TiledYf))) { ArrayQPitch *= pTexInfo->MSAA.NumSamples; } if(GmmIsPlanar(pTexInfo->Format)) { uint32_t Plane = pReqInfo->Plane; uint32_t OffsetX = 0; uint32_t OffsetY = 0; if(Plane < GMM_MAX_PLANE) { if(pReqInfo->ReqLock && pTexInfo->OffsetInfo.PlaneXe_LPG.Is1MBAuxTAlignedPlanes) { OffsetX = GFX_ULONG_CAST(pTexInfo->OffsetInfo.PlaneXe_LPG.X[GMM_PLANE_Y]); OffsetY = GFX_ULONG_CAST(pTexInfo->OffsetInfo.PlaneXe_LPG.Y[GMM_PLANE_Y]); for(uint32_t PlaneId = GMM_PLANE_Y; PlaneId < Plane; PlaneId++) { // physical offset calculation: x offset remains same as PLANE_Y, YOffset = sum of physical height of all prev planes OffsetY += GFX_ULONG_CAST(pTexInfo->OffsetInfo.PlaneXe_LPG.Physical.Height[PlaneId]); } Pitch = pTexInfo->OffsetInfo.PlaneXe_LPG.PhysicalPitch; ArrayQPitch = ((pTexInfo->OffsetInfo.PlaneXe_LPG.Physical.Height[GMM_PLANE_Y] + pTexInfo->OffsetInfo.PlaneXe_LPG.Physical.Height[GMM_PLANE_U] + pTexInfo->OffsetInfo.PlaneXe_LPG.Physical.Height[GMM_PLANE_V]) * pTexInfo->OffsetInfo.PlaneXe_LPG.PhysicalPitch); // Physical size of single array } else { OffsetX = GFX_ULONG_CAST(pTexInfo->OffsetInfo.PlaneXe_LPG.X[Plane]); OffsetY = GFX_ULONG_CAST(pTexInfo->OffsetInfo.PlaneXe_LPG.Y[Plane]); ArrayQPitch = pTexInfo->OffsetInfo.PlaneXe_LPG.ArrayQPitch; } } MipMapByteAddress = (OffsetY * Pitch) + OffsetX; __GMM_ASSERT(!pReqInfo->ArrayIndex || (pReqInfo->ArrayIndex < pTexInfo->ArraySize)); MipMapByteAddress += (ArrayQPitch * pReqInfo->ArrayIndex); } else { switch(pTexInfo->Type) { case RESOURCE_CUBE: { uint32_t CubeFace = pReqInfo->CubeFace; GMM_ASSERTDPF( // Validate Cube Map Params... (!pReqInfo->ArrayIndex || (pReqInfo->ArrayIndex < pTexInfo->ArraySize)) && (pReqInfo->CubeFace < __GMM_MAX_CUBE_FACE) && (pReqInfo->CubeFace != __GMM_NO_CUBE_MAP) && (pReqInfo->Plane == GMM_NO_PLANE) && (pReqInfo->Slice == 0), "Invalid parameter!"); // Support for CubeMap Arrays using 2D Arrays MipMapByteAddress = pTexInfo->OffsetInfo.Texture2DOffsetInfo.Offset[MipLevel]; MipMapByteAddress += (ArrayQPitch * ((6 * pReqInfo->ArrayIndex) + CubeFace)); break; } case RESOURCE_2D: case RESOURCE_1D: { MipMapByteAddress = pTexInfo->OffsetInfo.Texture2DOffsetInfo.Offset[MipLevel]; if(pReqInfo->ArrayIndex) { MipMapByteAddress += (ArrayQPitch * pReqInfo->ArrayIndex); } break; } case RESOURCE_3D: { if(GFX_GET_CURRENT_RENDERCORE(pPlatform->Platform) >= IGFX_GEN9_CORE) { MipMapByteAddress = pTexInfo->OffsetInfo.Texture2DOffsetInfo.Offset[MipLevel]; if(pReqInfo->Slice) { MipMapByteAddress += (ArrayQPitch * pReqInfo->Slice); } } else { MipMapByteAddress = Get3DMipByteAddress(pTexInfo, pReqInfo); } break; } default: { // These resources don't have multiple levels of detail MipMapByteAddress = 0; break; } } } MipMapByteAddress += pTexInfo->Flags.Gpu.S3d ? GetDisplayFrameOffset(pTexInfo, pReqInfo) : 0; return MipMapByteAddress; } void GmmLib::GmmXe_LPGTextureCalc::SetPlanarOffsetInfo(GMM_TEXTURE_INFO *pTexInfo, GMM_RESCREATE_CUSTOM_PARAMS &CreateParams) { const GMM_PLATFORM_INFO *pPlatform; pPlatform = GMM_OVERRIDE_PLATFORM_INFO(pTexInfo, pGmmLibContext); if(GMM_IS_TILED(pPlatform->TileInfo[pTexInfo->TileMode])) { pTexInfo->OffsetInfo.PlaneXe_LPG.IsTileAlignedPlanes = true; } for(uint8_t i = 1; i <= CreateParams.NoOfPlanes; i++) { pTexInfo->OffsetInfo.PlaneXe_LPG.X[i] = CreateParams.PlaneOffset.X[i]; pTexInfo->OffsetInfo.PlaneXe_LPG.Y[i] = CreateParams.PlaneOffset.Y[i]; } pTexInfo->OffsetInfo.PlaneXe_LPG.NoOfPlanes = CreateParams.NoOfPlanes; } #ifndef __GMM_KMD__ void GmmLib::GmmXe_LPGTextureCalc::SetPlanarOffsetInfo_2(GMM_TEXTURE_INFO *pTexInfo, GMM_RESCREATE_CUSTOM_PARAMS_2 &CreateParams) { const GMM_PLATFORM_INFO *pPlatform; pPlatform = GMM_OVERRIDE_PLATFORM_INFO(pTexInfo, pGmmLibContext); if(GMM_IS_TILED(pPlatform->TileInfo[pTexInfo->TileMode])) { pTexInfo->OffsetInfo.PlaneXe_LPG.IsTileAlignedPlanes = true; } for(uint8_t i = 1; i <= CreateParams.NoOfPlanes; i++) { pTexInfo->OffsetInfo.PlaneXe_LPG.X[i] = CreateParams.PlaneOffset.X[i]; pTexInfo->OffsetInfo.PlaneXe_LPG.Y[i] = CreateParams.PlaneOffset.Y[i]; } pTexInfo->OffsetInfo.PlaneXe_LPG.NoOfPlanes = CreateParams.NoOfPlanes; } #endif void GmmLib::GmmXe_LPGTextureCalc::SetPlaneUnAlignedTexOffsetInfo(GMM_TEXTURE_INFO *pTexInfo, uint32_t YHeight, uint32_t VHeight) { uint32_t UmdUHeight = 0, UmdVHeight = 0; pTexInfo->OffsetInfo.PlaneXe_LPG.UnAligned.Height[GMM_PLANE_Y] = YHeight; if(pTexInfo->OffsetInfo.PlaneXe_LPG.NoOfPlanes == 2) { pTexInfo->OffsetInfo.PlaneXe_LPG.UnAligned.Height[GMM_PLANE_U] = VHeight; UmdUHeight = (GMM_GLOBAL_GFX_SIZE_T)((pTexInfo->Size / pTexInfo->Pitch) - pTexInfo->OffsetInfo.PlaneXe_LPG.Y[GMM_PLANE_U]); } else if(pTexInfo->OffsetInfo.PlaneXe_LPG.NoOfPlanes == 3) { pTexInfo->OffsetInfo.PlaneXe_LPG.UnAligned.Height[GMM_PLANE_U] = pTexInfo->OffsetInfo.PlaneXe_LPG.UnAligned.Height[GMM_PLANE_V] = VHeight; UmdUHeight = (GMM_GLOBAL_GFX_SIZE_T)(pTexInfo->OffsetInfo.PlaneXe_LPG.Y[GMM_PLANE_V] - pTexInfo->OffsetInfo.PlaneXe_LPG.Y[GMM_PLANE_U]); UmdVHeight = (GMM_GLOBAL_GFX_SIZE_T)(((pTexInfo->Size / pTexInfo->Pitch) - pTexInfo->OffsetInfo.PlaneXe_LPG.Y[GMM_PLANE_U]) / 2); __GMM_ASSERTPTR((UmdUHeight == UmdVHeight), VOIDRETURN); } __GMM_ASSERTPTR(((pTexInfo->OffsetInfo.PlaneXe_LPG.Y[GMM_PLANE_U] == YHeight) && (UmdUHeight == VHeight)), VOIDRETURN); } uint32_t GmmLib::GmmXe_LPGTextureCalc::IsTileAlignedPlanes(GMM_TEXTURE_INFO *pTexInfo) { return pTexInfo->OffsetInfo.PlaneXe_LPG.IsTileAlignedPlanes; } uint32_t GmmLib::GmmXe_LPGTextureCalc::GetNumberOfPlanes(GMM_TEXTURE_INFO *pTexInfo) { return pTexInfo->OffsetInfo.PlaneXe_LPG.NoOfPlanes; } void GmmLib::GmmXe_LPGTextureCalc::GetPlaneIdForCpuBlt(GMM_TEXTURE_INFO *pTexInfo, GMM_RES_COPY_BLT *pBlt, uint32_t *PlaneId) { uint32_t TotalHeight = 0; if(pTexInfo->OffsetInfo.PlaneXe_LPG.NoOfPlanes == 2) { TotalHeight = GFX_ULONG_CAST(pTexInfo->OffsetInfo.PlaneXe_LPG.UnAligned.Height[GMM_PLANE_Y] + pTexInfo->OffsetInfo.PlaneXe_LPG.UnAligned.Height[GMM_PLANE_U]); } else if(pTexInfo->OffsetInfo.PlaneXe_LPG.NoOfPlanes == 3) { TotalHeight = GFX_ULONG_CAST(pTexInfo->OffsetInfo.PlaneXe_LPG.UnAligned.Height[GMM_PLANE_Y] + pTexInfo->OffsetInfo.PlaneXe_LPG.UnAligned.Height[GMM_PLANE_U] + pTexInfo->OffsetInfo.PlaneXe_LPG.UnAligned.Height[GMM_PLANE_V]); } else { TotalHeight = GFX_ULONG_CAST(pTexInfo->OffsetInfo.PlaneXe_LPG.UnAligned.Height[GMM_PLANE_Y]); //YV12 exception } // Determine if BLT rectange is for monolithic surface or contained in specific Y/UV plane if(((pBlt->Gpu.OffsetY + pBlt->Blt.Height <= pTexInfo->OffsetInfo.PlaneXe_LPG.Y[GMM_PLANE_U]) || pTexInfo->OffsetInfo.PlaneXe_LPG.NoOfPlanes == 1) && (pBlt->Gpu.OffsetX + pBlt->Blt.Width <= pTexInfo->BaseWidth)) { *PlaneId = GMM_PLANE_Y; } else if(pBlt->Gpu.OffsetY >= pTexInfo->OffsetInfo.PlaneXe_LPG.Y[GMM_PLANE_U] && (pBlt->Gpu.OffsetY + pBlt->Blt.Height <= (pTexInfo->OffsetInfo.PlaneXe_LPG.Y[GMM_PLANE_U] + pTexInfo->OffsetInfo.PlaneXe_LPG.UnAligned.Height[GMM_PLANE_U])) && (pBlt->Gpu.OffsetX + pBlt->Blt.Width <= pTexInfo->BaseWidth)) { *PlaneId = GMM_PLANE_U; } else if(pBlt->Gpu.OffsetY >= pTexInfo->OffsetInfo.PlaneXe_LPG.Y[GMM_PLANE_V] && (pBlt->Gpu.OffsetY + pBlt->Blt.Height <= (pTexInfo->OffsetInfo.PlaneXe_LPG.Y[GMM_PLANE_V] + pTexInfo->OffsetInfo.PlaneXe_LPG.UnAligned.Height[GMM_PLANE_U])) && (pBlt->Gpu.OffsetX + pBlt->Blt.Width <= pTexInfo->BaseWidth)) { *PlaneId = GMM_PLANE_V; } // For smaller surface, BLT rect may fall in Y Plane due to tile alignment but user may have requested monolithic BLT if(pBlt->Gpu.OffsetX == 0 && pBlt->Gpu.OffsetY == 0 && pBlt->Blt.Height >= TotalHeight) { *PlaneId = GMM_MAX_PLANE; } } void GmmLib::GmmXe_LPGTextureCalc::GetBltInfoPerPlane(GMM_TEXTURE_INFO *pTexInfo, GMM_RES_COPY_BLT *pBlt, uint32_t PlaneId) { if(PlaneId == GMM_PLANE_Y) { pBlt->Gpu.OffsetX = GFX_ULONG_CAST(pTexInfo->OffsetInfo.PlaneXe_LPG.X[GMM_PLANE_Y]); pBlt->Gpu.OffsetY = GFX_ULONG_CAST(pTexInfo->OffsetInfo.PlaneXe_LPG.Y[GMM_PLANE_Y]); pBlt->Blt.Height = GFX_ULONG_CAST(pTexInfo->OffsetInfo.PlaneXe_LPG.UnAligned.Height[GMM_PLANE_Y]); } else if(PlaneId == GMM_PLANE_U) { pBlt->Gpu.OffsetX = GFX_ULONG_CAST(pTexInfo->OffsetInfo.PlaneXe_LPG.X[GMM_PLANE_U]); pBlt->Gpu.OffsetY = GFX_ULONG_CAST(pTexInfo->OffsetInfo.PlaneXe_LPG.Y[GMM_PLANE_U]); pBlt->Sys.pData = (char *)pBlt->Sys.pData + uint32_t(pBlt->Blt.Height * pBlt->Sys.RowPitch); pBlt->Blt.Height = GFX_ULONG_CAST(pTexInfo->OffsetInfo.PlaneXe_LPG.UnAligned.Height[GMM_PLANE_U]); if(pTexInfo->Flags.Info.RedecribedPlanes) { __GMM_ASSERT(0); } } else { pBlt->Gpu.OffsetX = GFX_ULONG_CAST(pTexInfo->OffsetInfo.PlaneXe_LPG.X[GMM_PLANE_V]); pBlt->Gpu.OffsetY = GFX_ULONG_CAST(pTexInfo->OffsetInfo.PlaneXe_LPG.Y[GMM_PLANE_V]); pBlt->Blt.Height = GFX_ULONG_CAST(pTexInfo->OffsetInfo.PlaneXe_LPG.UnAligned.Height[GMM_PLANE_U]); pBlt->Sys.pData = (char *)pBlt->Sys.pData + uint32_t(pBlt->Blt.Height * pBlt->Sys.RowPitch); } } gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/TranslationTable/000077500000000000000000000000001466655022700233215ustar00rootroot00000000000000gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/TranslationTable/GmmAuxTable.cpp000066400000000000000000001306421466655022700262010ustar00rootroot00000000000000/*============================================================================== Copyright(c) 2019 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. Description: AUX-Table management functions (contains functions to assign memory to AUX-Tables with valid entries, and update their entries on request) ============================================================================*/ #include "Internal/Common/GmmLibInc.h" #include "../TranslationTable/GmmUmdTranslationTable.h" #if !defined(__GMM_KMD__) //============================================================================= // // Function: MapNullCCS // // Desc: Maps given resource, with dummy null-ccs chain, on Aux Table // // Caller: UpdateAuxTable (map op for null-tiles) // // Parameters: // UmdContext: Caller-thread specific info (regarding BB for TR-Aux udpate, cmdQ to use etc) // BaseAdr: Start adr of main surface // Size: Main-surface size in bytes // PartialL1e: Aux-metadata other than AuxVA // DoNotWait: 1 for CPU update, 0 for async(Gpu) update //----------------------------------------------------------------------------- GMM_STATUS GmmLib::AuxTable::MapNullCCS(GMM_UMD_SYNCCONTEXT *UmdContext, GMM_GFX_ADDRESS BaseAdr, GMM_GFX_SIZE_T Size, uint64_t PartialL1e, uint8_t DoNotWait) { GMM_STATUS Status = GMM_SUCCESS; GMM_GFX_SIZE_T L1TableSize = ((GMM_GFX_SIZE_T)GMM_L1_SIZE(AUXTT, GetGmmLibContext())) * (WA16K(GetGmmLibContext()) ? GMM_KBYTE(16) : GMM_KBYTE(64)); // TGL and above : L1TableSize = 256x64K OR 16x1M GMM_GFX_ADDRESS Addr = 0; GMM_GFX_ADDRESS L3GfxAddress = 0; GMM_CLIENT ClientType; GET_GMM_CLIENT_TYPE(pClientContext, ClientType); EnterCriticalSection(&TTLock); DoNotWait |= (!UmdContext || !UmdContext->pCommandQueueHandle); if(TTL3.L3Handle) { L3GfxAddress = TTL3.GfxAddress; } else { LeaveCriticalSection(&TTLock); return GMM_ERROR; } if(!DoNotWait) { PageTableMgr->TTCb.pfPrologTranslationTable( UmdContext->pCommandQueueHandle); } // For each L1 table for(Addr = GFX_ALIGN_FLOOR(BaseAdr, L1TableSize); // Start at begining of L1 table Addr < BaseAdr + Size; Addr += L1TableSize) // Increment by 1 L1 table { GMM_GFX_ADDRESS L1GfxAddress, L2GfxAddress; GMM_GFX_ADDRESS L1CPUAddress, L2CPUAddress; GMM_GFX_ADDRESS StartAddress = 0; GMM_GFX_ADDRESS EndAddress = 0; GMM_GFX_ADDRESS TileAddr = 0; GMM_GFX_SIZE_T L2eIdx = 0; StartAddress = Addr < BaseAdr ? BaseAdr : Addr; EndAddress = Addr + L1TableSize; if(EndAddress > BaseAdr + Size) { EndAddress = BaseAdr + Size; } GetL1L2TableAddr(StartAddress, &L1GfxAddress, &L2GfxAddress); // If tables are not there, then they are already invalidated as part of // AUX-TT initialization or other APIs. if(L2GfxAddress == GMM_NO_TABLE || L1GfxAddress == GMM_NO_TABLE) { //Clear Valid-bit for L3Entry or L2Entry uint64_t Data = 0; GMM_GFX_ADDRESS TableGfxAddress = (L2GfxAddress == GMM_NO_TABLE) ? L3GfxAddress : L2GfxAddress; GMM_GFX_ADDRESS TableCPUAddress = (L2GfxAddress == GMM_NO_TABLE) ? TTL3.CPUAddress : pTTL2[GMM_L3_ENTRY_IDX(AUXTT, StartAddress)].GetCPUAddress(); uint32_t TableEntryIdx = (L2GfxAddress == GMM_NO_TABLE) ? static_cast(GMM_L3_ENTRY_IDX(AUXTT, StartAddress)) : static_cast(GMM_L2_ENTRY_IDX(AUXTT, StartAddress)); L2CPUAddress = (L2GfxAddress == GMM_NO_TABLE) ? 0 : TableCPUAddress; if(!NullL1Table || !NullL2Table) { AllocateDummyTables(&NullL2Table, &NullL1Table); if(!NullL1Table || !NullL2Table) { //report error LeaveCriticalSection(&TTLock); return GMM_OUT_OF_MEMORY; } else { //Initialize dummy table entries (one-time) GMM_GFX_ADDRESS TableAddr = NullL2Table->GetCPUAddress(); GMM_AUXTTL2e L2e = {0}; L2e.Valid = 1; GMM_TO_AUX_L2e_L1GFXADDR_2((NullL1Table->GetPool()->GetGfxAddress() + PAGE_SIZE * NullL1Table->GetNodeIdx()), L2e, (!WA64K(GetGmmLibContext()) && !WA16K(GetGmmLibContext()))) // populate L2e.L1GfxAddr for(int i = 0; i < GMM_AUX_L2_SIZE; i++) { //initialize L2e ie clear Valid bit for all entries ((GMM_AUXTTL2e *)TableAddr)[i].Value = L2e.Value; } TableAddr = NullL1Table->GetCPUAddress(); GMM_AUXTTL1e L1e = {0}; L1e.Valid = 1; if(!WA64K(GetGmmLibContext())) { L1e.GfxAddress = (NullCCSTile >> 12); /*********** 4kb-aligned CCS adr *****/ } else { L1e.Reserved4 = (NullCCSTile >> 8); /*********** 4 lsbs of 256B-aligned CCS adr *****/ L1e.GfxAddress = (NullCCSTile >> 12); /*********** 4kb-aligned CCS adr *****/ } for(int i = 0; i < GMM_AUX_L1_SIZE(GetGmmLibContext()); i++) { //initialize L1e with null ccs tile ((GMM_AUXTTL1e *)TableAddr)[i].Value = L1e.Value; } } } if(L2GfxAddress == GMM_NO_TABLE) { GMM_AUXTTL3e L3e = {0}; L3e.Valid = 1; L3e.L2GfxAddr = (NullL2Table->GetPool()->GetGfxAddress() + PAGE_SIZE * NullL2Table->GetNodeIdx()) >> 15; Data = L3e.Value; } else { GMM_AUXTTL2e L2e = {0}; L2e.Valid = 1; GMM_TO_AUX_L2e_L1GFXADDR_2((NullL1Table->GetPool()->GetGfxAddress() + PAGE_SIZE * NullL1Table->GetNodeIdx()), L2e, (!WA64K(GetGmmLibContext()) && !WA16K(GetGmmLibContext()))) Data = L2e.Value; } if(DoNotWait) { //Sync update on CPU ((GMM_AUXTTL2e *)TableCPUAddress)[TableEntryIdx].Value = Data; } else { if(L2GfxAddress != GMM_NO_TABLE) { pTTL2[GMM_L3_ENTRY_IDX(AUXTT, StartAddress)].UpdatePoolFence(UmdContext, false); } PageTableMgr->TTCb.pfWriteL2L3Entry(UmdContext->pCommandQueueHandle, TableGfxAddress + TableEntryIdx * GMM_AUX_L2e_SIZE, Data); } continue; } else { uint32_t L3eIdx = static_cast(GMM_L3_ENTRY_IDX(AUXTT, StartAddress)); L2CPUAddress = pTTL2[L3eIdx].GetCPUAddress(); L2eIdx = GMM_L2_ENTRY_IDX(AUXTT, StartAddress); if(DoNotWait) { //Sync update on CPU ((GMM_AUXTTL3e *)(TTL3.CPUAddress))[L3eIdx].Valid = 1; //set Valid bit ((GMM_AUXTTL3e *)(TTL3.CPUAddress))[L3eIdx].L2GfxAddr = L2GfxAddress >> 15; ((GMM_AUXTTL2e *)L2CPUAddress)[L2eIdx].Valid = 1; //set Valid bit GMM_TO_AUX_L2e_L1GFXADDR_2(L1GfxAddress, ((GMM_AUXTTL2e *)L2CPUAddress)[L2eIdx], (!WA64K(GetGmmLibContext()) && !WA16K(GetGmmLibContext()))) } else { GMM_AUXTTL3e L3e = {0}; L3e.Valid = 1; L3e.L2GfxAddr = L2GfxAddress >> 15; PageTableMgr->TTCb.pfWriteL2L3Entry( UmdContext->pCommandQueueHandle, L3GfxAddress + (L3eIdx * GMM_AUX_L3e_SIZE), L3e.Value); pTTL2[L3eIdx].UpdatePoolFence(UmdContext, false); GMM_AUXTTL2e L2e = {0}; L2e.Valid = 1; GMM_TO_AUX_L2e_L1GFXADDR_2(L1GfxAddress, L2e, (!WA64K(GetGmmLibContext()) && !WA16K(GetGmmLibContext()))) PageTableMgr->TTCb.pfWriteL2L3Entry( UmdContext->pCommandQueueHandle, L2GfxAddress + (L2eIdx * GMM_AUX_L2e_SIZE), L2e.Value); } } // For each 64KB or 16KB of main surface (entry) in L1 table for(TileAddr = StartAddress; TileAddr < EndAddress; TileAddr += (WA16K(GetGmmLibContext()) ? GMM_KBYTE(16) : WA64K(GetGmmLibContext()) ? GMM_KBYTE(64) : GMM_MBYTE(1))) { uint64_t Data = PartialL1e | NullCCSTile | __BIT(0); GMM_GFX_SIZE_T L1eIdx = GMM_L1_ENTRY_IDX(AUXTT, TileAddr, GetGmmLibContext()); GmmLib::LastLevelTable *pL1Tbl = NULL; pL1Tbl = pTTL2[GMM_AUX_L3_ENTRY_IDX(TileAddr)].GetL1Table(L2eIdx, NULL); L1CPUAddress = pL1Tbl->GetCPUAddress(); if(DoNotWait) { //Sync update on CPU ((GMM_AUXTTL1e *)L1CPUAddress)[L1eIdx].Value = Data; GMM_DPF(GFXDBG_NORMAL, "##### Null-Map | Table Entry: TileAddress[0x%llX] L2eIdx[%d] :: L1eIdx[%d] L1Addr[0x%llX] L1Value[00x%llX]\n", TileAddr, L2eIdx, L1eIdx, &((GMM_AUXTTL1e *)L1CPUAddress)[L1eIdx], Data); } else { pL1Tbl->UpdatePoolFence(UmdContext, false); /* PageTableMgr->TTCb.pfWriteL1Entries( UmdContext->pCommandQueueHandle, 2, L1GfxAddress + (L1eIdx * GMM_AUX_L1e_SIZE), (uint32_t*)(&Data));*/ //**********REQUIRE UMD CHANGE TO UPDATE 64-bit ENTRY - both DWORDs must be updated atomically*******/ PageTableMgr->TTCb.pfWriteL2L3Entry( UmdContext->pCommandQueueHandle, L1GfxAddress + (L1eIdx * GMM_AUX_L1e_SIZE), Data); } if(pL1Tbl->TrackTableUsage(AUXTT, true, TileAddr, true, GetGmmLibContext())) { // L1 Table is not being used anymore GMM_AUXTTL2e L2e = {0}; GmmLib::GMM_PAGETABLEPool *PoolElem = NULL; GmmLib::LastLevelTable * pL1Tbl = NULL, *Prev = NULL; pL1Tbl = pTTL2[GMM_L3_ENTRY_IDX(AUXTT, TileAddr)].GetL1Table(L2eIdx, &Prev); // Map L2-entry to Null-L1Table L2e.Valid = 1; GMM_TO_AUX_L2e_L1GFXADDR_2((NullL1Table->GetPool()->GetGfxAddress() + PAGE_SIZE * NullL1Table->GetNodeIdx()), L2e, (!WA64K(GetGmmLibContext()) && !WA16K(GetGmmLibContext()))) // populate L2e.L1GfxAddress/Le2.Reserved2 if(DoNotWait) { //Sync update on CPU ((GMM_AUXTTL2e *)L2CPUAddress)[L2eIdx].Value = L2e.Value; } else { pTTL2[GMM_L3_ENTRY_IDX(AUXTT, TileAddr)].UpdatePoolFence(UmdContext, false); PageTableMgr->TTCb.pfWriteL2L3Entry(UmdContext->pCommandQueueHandle, L2GfxAddress + L2eIdx * GMM_AUX_L2e_SIZE, L2e.Value); } //Update usage for PoolNode assigned to L1Table, and free L1Tbl if(pL1Tbl) { PoolElem = pL1Tbl->GetPool(); if(PoolElem) { if(pL1Tbl->GetBBInfo().BBQueueHandle) { PoolElem->GetNodeBBInfoAtIndex(pL1Tbl->GetNodeIdx()) = pL1Tbl->GetBBInfo(); } DEASSIGN_POOLNODE(PageTableMgr, UmdContext, PoolElem, pL1Tbl->GetNodeIdx(), AUX_L1TABLE_SIZE_IN_POOLNODES_2(GetGmmLibContext())) } pTTL2[GMM_L3_ENTRY_IDX(AUXTT, TileAddr)].DeleteFromList(pL1Tbl, Prev); } // The L1 table is unused -- meaning everything else in this table is // already invalid. So, break early. break; } } } if(!DoNotWait) { PageTableMgr->TTCb.pfEpilogTranslationTable( UmdContext->pCommandQueueHandle, 1); // ForceFlush } LeaveCriticalSection(&TTLock); return Status; } //============================================================================= // // Function: InvalidateTable (InvalidateMappings) // // Desc: Unmaps given resource from Aux Table; and marks affected entries as invalid // // Caller: UpdateAuxTable (unmap op) // // Parameters: // UmdContext: Caller-thread specific info (regarding BB for Aux udpate, cmdQ to use etc) // BaseAdr: Start adr of main surface // Size: Main-surface size in bytes? (or take GmmResInfo?) // DoNotWait: 1 for CPU update, 0 for async(Gpu) update //----------------------------------------------------------------------------- GMM_STATUS GmmLib::AuxTable::InvalidateTable(GMM_UMD_SYNCCONTEXT *UmdContext, GMM_GFX_ADDRESS BaseAdr, GMM_GFX_SIZE_T Size, uint8_t DoNotWait) { GMM_STATUS Status = GMM_SUCCESS; GMM_GFX_SIZE_T L1TableSize = ((GMM_GFX_SIZE_T)GMM_L1_SIZE(AUXTT, GetGmmLibContext())) * (WA16K(GetGmmLibContext()) ? GMM_KBYTE(16) : GMM_KBYTE(64)); //Each AuxTable entry maps 16K main-surface GMM_GFX_ADDRESS Addr = 0; GMM_GFX_ADDRESS L3GfxAddress = 0; uint8_t isTRVA = 0; GMM_CLIENT ClientType; GET_GMM_CLIENT_TYPE(pClientContext, ClientType); //NullCCSTile isn't initialized, disable TRVA path isTRVA = (NullCCSTile ? isTRVA : 0); EnterCriticalSection(&TTLock); DoNotWait |= (!UmdContext || !UmdContext->pCommandQueueHandle); if(TTL3.L3Handle) { L3GfxAddress = TTL3.GfxAddress; } else { LeaveCriticalSection(&TTLock); return GMM_ERROR; } if(!DoNotWait) { PageTableMgr->TTCb.pfPrologTranslationTable( UmdContext->pCommandQueueHandle); } // For each L1 table for(Addr = GFX_ALIGN_FLOOR(BaseAdr, L1TableSize); // Start at begining of L1 table Addr < BaseAdr + Size; Addr += L1TableSize) // Increment by 1 L1 table { GMM_GFX_ADDRESS L1GfxAddress, L2GfxAddress; GMM_GFX_ADDRESS L1CPUAddress, L2CPUAddress; GMM_GFX_ADDRESS StartAddress = 0; GMM_GFX_ADDRESS EndAddress = 0; GMM_GFX_ADDRESS TileAddr = 0; GMM_GFX_SIZE_T L2eIdx = 0; StartAddress = Addr < BaseAdr ? BaseAdr : Addr; EndAddress = Addr + L1TableSize; if(EndAddress > BaseAdr + Size) { EndAddress = BaseAdr + Size; } GetL1L2TableAddr(StartAddress, &L1GfxAddress, &L2GfxAddress); // If tables are not there, then they are already invalidated as part of // AUX-TT initialization or other APIs. if(L2GfxAddress == GMM_NO_TABLE || L1GfxAddress == GMM_NO_TABLE) { //Clear Valid-bit for L3Entry or L2Entry GMM_AUXTTL2e L2e = {0}; //AUXTT L3e is identical to L2e, reuse. GMM_GFX_ADDRESS TableGfxAddress = (L2GfxAddress == GMM_NO_TABLE) ? L3GfxAddress : L2GfxAddress; GMM_GFX_ADDRESS TableCPUAddress = (L2GfxAddress == GMM_NO_TABLE) ? TTL3.CPUAddress : pTTL2[GMM_L3_ENTRY_IDX(AUXTT, StartAddress)].GetCPUAddress(); uint32_t TableEntryIdx = (L2GfxAddress == GMM_NO_TABLE) ? static_cast(GMM_L3_ENTRY_IDX(AUXTT, StartAddress)) : static_cast(GMM_L2_ENTRY_IDX(AUXTT, StartAddress)); L2CPUAddress = (L2GfxAddress == GMM_NO_TABLE) ? 0 : TableCPUAddress; if(isTRVA && NullL2Table && NullL1Table) { //invalidate if request spans entire stretch ie TileAdr aligns L1TableSize*GMM_L2_SIZE uint64_t Data = 0; if(L2GfxAddress == GMM_NO_TABLE) { GMM_AUXTTL3e L3e = {0}; L3e.Valid = 1; L3e.L2GfxAddr = (NullL2Table->GetPool()->GetGfxAddress() + PAGE_SIZE * NullL2Table->GetNodeIdx()) >> 15; Data = L3e.Value; } else { GMM_AUXTTL2e L2e = {0}; L2e.Valid = 1; GMM_TO_AUX_L2e_L1GFXADDR_2((NullL1Table->GetPool()->GetGfxAddress() + PAGE_SIZE * NullL1Table->GetNodeIdx()), L2e, (!WA64K(GetGmmLibContext()) && !WA16K(GetGmmLibContext()))) Data = L2e.Value; } L2e.Value = Data; } else { L2e.Valid = 0; } if(DoNotWait) { //Sync update on CPU ((GMM_AUXTTL2e *)TableCPUAddress)[TableEntryIdx].Value = L2e.Value; } else { if(L2GfxAddress != GMM_NO_TABLE) { pTTL2[GMM_L3_ENTRY_IDX(AUXTT, StartAddress)].UpdatePoolFence(UmdContext, false); } PageTableMgr->TTCb.pfWriteL2L3Entry(UmdContext->pCommandQueueHandle, TableGfxAddress + TableEntryIdx * GMM_AUX_L2e_SIZE, L2e.Value); } continue; } else { uint32_t L3eIdx = static_cast(GMM_L3_ENTRY_IDX(AUXTT, StartAddress)); L2CPUAddress = pTTL2[L3eIdx].GetCPUAddress(); L2eIdx = GMM_L2_ENTRY_IDX(AUXTT, StartAddress); if(DoNotWait) { //Sync update on CPU ((GMM_AUXTTL3e *)(TTL3.CPUAddress))[L3eIdx].Valid = 1; //set Valid bit ((GMM_AUXTTL3e *)(TTL3.CPUAddress))[L3eIdx].L2GfxAddr = L2GfxAddress >> 15; ((GMM_AUXTTL2e *)L2CPUAddress)[L2eIdx].Valid = 1; //set Valid bit GMM_TO_AUX_L2e_L1GFXADDR_2(L1GfxAddress, ((GMM_AUXTTL2e *)L2CPUAddress)[L2eIdx], (!WA64K(GetGmmLibContext()) && !WA16K(GetGmmLibContext()))) } else { GMM_AUXTTL3e L3e = {0}; L3e.Valid = 1; L3e.L2GfxAddr = L2GfxAddress >> 15; PageTableMgr->TTCb.pfWriteL2L3Entry( UmdContext->pCommandQueueHandle, L3GfxAddress + (L3eIdx * GMM_AUX_L3e_SIZE), L3e.Value); pTTL2[L3eIdx].UpdatePoolFence(UmdContext, false); GMM_AUXTTL2e L2e = {0}; L2e.Valid = 1; GMM_TO_AUX_L2e_L1GFXADDR_2(L1GfxAddress, L2e, (!WA64K(GetGmmLibContext()) && !WA16K(GetGmmLibContext()))) PageTableMgr->TTCb.pfWriteL2L3Entry( UmdContext->pCommandQueueHandle, L2GfxAddress + (L2eIdx * GMM_AUX_L2e_SIZE), L2e.Value); } } // For each 64KB or 16KB or 1MB of main surface (entry) in L1 table for(TileAddr = StartAddress; TileAddr < EndAddress; TileAddr += (WA16K(GetGmmLibContext()) ? GMM_KBYTE(16) : WA64K(GetGmmLibContext()) ? GMM_KBYTE(64) : GMM_MBYTE(1))) { //Invalidation of requested range irrespective of TRVA uint64_t Data = GMM_INVALID_AUX_ENTRY; GMM_GFX_SIZE_T L1eIdx = GMM_L1_ENTRY_IDX(AUXTT, TileAddr, GetGmmLibContext()); GmmLib::LastLevelTable *pL1Tbl = NULL; pL1Tbl = pTTL2[GMM_AUX_L3_ENTRY_IDX(TileAddr)].GetL1Table(L2eIdx, NULL); L1CPUAddress = pL1Tbl->GetCPUAddress(); if(DoNotWait) { //Sync update on CPU ((GMM_AUXTTL1e *)L1CPUAddress)[L1eIdx].Value = Data; GMM_DPF(GFXDBG_NORMAL, "~~UnMap | Table Entry: L2addressBase[0x%llX] :: L2Valid[%d] :: L2eidx[%d] L1addressBase[0x%llX] :: L1eidx[%d] L1Valid[%d] :: DerivedCCS[0x%llX] ", (GMM_AUXTTL2e *)L2CPUAddress, ((GMM_AUXTTL2e *)L2CPUAddress)[L2eIdx].Valid, L2eIdx, GMM_L1TABLE_ADDR_FROM_AUX_L2e_L1GFXADDR(((GMM_AUXTTL2e *)L2CPUAddress)[L2eIdx], true), L1eIdx, ((GMM_AUXTTL1e *)L1CPUAddress)[L1eIdx].Valid, (((GMM_AUXTTL1e *)L1CPUAddress)[L1eIdx].GfxAddress << 12)); } else { pL1Tbl->UpdatePoolFence(UmdContext, false); /* PageTableMgr->TTCb.pfWriteL1Entries( UmdContext->pCommandQueueHandle, 2, (uint32_t*)(&Data));*/ //**********REQUIRE UMD CHANGE TO UPDATE 64-bit ENTRY - both DWORDs must be updated atomically*******/ PageTableMgr->TTCb.pfWriteL2L3Entry( UmdContext->pCommandQueueHandle, L1GfxAddress + (L1eIdx * GMM_AUX_L1e_SIZE), Data); } if(pL1Tbl->TrackTableUsage(AUXTT, true, TileAddr, true, GetGmmLibContext())) { // L1 Table is not being used anymore GMM_AUXTTL2e L2e = {0}; GmmLib::GMM_PAGETABLEPool *PoolElem = NULL; GmmLib::LastLevelTable * pL1Tbl = NULL, *Prev = NULL; pL1Tbl = pTTL2[GMM_L3_ENTRY_IDX(AUXTT, TileAddr)].GetL1Table(L2eIdx, &Prev); if(isTRVA && NullL1Table && ((TileAddr > GFX_ALIGN_FLOOR(BaseAdr, L1TableSize) && TileAddr < GFX_ALIGN_NP2(BaseAdr, L1TableSize)) || (TileAddr > GFX_ALIGN_FLOOR(BaseAdr + Size, L1TableSize) && TileAddr < GFX_ALIGN_NP2(BaseAdr + Size, L1TableSize)))) { //Invalidation affects entries out of requested range, null-map for TR L2e.Valid = 1; GMM_TO_AUX_L2e_L1GFXADDR_2((NullL1Table->GetPool()->GetGfxAddress() + PAGE_SIZE * NullL1Table->GetNodeIdx()), L2e, (!WA64K(GetGmmLibContext()) && !WA16K(GetGmmLibContext()))) } else { // Clear valid bit of L2 entry L2e.Valid = 0; ((GMM_AUXTTL2e *)L2CPUAddress)[L2eIdx].Valid = 0; } if(DoNotWait) { //Sync update on CPU ((GMM_AUXTTL2e *)L2CPUAddress)[L2eIdx].Value = L2e.Value; } else { pTTL2[GMM_L3_ENTRY_IDX(AUXTT, TileAddr)].UpdatePoolFence(UmdContext, false); PageTableMgr->TTCb.pfWriteL2L3Entry(UmdContext->pCommandQueueHandle, L2GfxAddress + L2eIdx * GMM_AUX_L2e_SIZE, L2e.Value); } //Update usage for PoolNode assigned to L1Table, and free L1Tbl if(pL1Tbl) { PoolElem = pL1Tbl->GetPool(); if(PoolElem) { if(pL1Tbl->GetBBInfo().BBQueueHandle) { PoolElem->GetNodeBBInfoAtIndex(pL1Tbl->GetNodeIdx()) = pL1Tbl->GetBBInfo(); } DEASSIGN_POOLNODE(PageTableMgr, UmdContext, PoolElem, pL1Tbl->GetNodeIdx(), AUX_L1TABLE_SIZE_IN_POOLNODES_2(GetGmmLibContext())) } pTTL2[GMM_L3_ENTRY_IDX(AUXTT, TileAddr)].DeleteFromList(pL1Tbl, Prev); } // The L1 table is unused -- meaning everything else in this table is // already invalid. So, break early. break; } } } if(!DoNotWait) { PageTableMgr->TTCb.pfEpilogTranslationTable( UmdContext->pCommandQueueHandle, 1); // ForceFlush } LeaveCriticalSection(&TTLock); return Status; } //============================================================================= // // Function: MapValidEntry // // Desc: Maps given main-surface, on Aux-Table, to get the exact CCS cacheline tied to // different 4x4K pages of main-surface // // Caller: UpdateAuxTable (map op) // // Parameters: // UmdContext: ptr to thread-data // BaseAdr: Start adr of main-surface // BaseSize: main-surface Size in bytes // BaseResInfo: main surface ResInfo // AuxVA: Start adr of Aux-surface // AuxResInfo: Aux surface ResInfo // PartialData: Aux L1 partial data (ie w/o address) // DoNotWait: true for CPU update, false for async(Gpu) update //----------------------------------------------------------------------------- GMM_STATUS GmmLib::AuxTable::MapValidEntry(GMM_UMD_SYNCCONTEXT *UmdContext, GMM_GFX_ADDRESS BaseAdr, GMM_GFX_SIZE_T BaseSize, GMM_RESOURCE_INFO *BaseResInfo, GMM_GFX_ADDRESS AuxVA, GMM_RESOURCE_INFO *AuxResInfo, uint64_t PartialData, uint8_t DoNotWait) { GMM_STATUS Status = GMM_SUCCESS; GMM_GFX_ADDRESS Addr = 0, L3TableAdr = GMM_NO_TABLE; GMM_GFX_SIZE_T L1TableSize = GMM_AUX_L1_SIZE(GetGmmLibContext()) * (WA16K(GetGmmLibContext()) ? GMM_KBYTE(16) : GMM_KBYTE(64)); // L1TableSize maps to 16MB address space for TGL and above: 256x64k | 16x1MB GMM_GFX_SIZE_T CCS$Adr = AuxVA; uint8_t isTRVA =0 ; GMM_CLIENT ClientType; GET_GMM_CLIENT_TYPE(pClientContext, ClientType); //NullCCSTile isn't initialized, disable TRVA path isTRVA = (NullCCSTile ? isTRVA : 0); EnterCriticalSection(&TTLock); if(!TTL3.L3Handle || (!DoNotWait && !UmdContext)) { Status = GMM_ERROR; } else { L3TableAdr = TTL3.GfxAddress; if(!DoNotWait) { PageTableMgr->TTCb.pfPrologTranslationTable(UmdContext->pCommandQueueHandle); } // GMM_DPF(GFXDBG_CRITICAL, "Mapping surface: GPUVA=0x%016llX Size=0x%08X Aux_GPUVA=0x%016llX\n", BaseAdr, BaseSize, AuxVA); for(Addr = GFX_ALIGN_FLOOR(BaseAdr, L1TableSize); Addr < BaseAdr + BaseSize; Addr += L1TableSize) { GMM_GFX_ADDRESS StartAdr, EndAdr, TileAdr; GMM_GFX_ADDRESS L1TableAdr = GMM_NO_TABLE, L2TableAdr = GMM_NO_TABLE; GMM_GFX_ADDRESS L1TableCPUAdr = GMM_NO_TABLE, L2TableCPUAdr = GMM_NO_TABLE; GMM_GFX_SIZE_T L2eIdx = 0; GMM_GFX_SIZE_T L3eIdx = 0; bool AllocateL1 = false, AllocateL2 = false; EndAdr = Addr + L1TableSize; EndAdr = EndAdr > BaseAdr + BaseSize ? BaseAdr + BaseSize : EndAdr; StartAdr = Addr < BaseAdr ? BaseAdr : Addr; L2eIdx = GMM_L2_ENTRY_IDX(AUXTT, StartAdr); L3eIdx = GMM_L3_ENTRY_IDX(AUXTT, StartAdr); //Allocate L2/L1 Table -- get L2 Table Adr for GetL1L2TableAddr(Addr, &L1TableAdr, &L2TableAdr); if(L2TableAdr == GMM_NO_TABLE || L1TableAdr == GMM_NO_TABLE) { AllocateL1 = GMM_NO_TABLE == L1TableAdr; AllocateL2 = GMM_NO_TABLE == L2TableAdr; AllocateL1L2Table(Addr, &L1TableAdr, &L2TableAdr); if(L2TableAdr == GMM_NO_TABLE || L1TableAdr == GMM_NO_TABLE) { LeaveCriticalSection(&TTLock); return GMM_OUT_OF_MEMORY; } if(AllocateL2) { uint32_t i = 0; GMM_AUXTTL2e InvalidEntry; InvalidEntry.Value = 0; if(isTRVA && NullL1Table) { InvalidEntry.Valid = 1; GMM_TO_AUX_L2e_L1GFXADDR_2((NullL1Table->GetPool()->GetGfxAddress() + PAGE_SIZE * NullL1Table->GetNodeIdx()), InvalidEntry, (!WA16K(GetGmmLibContext()) && !WA64K(GetGmmLibContext()))) } if(DoNotWait) { L2TableCPUAdr = pTTL2[L3eIdx].GetCPUAddress(); ((GMM_AUXTTL3e *)(TTL3.CPUAddress))[L3eIdx].Value = 0; ((GMM_AUXTTL3e *)(TTL3.CPUAddress))[L3eIdx].L2GfxAddr = L2TableAdr >> 15; ((GMM_AUXTTL3e *)(TTL3.CPUAddress))[L3eIdx].Valid = 1; for(i = 0; i < GMM_AUX_L2_SIZE; i++) { //initialize L2e ie clear Valid bit for all entries ((GMM_AUXTTL2e *)L2TableCPUAdr)[i].Value = InvalidEntry.Value; } } else { GMM_AUXTTL3e L3e = {0}; L3e.Valid = 1; L3e.L2GfxAddr = L2TableAdr >> 15; PageTableMgr->TTCb.pfWriteL2L3Entry(UmdContext->pCommandQueueHandle, L3TableAdr + L3eIdx * GMM_AUX_L3e_SIZE, L3e.Value); //initialize L2e ie clear valid bit for all entries for(i = 0; i < GMM_AUX_L2_SIZE; i++) { PageTableMgr->TTCb.pfWriteL2L3Entry(UmdContext->pCommandQueueHandle, L2TableAdr + i * GMM_AUX_L2e_SIZE, InvalidEntry.Value); } } } if(AllocateL1) { uint64_t InvalidEntry = (!isTRVA) ? GMM_INVALID_AUX_ENTRY : (NullCCSTile | __BIT(0)); uint32_t i = 0; if(DoNotWait) { GmmLib::LastLevelTable *pL1Tbl = NULL; pL1Tbl = pTTL2[L3eIdx].GetL1Table(L2eIdx, NULL); L2TableCPUAdr = pTTL2[L3eIdx].GetCPUAddress(); L1TableCPUAdr = pL1Tbl->GetCPUAddress(); //Sync update on CPU ((GMM_AUXTTL2e *)L2TableCPUAdr)[L2eIdx].Value = 0; GMM_TO_AUX_L2e_L1GFXADDR_2(L1TableAdr, ((GMM_AUXTTL2e *)L2TableCPUAdr)[L2eIdx], (!WA64K(GetGmmLibContext()) && !WA16K(GetGmmLibContext()))) // populate L2e.L1GfxAddr ((GMM_AUXTTL2e *)L2TableCPUAdr)[L2eIdx] .Valid = 1; for(i = 0; i < (uint32_t)GMM_AUX_L1_SIZE(GetGmmLibContext()); i++) { //initialize L1e ie mark all entries with Null tile value ((GMM_AUXTTL1e *)L1TableCPUAdr)[i].Value = InvalidEntry; } } else { GMM_AUXTTL2e L2e = {0}; L2e.Valid = 1; GMM_TO_AUX_L2e_L1GFXADDR_2(L1TableAdr, L2e, (!WA64K(GetGmmLibContext()) && !WA16K(GetGmmLibContext()))) pTTL2[L3eIdx] .UpdatePoolFence(UmdContext, false); PageTableMgr->TTCb.pfWriteL2L3Entry(UmdContext->pCommandQueueHandle, L2TableAdr + L2eIdx * GMM_AUX_L2e_SIZE, L2e.Value); //initialize all L1e with invalid entries for(i = 0; i < (uint32_t)GMM_AUX_L1_SIZE(GetGmmLibContext()); i++) { PageTableMgr->TTCb.pfWriteL2L3Entry(UmdContext->pCommandQueueHandle, L1TableAdr + i * sizeof(uint64_t), InvalidEntry); } } } } //GMM_DPF(GFXDBG_NORMAL, "Mapping surface: GPUVA=0x%016llx Size=0x%08x Aux_GPUVA=0x%016llx", StartAdr, BaseSize, CCS$Adr); for(TileAdr = StartAdr; TileAdr < EndAdr; TileAdr += (WA16K(GetGmmLibContext()) ? GMM_KBYTE(16) : WA64K(GetGmmLibContext()) ? GMM_KBYTE(64) : GMM_MBYTE(1)), CCS$Adr += (pClientContext->GetLibContext()->GetSkuTable().FtrLinearCCS ? (WA16K(pClientContext->GetLibContext()) ? GMM_BYTES(64) : WA64K(pClientContext->GetLibContext()) ? GMM_BYTES(256) : GMM_KBYTE(4)) : 0)) { GMM_GFX_SIZE_T L1eIdx = GMM_L1_ENTRY_IDX(AUXTT, TileAdr, GetGmmLibContext()); GMM_AUXTTL1e L1e = {0}; L1e.Value = PartialData; L1e.Valid = 1; if(L1eIdx == 15 || L1eIdx == 14) { GMM_DPF(GFXDBG_NORMAL, "\n****** switching over L1*******\n"); } CCS$Adr = (pClientContext->GetLibContext()->GetSkuTable().FtrLinearCCS ? CCS$Adr : __GetCCSCacheline(BaseResInfo, BaseAdr, AuxResInfo, AuxVA, TileAdr - BaseAdr)); if(WA16K(GetGmmLibContext())) { L1e.Reserved2 = CCS$Adr >> 6; /*********** 2 lsbs of 64B-aligned CCS adr *****/ L1e.Reserved4 = CCS$Adr >> 8; /*********** 256B-aligned CCS adr *****/ L1e.GfxAddress = CCS$Adr >> 12; /*********** 4KB-aligned CCS adr *****/ } else if(WA64K(GetGmmLibContext())) { __GMM_ASSERT((CCS$Adr & 0xFF) == 0x0); __GMM_ASSERT(GFX_IS_ALIGNED(CCS$Adr, GMM_BYTES(256))); __GMM_ASSERT(GFX_IS_ALIGNED(TileAdr, GMM_KBYTE(64))); L1e.Reserved4 = CCS$Adr >> 8; /*********** 4 lsbs of 256B-aligned CCS adr *****/ L1e.GfxAddress = CCS$Adr >> 12; /*********** 4KB-aligned CCS adr *****/ } else // 1MB aligned address { __GMM_ASSERT((CCS$Adr & 0xFF) == 0x0); __GMM_ASSERT(GFX_IS_ALIGNED(CCS$Adr, GMM_KBYTE(4))); __GMM_ASSERT(GFX_IS_ALIGNED(TileAdr, GMM_MBYTE(1))); L1e.GfxAddress = CCS$Adr >> 12; /*********** 4KB-aligned CCS adr *****/ } GMM_DPF(GFXDBG_NORMAL, "--------------------------------MAP AuxTT Map Address: TileAddr[0x%llX], Size[0x%x], CCSAddr[0x%llX], L3eIdx[%d], L2eIdx[%d], L1eIdx[%d], \n L1CCSAddres[0x%llX] \n", TileAdr, BaseSize, CCS$Adr, L3eIdx, L2eIdx, L1eIdx, L1e.GfxAddress); GmmLib::LastLevelTable *pL1Tbl = NULL; pL1Tbl = pTTL2[L3eIdx].GetL1Table(L2eIdx, NULL); L1TableCPUAdr = pL1Tbl->GetCPUAddress(); if(DoNotWait) { //Sync update on CPU ((GMM_AUXTTL1e *)L1TableCPUAdr)[L1eIdx].Value = L1e.Value; } else { pL1Tbl->UpdatePoolFence(UmdContext, false); PageTableMgr->TTCb.pfWriteL2L3Entry(UmdContext->pCommandQueueHandle, L1TableAdr + L1eIdx * GMM_AUX_L1e_SIZE, L1e.Value); } GMM_DPF(GFXDBG_NORMAL, "Map | L3 Table Entry: L3AddressBase[0x%llX] :: L3.L2GfxAddr[0x%llX] :: L3Valid[0x%llX] \n", (GMM_AUXTTL3e *)(TTL3.CPUAddress), ((GMM_AUXTTL3e *)(TTL3.CPUAddress))[L3eIdx].L2GfxAddr, ((GMM_AUXTTL3e *)(TTL3.CPUAddress))[L3eIdx].Valid); GMM_DPF(GFXDBG_NORMAL, "Map | L2 Table Entry: L2addressBase[0x%llX] :: L2.L1GfxAddr[0x%llX] :: L2Valid[0x%llX] \n", ((GMM_AUXTTL2e *)pTTL2[L3eIdx].GetCPUAddress()), ((GMM_AUXTTL2e *)pTTL2[L3eIdx].GetCPUAddress())[L2eIdx].L1GfxAddr, ((GMM_AUXTTL2e *)pTTL2[L3eIdx].GetCPUAddress())[L2eIdx].Valid); GMM_DPF(GFXDBG_NORMAL, "Map | L1 Table Entry: L1addressBase[0x%llX] :: L1.CCSAddr[0x%llX] :: L1ValueReserved4[0x%llX] ::L1ValueReserved2[0x%llX] :: L1Valid[0x%llX] :: DerivedCCS[0x%llX] \n\n", ((GMM_AUXTTL1e *)L1TableCPUAdr), ((GMM_AUXTTL1e *)L1TableCPUAdr)[L1eIdx].GfxAddress, ((GMM_AUXTTL1e *)L1TableCPUAdr)[L1eIdx].Reserved4, ((GMM_AUXTTL1e *)L1TableCPUAdr)[L1eIdx].Reserved2, ((GMM_AUXTTL1e *)L1TableCPUAdr)[L1eIdx].Valid, (((GMM_AUXTTL1e *)L1TableCPUAdr)[L1eIdx].GfxAddress << 12)); GMM_DPF(GFXDBG_NORMAL, "**Map | Table Entry: L2addressBase[0x%llX] :: L2Valid[%d] :: L2eidx[%d] L1addressBase[0x%llX] :: L1eidx[%d] L1Valid[0x%llX] :: DerivedCCS[0x%llX]", ((GMM_AUXTTL2e *)pTTL2[L3eIdx].GetCPUAddress()), ((GMM_AUXTTL2e *)pTTL2[L3eIdx].GetCPUAddress())[L2eIdx].Valid, L2eIdx, GMM_L1TABLE_ADDR_FROM_AUX_L2e_L1GFXADDR(((GMM_AUXTTL2e *)pTTL2[L3eIdx].GetCPUAddress())[L2eIdx], true), L1eIdx, ((GMM_AUXTTL1e *)L1TableCPUAdr)[L1eIdx].Valid, (((GMM_AUXTTL1e *)L1TableCPUAdr)[L1eIdx].GfxAddress << 12)); // Since we are mapping a non-null entry, no need to check whether // L1 table is unused. pL1Tbl->TrackTableUsage(AUXTT, true, TileAdr, false, GetGmmLibContext()); } } if(!DoNotWait) { PageTableMgr->TTCb.pfEpilogTranslationTable( UmdContext->pCommandQueueHandle, 1); } } LeaveCriticalSection(&TTLock); return Status; } GMM_AUXTTL1e GmmLib::AuxTable::CreateAuxL1Data(GMM_RESOURCE_INFO *BaseResInfo) { GMM_RESOURCE_FORMAT Format; Format = BaseResInfo->GetResourceFormat(); Format = ((Format > GMM_FORMAT_INVALID) && (Format < GMM_RESOURCE_FORMATS)) ? Format : GMM_FORMAT_INVALID; GMM_FORMAT_ENTRY FormatInfo = pClientContext->GetLibContext()->GetPlatformInfo().FormatTable[Format]; GMM_AUXTTL1e L1ePartial = {0}; #define GMM_REGISTRY_UMD_PATH "SOFTWARE\\Intel\\IGFX\\GMM\\" #define GMM_E2EC_OVERRIDEDEPTH16BPPTO12 "ForceYUV16To12BPP" L1ePartial.Mode = BaseResInfo->GetResFlags().Info.RenderCompressed ? 0x1 : 0x0; //MC on VCS supports all compression modes, //MC on Render pipe only 128B compr (until B-step) //Recognize which .MC surfaces needs Render pipe access if(pClientContext->GetLibContext()->GetWaTable().WaLimit128BMediaCompr) { L1ePartial.Mode = 0x1; //Limit media compression to 128B (same as RC) on gen12LP A0 } //L1ePartial.Lossy = 0; // when to set it L1ePartial.TileMode = BaseResInfo->GetResFlags().Info.TiledYs ? 0 : 1; L1ePartial.Format = FormatInfo.CompressionFormat.AuxL1eFormat; L1ePartial.LumaChroma = GmmIsPlanar(Format); if(pClientContext->GetLibContext()->GetWaTable().WaUntypedBufferCompression && BaseResInfo->GetResourceType() == RESOURCE_BUFFER) { //Gen12LP WA to support untyped raw buffer compression on HDC ie MLC(machine-learning compression) L1ePartial.TileMode = 0; L1ePartial.Depth = 0x6; L1ePartial.Format = GMM_E2ECOMP_FORMAT_RGBAFLOAT16; } __GMM_ASSERT(L1ePartial.Format > GMM_E2ECOMP_MIN_FORMAT && //Are we going to reuse 0x00 for uncompressed indication? CCS contains that info, but only known by HW L1ePartial.Format <= GMM_E2ECOMP_MAX_FORMAT); //Could SW use it as surface-wide uncompressed state indicator? If so, remove teh assert (Need to make sure, all format encodings are correct) if(BaseResInfo->GetResFlags().Info.RenderCompressed) { if(BaseResInfo->GetResourceType() != RESOURCE_BUFFER) { switch(FormatInfo.Element.BitsPer) { case 8: L1ePartial.Depth = 0x4; break; case 16: L1ePartial.Depth = 0x0; break; case 32: L1ePartial.Depth = 0x5; break; case 64: L1ePartial.Depth = 0x6; break; case 128: L1ePartial.Depth = 0x7; break; default: L1ePartial.Depth = 0x3; } } } else { switch(Format) { case GMM_FORMAT_P012: case GMM_FORMAT_Y412: case GMM_FORMAT_Y212: //which format encoding for Y212, Y412, P012? L1ePartial.Depth = 0x2; break; case GMM_FORMAT_P010: //case GMM_FORMAT_Y410: case GMM_FORMAT_Y210: //which format encoding for Y210? L1ePartial.Depth = 0x1; break; case GMM_FORMAT_P016: //per HAS, separate encoding than P010, but a comment says to use P010 in AuxTable? case GMM_FORMAT_Y416: case GMM_FORMAT_Y216: L1ePartial.Depth = 0x0; break; default: L1ePartial.Depth = 0x3; //For MC, bpp got from format encoding } if(L1ePartial.Format == GMM_E2ECOMP_FORMAT_R10G10B10A2_UNORM) { L1ePartial.Format = GMM_E2ECOMP_FORMAT_RGB10b; } } return L1ePartial; } GMM_GFX_ADDRESS GMM_INLINE GmmLib::AuxTable::__GetCCSCacheline(GMM_RESOURCE_INFO *BaseResInfo, GMM_GFX_ADDRESS BaseAdr, GMM_RESOURCE_INFO *AuxResInfo, GMM_GFX_ADDRESS AuxVA, GMM_GFX_SIZE_T AdrOffset) { GMM_GFX_ADDRESS CCSChunkAdr = 0xFFFFFFF0; uint32_t x = 0, y = 0; uint32_t i = 0, j = 0; uint32_t CCSXTile = 0, CCSYTile = 0; GMM_UNREFERENCED_PARAMETER(BaseAdr); bool BaseIsYF = BaseResInfo->GetResFlags().Info.TiledYf ? true : false; uint32_t BasePitchInTiles = BaseResInfo->GetRenderPitchTiles(); //Find YF/YS TileId for given main surface 16K-chunk //and CCS$Id corresponding to main's AdrOffset >>= 14; //AdrOffset must be 16K-aligned chunk, since mapping unit is 4 YF pages if(BaseIsYF) { uint32_t PitchIn4YF = BasePitchInTiles / 4; //Base Pitch is physically padded to 4x1 YF width if (PitchIn4YF != 0) { i = static_cast(AdrOffset % PitchIn4YF); j = static_cast(AdrOffset / PitchIn4YF); } else { __GMM_ASSERT(PitchIn4YF != 0); return 0; } } else if(BasePitchInTiles != 0) //TileYs { x = static_cast(AdrOffset >> 2); //YS-tile count y = x / BasePitchInTiles; //YS- tile id x = x % BasePitchInTiles; i = 2 * x; j = 2 * y; switch(AdrOffset % 4) //YS : XYXY [XYXY YF] ie 2x2 16K-units in Y-major { case 0: break; case 1: j++; break; case 2: i++; break; case 3: i++; j++; break; } } //Compute CCS$ address for CCSXTile = (i >= 8) ? i / 8 : 0; //8x8 CLs make one CCS Tile; get TileOffset CCSYTile = (j >= 8) ? j / 8 : 0; i %= 8; j %= 8; uint32_t AuxPitchInTiles = AuxResInfo ? AuxResInfo->GetRenderPitchTiles() : BaseResInfo->GetRenderAuxPitchTiles(); CCSChunkAdr = AuxVA + ((CCSXTile + CCSYTile * AuxPitchInTiles) * GMM_KBYTE(4)) + (8 * GMM_BYTES(64) * i) + (GMM_BYTES(64) * j); return CCSChunkAdr; } #endif /*!__GMM_KMD__*/ gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/TranslationTable/GmmPageTableMgr.cpp000066400000000000000000000653431466655022700267730ustar00rootroot00000000000000/*============================================================================== Copyright(c) 2019 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. Description: UMD-TT manager (manages both TR-TT and AUX-TT in user mode space) ============================================================================*/ #include "Internal/Common/GmmLibInc.h" #include "External/Common/GmmPageTableMgr.h" #include "../TranslationTable/GmmUmdTranslationTable.h" #include "External/Common/GmmClientContext.h" #if defined(__linux__) #include "Internal/Linux/GmmResourceInfoLinInt.h" #endif #define ENTER_CRITICAL_SECTION \ if(AuxTTObj) \ { \ EnterCriticalSection(&PoolLock); \ } #define EXIT_CRITICAL_SECTION \ if(AuxTTObj) \ { \ LeaveCriticalSection(&PoolLock); \ } extern GMM_MA_LIB_CONTEXT *pGmmMALibContext; #if defined(__linux__) GMM_STATUS GmmLib::__GmmDeviceAlloc(GmmClientContext * pClientContext, GMM_DEVICE_CALLBACKS_INT *pDeviceCbInt, GMM_DEVICE_ALLOC * pAlloc) { GMM_CLIENT ClientType; GMM_DDI_ALLOCATE Alloc = {0}; int err; GET_GMM_CLIENT_TYPE(pClientContext, ClientType); __GMM_ASSERTPTR(GmmCheckForNullDevCbPfn(ClientType, pDeviceCbInt, GMM_DEV_CB_ALLOC), GMM_INVALIDPARAM); if(GmmCheckForNullDevCbPfn(ClientType, pDeviceCbInt, GMM_DEV_CB_ALLOC)) { Alloc.size = pAlloc->Size; Alloc.alignment = pAlloc->Alignment; err = GmmDeviceCallback(ClientType, pDeviceCbInt, &Alloc); if(err) { return GMM_OUT_OF_MEMORY; } pAlloc->GfxVA = Alloc.gfxAddr; pAlloc->CPUVA = (GMM_GFX_ADDRESS) Alloc.cpuAddr; pAlloc->Handle = (HANDLE)Alloc.bo; } return GMM_SUCCESS; } GMM_STATUS GmmLib::__GmmDeviceDealloc(GMM_CLIENT ClientType, GMM_DEVICE_CALLBACKS_INT *DeviceCb, GMM_DEVICE_DEALLOC * pDealloc, GmmClientContext * pClientContext) { GMM_DDI_DEALLOCATE DeAlloc = {0}; int err = 0; __GMM_ASSERTPTR(GmmCheckForNullDevCbPfn(ClientType, DeviceCb, GMM_DEV_CB_DEALLOC), GMM_INVALIDPARAM); if(GmmCheckForNullDevCbPfn(ClientType, DeviceCb, GMM_DEV_CB_DEALLOC)) { DeAlloc.bo = pDealloc->Handle; err = GmmDeviceCallback(ClientType, DeviceCb, &DeAlloc); } return (err == 0) ? GMM_SUCCESS : GMM_ERROR; } #endif //============================================================================= // // Function: __AllocateNodePool // // Desc: Allocates (always resident SVM) memory for new Pool node, and updates PageTableMgr object // // Parameters: // AddrAlignment: Pool allocation address alignment // // Returns: // S_OK on success, //----------------------------------------------------------------------------- GmmLib::GMM_PAGETABLEPool *GmmLib::GmmPageTableMgr::__AllocateNodePool(uint32_t AddrAlignment, GmmLib::POOL_TYPE Type) { GMM_STATUS Status = GMM_SUCCESS; GMM_RESOURCE_INFO *pGmmResInfo = NULL; GMM_PAGETABLEPool *pTTPool = NULL; HANDLE PoolHnd = 0; GMM_CLIENT ClientType; GMM_DEVICE_ALLOC Alloc = {0}; ENTER_CRITICAL_SECTION //Allocate pool, sized PAGETABLE_POOL_MAX_NODES pages, assignable to TR/Aux L1/L2 tables //SVM allocation, always resident Alloc.Size = PAGETABLE_POOL_SIZE; Alloc.Alignment = AddrAlignment; Alloc.hCsr = hCsr; Status = __GmmDeviceAlloc(pClientContext, &DeviceCbInt, &Alloc); if(Status != GMM_SUCCESS) { __GMM_ASSERT(0); EXIT_CRITICAL_SECTION return NULL; } PoolHnd = Alloc.Handle; pGmmResInfo = (GMM_RESOURCE_INFO *)Alloc.Priv; pTTPool = new GMM_PAGETABLEPool(PoolHnd, pGmmResInfo, Alloc.GfxVA, Alloc.CPUVA, Type); if(pTTPool) { if(pPool) { NumNodePoolElements++; if(Type == POOL_TYPE_TRTTL2) // TRTT-L2 not 1st node in Pool LinkedList, place it at beginning { pPool = pPool->InsertInListAtBegin(pTTPool); } else { pTTPool = pPool->InsertInList(pTTPool); } } else { NumNodePoolElements = 1; pPool = pTTPool; } } else { __GMM_ASSERT(0); Status = GMM_OUT_OF_MEMORY; } EXIT_CRITICAL_SECTION return (Status == GMM_SUCCESS) ? pTTPool : NULL; } //============================================================================= // // Function: __ReleaseUnusedPool // // Desc: Frees up unused PageTablePools once residency limit is hit // // Parameters: // UmdContext: pointer to caller thread's context (containing BBHandle/Fence info) // //----------------------------------------------------------------------------- void GmmLib::GmmPageTableMgr::__ReleaseUnusedPool(GMM_UMD_SYNCCONTEXT *UmdContext) { GMM_STATUS Status = GMM_SUCCESS; GMM_GFX_SIZE_T PoolSizeToFree = {0}; GMM_GFX_SIZE_T FreedSize = {0}; GmmLib::GMM_PAGETABLEPool *Pool = NULL, *PrevPool = NULL; uint32_t i = 0; GMM_CLIENT ClientType; GMM_DEVICE_DEALLOC Dealloc; GET_GMM_CLIENT_TYPE(pClientContext, ClientType); ENTER_CRITICAL_SECTION if(pPool->__IsUnusedTRTTPoolOverLimit(&PoolSizeToFree)) { for(i = 0; i < NumNodePoolElements && FreedSize < PoolSizeToFree; i++) { Pool = (PrevPool) ? PrevPool->GetNextPool() : pPool; if(Pool->IsPoolInUse(UmdContext ? SyncInfo(UmdContext->BBFenceObj, UmdContext->BBLastFence) : SyncInfo())) { PrevPool = Pool; continue; } if(GmmCheckForNullDevCbPfn(ClientType, &DeviceCbInt, GMM_DEV_CB_WAIT_FROM_CPU)) { GMM_DDI_WAITFORSYNCHRONIZATIONOBJECTFROMCPU Wait = {0}; Wait.bo = Pool->GetPoolHandle(); GmmDeviceCallback(ClientType, &DeviceCbInt, &Wait); } Dealloc.Handle = Pool->GetPoolHandle(); Dealloc.GfxVA = Pool->GetGfxAddress(); Dealloc.Priv = Pool->GetGmmResInfo(); Dealloc.hCsr = hCsr; Status = __GmmDeviceDealloc(ClientType, &DeviceCbInt, &Dealloc, pClientContext); __GMM_ASSERT(GMM_SUCCESS == Status); if(PrevPool) { PrevPool->GetNextPool() = Pool->GetNextPool(); } else { pPool = Pool->GetNextPool(); } delete Pool; FreedSize += PAGETABLE_POOL_SIZE; } } EXIT_CRITICAL_SECTION } //============================================================================= // // Function: __GetFreePoolNode // // Desc: Finds free node within existing PageTablePool(s), if no such node found, // allocates new PageTablePool. Caller should update Pool Node usage // // Parameters: // FreePoolNodeIdx: pointer to return Pool's free Node index // PoolType: AuxTT_L1/L2 pool // // Returns: // PageTablePool element and FreePoolNodeIdx that should be used for L2/L1 assignment // NULL, if no free node exists and new pool allocation failed //----------------------------------------------------------------------------- GmmLib::GMM_PAGETABLEPool *GmmLib::GmmPageTableMgr::__GetFreePoolNode(uint32_t *FreePoolNodeIdx, POOL_TYPE PoolType) { uint32_t PoolNode = -1, i = 0, j = 0, DWdivisor = 1, IdxMultiplier = 1; bool PoolNodeFound = false, TRTTPool = false; ENTER_CRITICAL_SECTION GmmLib::GMM_PAGETABLEPool *Pool = pPool; Pool = (PoolType == POOL_TYPE_TRTTL2) ? Pool : //1st pool reserved for TRTT-L2, since TRTT-L2 pruning not supported yet, (Pool ? Pool->GetNextPool() : NULL); //other pools can be TR-L1/Aux-L1/Aux-L2 (and support dynamic pruning) TRTTPool = (PoolType == POOL_TYPE_TRTTL2 || PoolType == POOL_TYPE_TRTTL1) ? true : false; DWdivisor = TRTTPool ? 8 * sizeof(uint32_t) : (PoolType == POOL_TYPE_AUXTTL2) ? 8 * sizeof(uint32_t) * AUX_L2TABLE_SIZE_IN_POOLNODES : 8 * sizeof(uint32_t) * AUX_L1TABLE_SIZE_IN_POOLNODES_2(GetLibContext()); IdxMultiplier = TRTTPool ? 1 : (PoolType == POOL_TYPE_AUXTTL2) ? AUX_L2TABLE_SIZE_IN_POOLNODES : AUX_L1TABLE_SIZE_IN_POOLNODES_2(GetLibContext()); //Scan existing PageTablePools for free pool node for(i = (PoolType == POOL_TYPE_TRTTL2) ? 0 : 1; Pool && i < NumNodePoolElements; i++) { if(Pool->GetNumFreeNode() > 0 && Pool->GetPoolType() == PoolType) { PoolNodeFound = true; *FreePoolNodeIdx = 0; for(; j < PAGETABLE_POOL_MAX_NODES / DWdivisor; j++) { if(_BitScanForward((uint32_t *)&PoolNode, (uint32_t) ~(Pool->GetNodeUsageAtIndex(j)))) // Get LSB that has value 0 { *FreePoolNodeIdx += PoolNode * IdxMultiplier; PoolNodeFound = true; break; } PoolNodeFound = false; *FreePoolNodeIdx += DWdivisor; //DWORD size in bits } } if(PoolNodeFound) { __GMM_ASSERT(Pool->GetPoolType() == PoolType); EXIT_CRITICAL_SECTION return Pool; } Pool = Pool->GetNextPool(); } //No free pool node, allocate new if(!PoolNodeFound) { GMM_PAGETABLEPool *Pool = NULL; if(Pool = __AllocateNodePool(IdxMultiplier * PAGE_SIZE, PoolType)) { __GMM_ASSERT(Pool->GetPoolType() == PoolType); *FreePoolNodeIdx = 0; EXIT_CRITICAL_SECTION return Pool; } } EXIT_CRITICAL_SECTION return NULL; } /********************************************************************************** ** Class GmmPageTableMgr functions ** ***********************************************************************************/ ///////////////////////////////////////////////////////////////////////////////////// /// Instantiates GmmPageTableMgr, allocating memory for root-tables, copies provided /// device-callback function pointers /// /// @param[in] DeviceCb: pointer sharing device-callback function pointers /// @param[in] TTFlags: Flags specifying which PageTables are required by client /// @return GmmPageTableMgr* ///////////////////////////////////////////////////////////////////////////////////// GmmLib::GmmPageTableMgr::GmmPageTableMgr(GMM_DEVICE_CALLBACKS_INT *DeviceCB, uint32_t TTFlags, GmmClientContext *pClientContextIn) : GmmPageTableMgr() { GMM_PAGETABLE_MGR *ptr = NULL; GMM_STATUS status = GMM_SUCCESS; GMM_CLIENT ClientType; if(pClientContextIn) { ClientType = pClientContextIn->GetClientType(); } else { goto ERROR_CASE; } // this is needed if there is an error case and destructor gets called on ptr this->pClientContext = pClientContextIn; // Currently coping the code below to GMMOldAPi.cpp for backward compatible. // Any changes here should be copied there. //Initialize PageTableMgr further, only if PageTable creation succeeded try { ptr = new GmmPageTableMgr(); ptr->pClientContext = pClientContextIn; memcpy(&ptr->DeviceCbInt, DeviceCB, sizeof(GMM_DEVICE_CALLBACKS_INT)); if(pClientContextIn->GetSkuTable().FtrE2ECompression && !pClientContextIn->GetSkuTable().FtrFlatPhysCCS) { __GMM_ASSERT(TTFlags & AUXTT); //Aux-TT is mandatory ptr->AuxTTObj = new AuxTable(pClientContext); if(!ptr->AuxTTObj) { goto ERROR_CASE; } ptr->AuxTTObj->PageTableMgr = ptr; ptr->AuxTTObj->pClientContext = pClientContextIn; status = ptr->AuxTTObj->AllocateL3Table(8 * PAGE_SIZE, 8 * PAGE_SIZE); if(status != GMM_SUCCESS) { InitializeCriticalSection(&(ptr->PoolLock)); goto ERROR_CASE; } } } catch(...) { __GMM_ASSERT(false); if(ptr && (AuxTTObj)) { InitializeCriticalSection(&(ptr->PoolLock)); } goto ERROR_CASE; } if(status == GMM_SUCCESS && !(AuxTTObj)) { if(ptr->AuxTTObj) { ptr->AuxTTObj->PageTableMgr = this; } *this = *ptr; //Don't initialize PoolLock until any of AuxTable object created if(ptr->AuxTTObj ) { InitializeCriticalSection(&PoolLock); } //Delete temporary ptr, but don't release allocated PageTable Obj. ptr->AuxTTObj = NULL; } ERROR_CASE: delete ptr; ptr = NULL; } ///////////////////////////////////////////////////////////////////////////////////// /// Returns Root-table address for Aux-table /// /// @return GMM_GFX_ADDRESS if Aux-Table was created; NULL otherwise ///////////////////////////////////////////////////////////////////////////////////// GMM_GFX_ADDRESS GmmLib::GmmPageTableMgr::GetAuxL3TableAddr() { return AuxTTObj ? AuxTTObj->GetL3Address() : 0ULL; } ///////////////////////////////////////////////////////////////////////////////////// /// Queues commands to initialize Aux-Table registers in the HW context image /// /// @param[in] initialBBHandle: pointer to BatchBuffer for queuing commands /// @param[in] engType: specifes engine on which the context would run /// @return GMM_SUCCESS if queuing succeeded; GMM_ERROR otherwise ///////////////////////////////////////////////////////////////////////////////////// GMM_STATUS GmmLib::GmmPageTableMgr::InitContextAuxTableRegister(HANDLE CmdQHandle, GMM_ENGINE_TYPE engType) { GMM_GFX_ADDRESS MaskedL3GfxAddress = 0ULL; GMM_UNREFERENCED_PARAMETER(engType); //Check FtrE2ECompression = 1 if(GetLibContext()->GetSkuTable().FtrE2ECompression && AuxTTObj != NULL) { EnterCriticalSection(&AuxTTObj->TTLock); if(CmdQHandle) { //engType = ENGINE_TYPE_RCS; //use correct offset based on engType (once per-eng offsets known) uint64_t RegOffset = 0, L3AdrReg = 0; GET_L3ADROFFSET(0, L3AdrReg, GetLibContext()); RegOffset = (L3AdrReg + sizeof(uint32_t)); RegOffset = L3AdrReg | (RegOffset << 0x20); MaskedL3GfxAddress = AuxTTObj->GetL3Address(); //TTCb.pfPrologTranslationTable(CmdQHandle); //MI_FLUSH, TLBInv not required since its called during context-init TTCb.pfWriteL3Adr(CmdQHandle, MaskedL3GfxAddress, RegOffset); GMM_DPF(GFXDBG_NORMAL, "AuxTT Map Address: GPUVA=0x%016llX\n", MaskedL3GfxAddress); //TTCb.pfEpilogTranslationTable(CmdQHandle, 0); AuxTTObj->GetRegisterStatus() = 0; } else { __GMM_ASSERT(false); LeaveCriticalSection(&AuxTTObj->TTLock); return GMM_INVALIDPARAM; } LeaveCriticalSection(&AuxTTObj->TTLock); } return GMM_SUCCESS; } ///////////////////////////////////////////////////////////////////////////////////// /// Updates the Aux-PageTables, for given base resource, with appropriate mappings /// /// @param[in] Details of AuxTable update request /// @return GMM_STATUS ///////////////////////////////////////////////////////////////////////////////////// GMM_STATUS GmmLib::GmmPageTableMgr::UpdateAuxTable(const GMM_DDI_UPDATEAUXTABLE *UpdateReq) { if(GetAuxL3TableAddr() == 0ULL) { GMM_ASSERTDPF(0, "Invalid AuxTable update request, AuxTable is not initialized"); return GMM_INVALIDPARAM; } if(!((UpdateReq->BaseResInfo->GetResFlags().Info.RenderCompressed || UpdateReq->BaseResInfo->GetResFlags().Info.MediaCompressed) && ((!UpdateReq->AuxResInfo && UpdateReq->BaseResInfo->GetResFlags().Gpu.UnifiedAuxSurface) || (UpdateReq->AuxResInfo && UpdateReq->AuxResInfo->GetResFlags().Gpu.CCS)))) /*(UpdateReq->BaseResInfo->GetResFlags().Gpu.TiledResource || UpdateReq->BaseResInfo->GetResFlags().Gpu.Depth) */ //Allow Separate Aux for Depth/TR/MSAA/others? { GMM_ASSERTDPF(0, "Invalid AuxTable update request"); return GMM_INVALIDPARAM; } if(UpdateReq->Map && !(!UpdateReq->BaseResInfo->GetResFlags().Gpu.TiledResource || (UpdateReq->BaseResInfo->GetResFlags().Gpu.TiledResource && UpdateReq->UmdContext && UpdateReq->UmdContext->pCommandQueueHandle))) { //GMM_DPF_CRITICAL("TiledResources must Gpu-update AuxTable, proceeding with CPU-update..."); //Allowing CPU-update if requested so.. if(!UpdateReq->DoNotWait) { return GMM_INVALIDPARAM; } } ENTER_CRITICAL_SECTION if(UpdateReq->Map) { //Get AuxL1e data (other than CCS-adr) from main surface uint64_t PartialL1e = AuxTTObj->CreateAuxL1Data(UpdateReq->BaseResInfo).Value; GMM_STATUS Status = GMM_SUCCESS; if(UpdateReq->BaseResInfo->GetResFlags().Gpu.TiledResource) { //Aux-TT is sparsely updated, for TRs, upon change in mapping state ie // null->non-null must be mapped // non-null->null invalidated on AuxTT uint8_t CpuUpdate = UpdateReq->DoNotWait || !(UpdateReq->UmdContext && UpdateReq->UmdContext->pCommandQueueHandle); GMM_GFX_ADDRESS AuxVA = UpdateReq->AuxSurfVA; if(UpdateReq->BaseResInfo->GetResFlags().Gpu.UnifiedAuxSurface) { GMM_UNIFIED_AUX_TYPE AuxType = GMM_AUX_CCS; AuxType = (UpdateReq->BaseResInfo->GetResFlags().Gpu.Depth && UpdateReq->BaseResInfo->GetResFlags().Gpu.CCS) ? GMM_AUX_ZCS : AuxType; AuxVA = UpdateReq->BaseGpuVA + GmmResGetAuxSurfaceOffset64(UpdateReq->BaseResInfo, AuxType); } } else { GMM_GFX_ADDRESS AuxVA = {0}; GMM_GFX_ADDRESS UVAuxVA = {0}; GMM_GFX_SIZE_T YPlaneSize = 0; uint32_t MaxPlanes = 1; if(!UpdateReq->AuxResInfo && UpdateReq->BaseResInfo->GetResFlags().Gpu.UnifiedAuxSurface) { GMM_UNIFIED_AUX_TYPE AuxType = GMM_AUX_CCS; AuxType = (UpdateReq->BaseResInfo->GetResFlags().Gpu.Depth && UpdateReq->BaseResInfo->GetResFlags().Gpu.CCS) ? GMM_AUX_ZCS : AuxType; AuxVA = UpdateReq->BaseGpuVA + GmmResGetAuxSurfaceOffset64(UpdateReq->BaseResInfo, AuxType); //For UV Packed, Gen12 e2e compr supported formats have 2 planes per surface //Each has distinct Aux surface, Y-plane/UV-plane must be mapped to respective Y/UV Aux surface if(GmmIsPlanar(UpdateReq->BaseResInfo->GetResourceFormat())) { GMM_REQ_OFFSET_INFO ReqInfo = {0}; ReqInfo.Plane = GMM_PLANE_U; ReqInfo.ReqRender = 1; MaxPlanes = 2; UpdateReq->BaseResInfo->GetOffset(ReqInfo); YPlaneSize = ReqInfo.Render.Offset64; UVAuxVA = UpdateReq->BaseGpuVA + GmmResGetAuxSurfaceOffset64(UpdateReq->BaseResInfo, GMM_AUX_UV_CCS); } } //Per-plane Aux-TT map called with per-plane base/Aux address/size for(uint32_t i = 0; i < MaxPlanes; i++) { GMM_GFX_SIZE_T SurfSize = (MaxPlanes > 1 && UpdateReq->BaseResInfo->GetArraySize() > 1) ? (UpdateReq->BaseResInfo->GetQPitchPlanar(GMM_NO_PLANE) * UpdateReq->BaseResInfo->GetRenderPitch()) : UpdateReq->BaseResInfo->GetSizeMainSurface(); GMM_GFX_SIZE_T MapSize = (i == 0) ? ((MaxPlanes > 1) ? YPlaneSize : SurfSize) : SurfSize - YPlaneSize; GMM_GFX_ADDRESS BaseSurfVA = (UpdateReq->AuxResInfo || i == 0) ? UpdateReq->BaseGpuVA : UpdateReq->BaseGpuVA + YPlaneSize; GMM_GFX_ADDRESS AuxSurfVA = (UpdateReq->AuxResInfo) ? UpdateReq->AuxSurfVA : (i > 0 ? UVAuxVA : AuxVA); //Luma plane reset LumaChroma bit ((GMM_AUXTTL1e *)&PartialL1e)->LumaChroma = (i == 0) ? 0 : 1; uint32_t ArrayEle = GFX_MAX(((MaxPlanes > 1) ? UpdateReq->BaseResInfo->GetArraySize() : 1), 1); for(uint32_t j = 0; j < ArrayEle; j++) { BaseSurfVA += ((j > 0) ? (UpdateReq->BaseResInfo->GetQPitchPlanar(GMM_PLANE_Y) * UpdateReq->BaseResInfo->GetRenderPitch()) : 0); AuxSurfVA += (UpdateReq->AuxResInfo ? ((j > 0) ? (UpdateReq->AuxResInfo->GetQPitchPlanar(GMM_PLANE_Y) * UpdateReq->BaseResInfo->GetRenderPitch()) : 0) : ((j > 0) ? UpdateReq->BaseResInfo->GetAuxQPitch() : 0)); //(Flat mapping): Remove main/aux resInfo from params Status = AuxTTObj->MapValidEntry(UpdateReq->UmdContext, BaseSurfVA, MapSize, UpdateReq->BaseResInfo, AuxSurfVA, UpdateReq->AuxResInfo, PartialL1e, 1); if(Status != GMM_SUCCESS) { GMM_ASSERTDPF(0, "Insufficient memory, free resources and try again"); EXIT_CRITICAL_SECTION return Status; } } } } } else { //Invalidate all mappings for given main surface AuxTTObj->InvalidateTable(UpdateReq->UmdContext, UpdateReq->BaseGpuVA, UpdateReq->BaseResInfo->GetSizeMainSurface(), UpdateReq->DoNotWait); } EXIT_CRITICAL_SECTION return GMM_SUCCESS; } #if defined(__linux__) && !_WIN32 ///////////////////////////////////////////////////////////////////////////////////// /// Gets size of PageTable buffer object (BOs) list /// /// @param[in] TTFlags: Flags specifying PageTable-type for which BO-count required /// @return non-zero if BO list is created. Zero otherwise. ///////////////////////////////////////////////////////////////////////////////////// int GmmLib::GmmPageTableMgr::GetNumOfPageTableBOs(uint8_t TTFlags) { int NumBO = 0; __GMM_ASSERTPTR(TTFlags & AUXTT, 0); ENTER_CRITICAL_SECTION if(AuxTTObj && AuxTTObj->GetL3Handle()) NumBO++; NumBO += NumNodePoolElements; EXIT_CRITICAL_SECTION return NumBO; } ///////////////////////////////////////////////////////////////////////////////////// /// Gets size of PageTable buffer object (BOs) list /// /// @param[in] TTFlags: Flags specifying PageTable-type for which BO-count required /// @param[in][out] BOList: pointer to memory where PageTable BO*(s) must be sent /// @return non-zero if BO list is created. Zero otherwise. ///////////////////////////////////////////////////////////////////////////////////// int GmmLib::GmmPageTableMgr::GetPageTableBOList(uint8_t TTFlags, void *BOList) { int NumBO = GetNumOfPageTableBOs(TTFlags); HANDLE * Handles = (HANDLE *)BOList; GmmLib::GMM_PAGETABLEPool *Pool; __GMM_ASSERTPTR(TTFlags & AUXTT, 0); __GMM_ASSERTPTR(BOList, 0); __GMM_ASSERTPTR(NumBO, 0); ENTER_CRITICAL_SECTION if(AuxTTObj && AuxTTObj->GetL3Handle()) Handles[0] = AuxTTObj->GetL3Handle(); Pool = pPool; for(int i = 0; i < NumNodePoolElements; i++) { if(Pool) { Handles[i + 1] = Pool->GetPoolHandle(); Pool = Pool->GetNextPool(); } } EXIT_CRITICAL_SECTION return NumBO; } #endif ///////////////////////////////////////////////////////////////////////////////////// /// Releases GmmPageTableMgr, deleting root-tables and existing page-table pools ///////////////////////////////////////////////////////////////////////////////////// GmmLib::GmmPageTableMgr::~GmmPageTableMgr() { GMM_CLIENT ClientType; GET_GMM_CLIENT_TYPE(pClientContext, ClientType); if(pPool) { ENTER_CRITICAL_SECTION pPool->__DestroyPageTablePool(&DeviceCbInt, hCsr); NumNodePoolElements = 0; EXIT_CRITICAL_SECTION } if(AuxTTObj) { DeleteCriticalSection(&PoolLock); if(AuxTTObj) { if(AuxTTObj->NullL1Table) { delete AuxTTObj->NullL1Table; } if(AuxTTObj->NullL2Table) { delete AuxTTObj->NullL2Table; } AuxTTObj->DestroyL3Table(); delete AuxTTObj; AuxTTObj = NULL; } } } ///////////////////////////////////////////////////////////////////////////////////// /// Instantiates and zeroes out GmmPageTableMgr /// /// @return GmmPageTableMgr* ///////////////////////////////////////////////////////////////////////////////////// GmmLib::GmmPageTableMgr::GmmPageTableMgr() { this->AuxTTObj = NULL; this->pPool = NULL; this->NumNodePoolElements = 0; this->pClientContext = NULL; this->hCsr = NULL; memset(&DeviceCb, 0, sizeof(GMM_DEVICE_CALLBACKS)); memset(&DeviceCbInt, 0, sizeof(GMM_DEVICE_CALLBACKS_INT)); } gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/TranslationTable/GmmUmdTranslationTable.cpp000066400000000000000000000613721466655022700304130ustar00rootroot00000000000000/*============================================================================== Copyright(c) 2019 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. Description: Contains functions of internal classes (ie PageTablePool, PageTable, Table), that support user mode page table management ============================================================================*/ #include "Internal/Common/GmmLibInc.h" #include "../TranslationTable/GmmUmdTranslationTable.h" #include "Internal/Common/Texture/GmmTextureCalc.h" #if !defined(__GMM_KMD) #if defined(__linux__) #include "Internal/Linux/GmmResourceInfoLinInt.h" #define _aligned_free(ptr) free(ptr) #endif //============================================================================= // // Function: AllocateL3Table // // Desc: Allocates (always resident SVM) memory for AUXTT\L3 Table, and updates AUXTT object // // Parameters: // pAUXTT_Obj: per-device AUX-TT object. Contains AUXTT node info // // Returns: // GMM_SUCCESS on success, // GMM_INVALIDPARAM on invalid parameter(s) // GMM_OUT_OF_MEMORY on memory allocation failure, failure to make resident //----------------------------------------------------------------------------- GMM_STATUS GmmLib::PageTable::AllocateL3Table(uint32_t L3TableSize, uint32_t L3AddrAlignment) { GMM_STATUS Status = GMM_SUCCESS; GMM_DEVICE_ALLOC Alloc = {0}; __GMM_ASSERTPTR(PageTableMgr, GMM_INVALIDPARAM); EnterCriticalSection(&TTLock); Alloc.Size = L3TableSize; Alloc.Alignment = L3AddrAlignment; Alloc.hCsr = PageTableMgr->hCsr; Status = __GmmDeviceAlloc(pClientContext, &PageTableMgr->DeviceCbInt, &Alloc); if(Status != GMM_SUCCESS) { LeaveCriticalSection(&TTLock); return Status; } TTL3.GfxAddress = GMM_GFX_ADDRESS_CANONIZE(Alloc.GfxVA); TTL3.CPUAddress = Alloc.CPUVA; TTL3.NeedRegisterUpdate = true; TTL3.L3Handle = (HANDLE)(uintptr_t)Alloc.Handle; TTL3.pGmmResInfo = (GMM_RESOURCE_INFO *)Alloc.Priv; // Invalidate L3e's for(int i = 0; i < (GMM_L3_SIZE(TTType)); i++) { //initialize L3e ie mark all entries with Null tile/invalid value ((GMM_AUXTTL3e *)TTL3.CPUAddress)[i].Value = 0; } LeaveCriticalSection(&TTLock); return Status; } //============================================================================= // // Function: __IsUnusedTRTTPoolOverLimit // // Desc: Checks if unused TRTTPools have reached residency limit and must be freed. // // Parameters: // pTRTT_Obj: per-device TT object. Contains TT node info // OverLimitSize: Size in bytes that can be freed // // Returns: // True, if unused TTPool reached max. residency limit // False, otherwise //----------------------------------------------------------------------------- bool GmmLib::GmmPageTablePool::__IsUnusedTRTTPoolOverLimit(GMM_GFX_SIZE_T *OverLimitSize) { GMM_GFX_SIZE_T UnusedTrTTPoolSize = 0; GmmLib::GMM_PAGETABLEPool *Pool = NULL; Pool = this; while(Pool) { if(Pool->NumFreeNodes == PAGETABLE_POOL_MAX_NODES) { UnusedTrTTPoolSize += PAGETABLE_POOL_SIZE; } Pool = Pool->NextPool; } *OverLimitSize = (UnusedTrTTPoolSize > PAGETABLE_POOL_MAX_UNUSED_SIZE) ? (UnusedTrTTPoolSize - PAGETABLE_POOL_MAX_UNUSED_SIZE) : 0; return (UnusedTrTTPoolSize > PAGETABLE_POOL_MAX_UNUSED_SIZE) ? true : false; } //============================================================================= // // Function: AllocateL1L2Table // // Desc: Assigns pages from AUXTTPool for L1/L2Table for translation of given TRVA // // Parameters: // pAUXTT_Obj: per-device AUX-TT object. Contains AUXTT node info // TileAddr: Tiled Resource Virtual address // // Returns: // L2Table/L1Table Address //----------------------------------------------------------------------------- void GmmLib::PageTable::AllocateL1L2Table(GMM_GFX_ADDRESS TileAddr, GMM_GFX_ADDRESS *L1TableAdr, GMM_GFX_ADDRESS *L2TableAdr) { GMM_GFX_ADDRESS L3TableAdr = GMM_NO_TABLE; uint32_t L3eIdx = static_cast(GMM_L3_ENTRY_IDX(TTType, TileAddr)); uint32_t L2eIdx = static_cast(GMM_L2_ENTRY_IDX(TTType, TileAddr)); GmmLib::LastLevelTable *pL1Tbl = NULL; __GMM_ASSERTPTR(pClientContext, VOIDRETURN); // void return *L2TableAdr = GMM_NO_TABLE; *L1TableAdr = GMM_NO_TABLE; if(TTL3.L3Handle) { L3TableAdr = TTL3.GfxAddress; } else { //Should never hit -- L3Table is allocated during device creation __GMM_ASSERT(false); } if(pTTL2[L3eIdx].GetPool()) { GmmLib::GMM_PAGETABLEPool *PoolElem = NULL; PoolElem = pTTL2[L3eIdx].GetPool(); *L2TableAdr = (PoolElem != NULL) ? PoolElem->GetGfxAddress() + (PAGE_SIZE * pTTL2[L3eIdx].GetNodeIdx()) : GMM_NO_TABLE; } else { uint32_t PoolNodeIdx = PAGETABLE_POOL_MAX_NODES; GmmLib::GMM_PAGETABLEPool *PoolElem = NULL; POOL_TYPE PoolType = POOL_TYPE_AUXTTL2; PoolElem = PageTableMgr->__GetFreePoolNode(&PoolNodeIdx, PoolType); if(PoolElem) { pTTL2[L3eIdx] = MidLevelTable(PoolElem, PoolNodeIdx, PoolElem->GetNodeBBInfoAtIndex(PoolNodeIdx)); *L2TableAdr = PoolElem->GetGfxAddress() + PAGE_SIZE * PoolNodeIdx; //PoolNodeIdx must be multiple of 8 (Aux L2) and multiple of 2 (Aux L1) ASSIGN_POOLNODE(PoolElem, PoolNodeIdx, NodesPerTable) } } pL1Tbl = pTTL2[L3eIdx].GetL1Table(L2eIdx); if(pL1Tbl) { GmmLib::GMM_PAGETABLEPool *PoolElem = NULL; PoolElem = pL1Tbl->GetPool(); *L1TableAdr = (PoolElem != NULL) ? PoolElem->GetGfxAddress() + (PAGE_SIZE * pL1Tbl->GetNodeIdx()) : GMM_NO_TABLE; } else { //Allocate L1 Table uint32_t PoolNodeIdx = PAGETABLE_POOL_MAX_NODES; GmmLib::GMM_PAGETABLEPool *PoolElem = NULL; POOL_TYPE PoolType = POOL_TYPE_AUXTTL1; PoolElem = PageTableMgr->__GetFreePoolNode(&PoolNodeIdx, PoolType); //Recognize if Aux-L1 being allocated if(PoolElem) { pL1Tbl = new GmmLib::LastLevelTable(PoolElem, PoolNodeIdx, GMM_L1_SIZE_DWORD(TTType, GetGmmLibContext()), L2eIdx); // use TR vs Aux L1_Size_DWORD if(pL1Tbl) { *L1TableAdr = PoolElem->GetGfxAddress() + PAGE_SIZE * PoolNodeIdx; //PoolNodeIdx should reflect 1 node per Tr-table and 2 nodes per AUX L1 TABLE if(PoolNodeIdx != PAGETABLE_POOL_MAX_NODES) { uint32_t PerTableNodes = (TTType == AUXTT) ? AUX_L1TABLE_SIZE_IN_POOLNODES_2(GetGmmLibContext()) : 1; ASSIGN_POOLNODE(PoolElem, PoolNodeIdx, PerTableNodes) } pTTL2[L3eIdx].InsertInList(pL1Tbl); } } } } //============================================================================= // // Function: AllocateDummyTables // // Desc: Assigns pages from AUXTTPool for Dummy L1/L2Table // // Parameters: // L2Table - Ptr to initiatize dummy L2Table // L1Table - Ptr to initiatize dummy L1Table // // Returns: // L2Table/L1Tables //----------------------------------------------------------------------------- void GmmLib::PageTable::AllocateDummyTables(GmmLib::Table **L2Table, GmmLib::Table **L1Table) { GMM_GFX_ADDRESS L3TableAdr = GMM_NO_TABLE; GmmLib::LastLevelTable *pL1Tbl = NULL; __GMM_ASSERTPTR(pClientContext, VOIDRETURN); if(TTL3.L3Handle) { L3TableAdr = TTL3.GfxAddress; } else { //Should never hit -- L3Table is allocated during device creation __GMM_ASSERT(false); } //Allocate dummy L2Table { uint32_t PoolNodeIdx = PAGETABLE_POOL_MAX_NODES; GmmLib::GMM_PAGETABLEPool *PoolElem = NULL; POOL_TYPE PoolType = POOL_TYPE_AUXTTL2; PoolElem = PageTableMgr->__GetFreePoolNode(&PoolNodeIdx, PoolType); if(PoolElem) { *L2Table = new GmmLib::MidLevelTable(PoolElem, PoolNodeIdx, PoolElem->GetNodeBBInfoAtIndex(PoolNodeIdx)); ASSIGN_POOLNODE(PoolElem, PoolNodeIdx, NodesPerTable) } } //Allocate dummy L1Table { uint32_t PoolNodeIdx = PAGETABLE_POOL_MAX_NODES; GmmLib::GMM_PAGETABLEPool *PoolElem = NULL; POOL_TYPE PoolType = POOL_TYPE_AUXTTL1; PoolElem = PageTableMgr->__GetFreePoolNode(&PoolNodeIdx, PoolType); //Recognize if Aux-L1 being allocated if(PoolElem) { *L1Table = new GmmLib::LastLevelTable(PoolElem, PoolNodeIdx, GMM_L1_SIZE_DWORD(TTType, GetGmmLibContext()), 0); // use TR vs Aux L1_Size_DWORD if(*L1Table) { if(PoolNodeIdx != PAGETABLE_POOL_MAX_NODES) { uint32_t PerTableNodes = (TTType == AUXTT) ? AUX_L1TABLE_SIZE_IN_POOLNODES_2(GetGmmLibContext()) : 1; ASSIGN_POOLNODE(PoolElem, PoolNodeIdx, PerTableNodes) } } } } } //============================================================================= // // Function: GetL1L2TableAddr // // Desc: For given tile address, returns L1/L2 Table address if the table exists // // Parameters: // pAUXTT_Obj: per-device AUX-TT object. Contains AXUTT node info // TileAddr: Tiled Resource Virtual address // // Returns: // L2Table/L1Table Address //----------------------------------------------------------------------------- void GmmLib::PageTable::GetL1L2TableAddr(GMM_GFX_ADDRESS TileAddr, GMM_GFX_ADDRESS *L1TableAdr, GMM_GFX_ADDRESS *L2TableAdr) { GMM_GFX_SIZE_T L3eIdx, L2eIdx, L1eIdx; GMM_GFX_ADDRESS L3TableAdr = GMM_NO_TABLE; *L2TableAdr = GMM_NO_TABLE; *L1TableAdr = GMM_NO_TABLE; __GMM_ASSERTPTR(pClientContext, VOIDRETURN); L3eIdx = GMM_L3_ENTRY_IDX(TTType, TileAddr); L2eIdx = GMM_L2_ENTRY_IDX(TTType, TileAddr); L1eIdx = GMM_L1_ENTRY_IDX(TTType, TileAddr, GetGmmLibContext()); __GMM_ASSERT(TTL3.L3Handle); L3TableAdr = TTL3.GfxAddress; if(pTTL2[L3eIdx].GetPool()) { GmmLib::GMM_PAGETABLEPool *Pool = NULL; GmmLib::LastLevelTable * pL1Tbl = NULL; Pool = pTTL2[L3eIdx].GetPool(); if(Pool) { __GMM_ASSERT(Pool->GetNumFreeNode() != PAGETABLE_POOL_MAX_NODES); __GMM_ASSERT(pTTL2[L3eIdx].GetNodeIdx() < PAGETABLE_POOL_MAX_NODES); __GMM_ASSERT(Pool->GetNodeUsageAtIndex(pTTL2[L3eIdx].GetNodeIdx() / (32 * NodesPerTable)) != 0); *L2TableAdr = Pool->GetGfxAddress() + PAGE_SIZE * (pTTL2[L3eIdx].GetNodeIdx()); } pL1Tbl = pTTL2[L3eIdx].GetL1Table(L2eIdx); if(pL1Tbl && pL1Tbl->GetPool()) { Pool = NULL; Pool = pL1Tbl->GetPool(); if(Pool) { uint32_t PerTableNodes = (TTType == AUXTT) ? AUX_L1TABLE_SIZE_IN_POOLNODES_2(GetGmmLibContext()) : 1; __GMM_ASSERT(Pool->GetNumFreeNode() != PAGETABLE_POOL_MAX_NODES); __GMM_ASSERT(pL1Tbl->GetNodeIdx() < PAGETABLE_POOL_MAX_NODES); __GMM_ASSERT(Pool->GetNodeUsageAtIndex(pL1Tbl->GetNodeIdx() / (32 * PerTableNodes)) != 0); *L1TableAdr = Pool->GetGfxAddress() + PAGE_SIZE * (pL1Tbl->GetNodeIdx()); } } } } //============================================================================= // // Function: GetMappingType // // Desc: For given gfx address and size, returns MappingType (null/non-null or // Valid/Invalid) of GfxVA and first gfx address have reverse mapping // /// @param[in] GfxVA: Gfx Address whose mapping type is being queried /// @param[in] Size: Size of interested Gfx address range /// @param[out] LastAddr : 1st Gfx Address having reverse mapping type // /// @return 1/0 : for non-null/valid vs null/invalid mapping //----------------------------------------------------------------------------- uint8_t GmmLib::PageTable::GetMappingType(GMM_GFX_ADDRESS GfxVA, GMM_GFX_SIZE_T Size, GMM_GFX_ADDRESS &LastAddr) { GMM_GFX_SIZE_T L3eIdx, L2eIdx, L1eIdx, L1EntrySize; uint32_t L1Size, L2Size; uint8_t MapType = 0; //true for non-null, false for null mapped bool bFoundLastVA = false, bTerminate = false; GMM_GFX_ADDRESS TileAddr = GfxVA; L3eIdx = GMM_L3_ENTRY_IDX(TTType, GfxVA); L2eIdx = GMM_L2_ENTRY_IDX(TTType, GfxVA); L1eIdx = GMM_L1_ENTRY_IDX(TTType, GfxVA, GetGmmLibContext()); L1EntrySize = WA16K(GetGmmLibContext()) ? GMM_KBYTE(16) : WA64K(GetGmmLibContext()) ? GMM_KBYTE(64) : GMM_MBYTE(1); EnterCriticalSection(&TTLock); __GMM_ASSERT(TTL3.L3Handle); #define GET_NEXT_L1TABLE(L1eIdx, L2eIdx, L3eIdx) \ { \ L1eIdx = 0; \ L2eIdx++; \ if(L2eIdx == (GMM_L2_SIZE(TTType))) \ { \ L2eIdx = 0; \ L3eIdx++; \ if(L3eIdx == (GMM_L3_SIZE(TTType))) \ { \ bTerminate = true; \ } \ } \ } #define GET_NEXT_L2TABLE(L1eIdx, L2eIdx, L3eIdx) \ { \ L1eIdx = L2eIdx = 0; \ L3eIdx++; \ if(L3eIdx == (GMM_L3_SIZE(TTType))) \ { \ bTerminate = true; \ } \ } while(!(bFoundLastVA || bTerminate) && (TileAddr < GfxVA + Size)) { if(pTTL2[L3eIdx].GetPool()) { GmmLib::LastLevelTable *pL1Tbl = NULL; pL1Tbl = pTTL2[L3eIdx].GetL1Table(L2eIdx); if(pL1Tbl && pL1Tbl->GetPool()) { uint32_t LastBit = 0; uint32_t i = static_cast(L1eIdx) / 32; while(!bFoundLastVA && i < (uint32_t)(GMM_L1_SIZE_DWORD(TTType, GetGmmLibContext()))) { uint32_t UsageDW = pL1Tbl->GetUsedEntries()[i++]; uint32_t BitNum = 31; if(GfxVA == TileAddr) { BitNum = L1eIdx % 32; MapType = ((UsageDW & __BIT(BitNum)) ? 0x1 : 0x0); //true for non-null, false for null mapped UsageDW = (!MapType) ? UsageDW : ~UsageDW; UsageDW = ((uint64_t)UsageDW >> (BitNum + 1)) << (BitNum + 1); // clear lsb <= BitNum } else { UsageDW = (!MapType) ? UsageDW : ~UsageDW; } if(_BitScanForward((uint32_t *)&LastBit, UsageDW)) // Gets lsb > BitNum, having reverse mapType { bFoundLastVA = true; uint32_t NumTiles = (GfxVA == TileAddr) ? (LastBit - BitNum) : LastBit; LastAddr = TileAddr + NumTiles * L1EntrySize; } else { uint32_t NumTiles = (GfxVA == TileAddr) ? (32 - BitNum) : 32; TileAddr += NumTiles * L1EntrySize; } } if(!bFoundLastVA) { GET_NEXT_L1TABLE(L1eIdx, L2eIdx, L3eIdx); } } else //L2Entry is NULL { if(MapType) //First hit null-map { LastAddr = TileAddr; bFoundLastVA = true; } else { GMM_GFX_SIZE_T NumTiles = GMM_L1_USABLESIZE(TTType, GetGmmLibContext()); if(GfxVA == TileAddr) { MapType = false; NumTiles -= L1eIdx; } TileAddr += NumTiles * L1EntrySize; GET_NEXT_L1TABLE(L1eIdx, L2eIdx, L3eIdx) } } } else //L3entry is NULL { if(MapType) //First hit null-map { LastAddr = TileAddr; bFoundLastVA = true; } else { GMM_GFX_SIZE_T NumTiles = 0; if(GfxVA == TileAddr) { MapType = false; L1Size = GMM_L1_USABLESIZE(TTType, GetGmmLibContext()) - L1eIdx; L2Size = GMM_L2_SIZE(TTType) - L2eIdx; NumTiles = ((uint64_t)L1Size * L2Size); } else { L1Size = GMM_L1_USABLESIZE(TTType, GetGmmLibContext()); L2Size = GMM_L2_SIZE(TTType); NumTiles = ((uint64_t)L1Size * L2Size); } TileAddr += NumTiles * L1EntrySize; GET_NEXT_L2TABLE(L1eIdx, L2eIdx, L3eIdx) } } } if(!bFoundLastVA) { LastAddr = TileAddr; } LeaveCriticalSection(&TTLock); return MapType; } //============================================================================= // // Function: TrackTableUsage // // Desc: For given tile address, updates Table Usage.If Table has all Nullmappings // then its pool node can be unassigned // // Parameters: // Type: Translation Table type (Aux) // IsL1: Is called for L1table or L2 Table // TileAddr: Tiled Resource Virtual address // NullMapped: true if given tiled adr was null mapped, otherwise false // // Returns: // true, if Table for given tile adr is all null mapped // false,if Table does not exist or has non-null mapping //----------------------------------------------------------------------------- bool GmmLib::Table::TrackTableUsage(TT_TYPE Type, bool IsL1, GMM_GFX_ADDRESS TileAdr, bool NullMapped, GMM_LIB_CONTEXT *pGmmLibContext ) { uint32_t EntryIdx; uint32_t ElemNum = 0, BitNum = 0; EntryIdx = IsL1 ? static_cast(GMM_L1_ENTRY_IDX(Type, TileAdr, pGmmLibContext)) : static_cast(GMM_L2_ENTRY_IDX(Type, TileAdr)); ElemNum = EntryIdx / (sizeof(UsedEntries[0]) * 8); BitNum = EntryIdx % (sizeof(UsedEntries[0]) * 8); if(NullMapped) { UsedEntries[ElemNum] &= ~(1 << BitNum); } else { UsedEntries[ElemNum] |= (1 << BitNum); } if(NullMapped) { int TableDWSize = IsL1 ? static_cast(GMM_L1_SIZE_DWORD(Type, pGmmLibContext)) : static_cast(GMM_L2_SIZE_DWORD(Type)); for(int i = 0; i < TableDWSize; i++) { if(UsedEntries[i]) { return false; } } } return NullMapped ? true : false; } //============================================================================= // // Function: __IsTableNullMapped // // Desc: For given tile address, checks if given Table has all Nullmappings // then its pool node can be unassigned // // Parameters: // Type: Translation Table type (TR or Aux) // IsL1: Is called for L1table or L2 Table // TileAddr: Tiled Resource Virtual address // // Returns: // true, if Table for given tile adr is all null mapped // false,if Table has non-null mapping //----------------------------------------------------------------------------- bool GmmLib::Table::IsTableNullMapped(TT_TYPE Type, bool IsL1, GMM_GFX_ADDRESS TileAdr, GMM_LIB_CONTEXT *pGmmLibContext) { GMM_UNREFERENCED_PARAMETER(TileAdr); int TableDWSize = IsL1 ? static_cast(GMM_L1_SIZE_DWORD(Type, pGmmLibContext)) : static_cast(GMM_L2_SIZE_DWORD(Type)); for(int i = 0; i < TableDWSize; i++) { if(UsedEntries[i]) { return false; } } return true; } //============================================================================= // // Function: __UpdatePoolFence // // Desc: Updates AUXTTPool's or Table's BBFenceObj/value with current BB fence // // Parameters: // pAUXTT_Obj: per-device AUX-TT object. Contains AUXTT node info // Table: L1/L2 table pointer // L1Table: true for L1 Table, else false // ClearNode: if true, Fence info is cleared for table // false, Fence info is updated for table and pool //----------------------------------------------------------------------------- void GmmLib::Table::UpdatePoolFence(GMM_UMD_SYNCCONTEXT *UmdContext, bool ClearNode) { if(!ClearNode) { //update both node and pool with current fence/handle PoolElem->GetPoolBBInfo().BBQueueHandle = BBInfo.BBQueueHandle = UmdContext->BBFenceObj; PoolElem->GetPoolBBInfo().BBFence = BBInfo.BBFence = UmdContext->BBLastFence + 1; //Save incremented fence value, since DX does it during submission } else { //Clear node fence/handle BBInfo.BBQueueHandle = 0; BBInfo.BBFence = 0; } } ///////////////////////////////////////////////////////////////////////////////////// /// Releases all PageTable Pool(s) existing in Linked List /// /// @param[in] DeviceCallbacks pointer to device callbacks structure /// @return GMM_STATUS ///////////////////////////////////////////////////////////////////////////////////// GMM_STATUS GmmLib::GmmPageTablePool::__DestroyPageTablePool(void *DeviceCallbacks, HANDLE hCsr) { GMM_STATUS Status = GMM_SUCCESS; GMM_DEVICE_CALLBACKS_INT *DeviceCb = static_cast(DeviceCallbacks); GMM_PAGETABLEPool *Node = this, *Next = NULL; GMM_CLIENT ClientType; GMM_DEVICE_DEALLOC Dealloc = {0}; //Evict/Free gpu Va is implictly done by OS when de-allocating while(Node) { Next = Node->NextPool; GET_GMM_CLIENT_TYPE(Node->pClientContext, ClientType); Dealloc.Handle = Node->PoolHandle; Dealloc.GfxVA = Node->PoolGfxAddress; Dealloc.Priv = Node->pGmmResInfo; Dealloc.hCsr = hCsr; Status = __GmmDeviceDealloc(ClientType, DeviceCb, &Dealloc, Node->pClientContext); Node->PoolHandle = NULL; Node->PoolGfxAddress = 0; delete Node; Node = Next; } return Status; } ///////////////////////////////////////////////////////////////////////////////////// /// Releases memory allocated to PageTable's Root-table /// /// @return GMM_STATUS ///////////////////////////////////////////////////////////////////////////////////// GMM_STATUS GmmLib::PageTable::DestroyL3Table() { GMM_STATUS Status = GMM_SUCCESS; uint8_t hr = GMM_SUCCESS; GMM_CLIENT ClientType; GMM_DEVICE_DEALLOC Dealloc = {0}; GET_GMM_CLIENT_TYPE(pClientContext, ClientType); EnterCriticalSection(&TTLock); if(TTL3.L3Handle) { Dealloc.Handle = TTL3.L3Handle; Dealloc.GfxVA = TTL3.GfxAddress; Dealloc.Priv = TTL3.pGmmResInfo; Dealloc.hCsr = PageTableMgr->hCsr; Status = __GmmDeviceDealloc(ClientType, &PageTableMgr->DeviceCbInt, &Dealloc, pClientContext); TTL3.L3Handle = NULL; TTL3.GfxAddress = 0; TTL3.CPUAddress = 0; } LeaveCriticalSection(&TTLock); return Status; } #endif //!__GMM_KMD gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/TranslationTable/GmmUmdTranslationTable.h000066400000000000000000000554431466655022700300620ustar00rootroot00000000000000/*============================================================================== Copyright(c) 2019 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. Description: This file contains the class definitions for GmmPageTablePool PageTable, and low-level Tables for user-mode PageTable management, that is common for both Linux and Windows. ======================= end_copyright_notice ==================================*/ #pragma once #include "External/Common/GmmPageTableMgr.h" #ifdef __linux__ #include #include // Internal Linux version of MSDK APIs. static inline void InitializeCriticalSection(pthread_mutex_t *mutex) { pthread_mutexattr_t Attr; pthread_mutexattr_init(&Attr); pthread_mutexattr_settype(&Attr, PTHREAD_MUTEX_RECURSIVE); pthread_mutex_init(mutex, &Attr); } static inline void DeleteCriticalSection(pthread_mutex_t *mutex) { pthread_mutex_destroy(mutex); } static inline void EnterCriticalSection(pthread_mutex_t *mutex) { pthread_mutex_lock(mutex); } static inline void LeaveCriticalSection(pthread_mutex_t *mutex) { pthread_mutex_unlock(mutex); } #ifndef _BitScanForwardDefined static inline int _BitScanForward(uint32_t *index, uint32_t mask) { int i; #ifdef __ANDROID__ i = ffs(mask); #else i = ffsl(mask); #endif if(i > 0) { *index = (uint32_t)(i - 1); return i; } return 0; } #endif #endif #define GMM_L1_USABLESIZE(TTType, pGmmLibContext) (GMM_AUX_L1_USABLESIZE(pGmmLibContext)) #define GMM_L1_SIZE(TTType, pGmmLibContext) (GMM_AUX_L1_SIZE(pGmmLibContext)) #define GMM_L1_SIZE_DWORD(TTType, pGmmLibContext) (GMM_AUX_L1_SIZE_DWORD(pGmmLibContext)) #define GMM_L2_SIZE(TTType) (GMM_AUX_L2_SIZE) #define GMM_L2_SIZE_DWORD(TTType) (GMM_AUX_L2_SIZE_DWORD) #define GMM_L3_SIZE(TTType) (GMM_AUX_L3_SIZE) #define GMM_L1_ENTRY_IDX(TTType, GfxAddress, pGmmLibContext) (GMM_AUX_L1_ENTRY_IDX((GfxAddress), (pGmmLibContext))) #define GMM_L2_ENTRY_IDX(TTType, GfxAddress) (GMM_AUX_L2_ENTRY_IDX(GfxAddress)) #define GMM_L3_ENTRY_IDX(TTType, GfxAddress) (GMM_AUX_L3_ENTRY_IDX(GfxAddress)) #ifdef GMM_ULT #define GMM_L1_ENTRY_IDX_EXPORTED(TTType, GfxAddress, WA64KEx) GMM_AUX_L1_ENTRY_IDX_EXPORTED((GfxAddress), WA64KEx) #define GMM_L1_ENTRY_IDX_EXPORTED_2(TTType, GfxAddress, WA64KEx, WA16KEx) (GMM_AUX_L1_ENTRY_IDX_EXPORTED_2((GfxAddress), WA64KEx, WA16KEx)) #endif #ifdef __cplusplus #include "External/Common/GmmMemAllocator.hpp" //HW provides single-set of TR/Aux-TT registers for non-privileged programming //Engine-specific offsets are HW-updated with programmed values. #define GET_L3ADROFFSET(TRTT, L3AdrOffset, pGmmLibContext) \ L3AdrOffset = 0x4200; #define ASSIGN_POOLNODE(Pool, NodeIdx, PerTableNodes) { \ (Pool)->GetNodeUsageAtIndex((NodeIdx) / (32 *(PerTableNodes))) |= __BIT(((NodeIdx) / (PerTableNodes)) % 32); \ (Pool)->GetNodeBBInfoAtIndex(NodeIdx) = SyncInfo(); \ (Pool)->GetNumFreeNode() -= (PerTableNodes); \ } #define DEASSIGN_POOLNODE(PageTableMgr, UmdContext, Pool, NodeIdx, PerTableNodes) { \ (Pool)->GetNodeUsageAtIndex((NodeIdx) / (32 * (PerTableNodes))) &= ~__BIT(((NodeIdx) / (PerTableNodes)) % 32 ); \ (Pool)->GetNumFreeNode() += (PerTableNodes); \ if((Pool)->GetNumFreeNode() == PAGETABLE_POOL_MAX_NODES) { \ PageTableMgr->__ReleaseUnusedPool((UmdContext)); \ } \ } namespace GmmLib { #define PAGETABLE_POOL_MAX_NODES 512 //Max. number of L2/L1 tables pool contains #define PAGETABLE_POOL_SIZE_IN_DWORD PAGETABLE_POOL_MAX_NODES / 32 #define PAGETABLE_POOL_SIZE PAGETABLE_POOL_MAX_NODES * PAGE_SIZE //Pool for L2/L1 table allocation #define AUX_L2TABLE_SIZE_IN_POOLNODES 8 //Aux L2 is 32KB #define AUX_L1TABLE_SIZE_IN_POOLNODES 2 //Aux L1 is 8KB #define AUX_L1TABLE_SIZE_IN_POOLNODES_2(pGmmLibContext) (pGmmLibContext ? ((WA64K(pGmmLibContext) || WA16K(pGmmLibContext)) ? 2 : 1) : 2) //Aux L1 is 8KB / 4K (MTL) #define PAGETABLE_POOL_MAX_UNUSED_SIZE GMM_MBYTE(16) //Max. size of unused pool, driver keeps resident ////////////////////////////////////////////////////////////////////////////////////////////// /// Contains functions and members for GmmPageTablePool. /// PageTablePool is a Linked-list, provides common location for both Aux TT and TR-TT pages /// Separate NodePool (linked-list element) kept for each PoolType, for cleaner management in /// per-table size ///////////////////////////////////////////////////////////////////////////////////////////// class GmmPageTablePool { private: //PageTablePool allocation descriptor GMM_RESOURCE_INFO* pGmmResInfo; HANDLE PoolHandle; GMM_GFX_ADDRESS PoolGfxAddress; GMM_GFX_ADDRESS CPUAddress; //LMEM-cpuvisible adr POOL_TYPE PoolType; //Separate Node-pools for TR-L2, TR-L1, Aux-L2, Aux-L1 usages- //PageTablePool usage descriptors int NumFreeNodes; //has value {0 to Pool_Max_nodes} uint32_t* NodeUsage; //destined node state (updated during node assignment and removed based on destined state of L1/L2 Table //that used the pool node) //Aux-Pool node-usage tracked at every eighth/second node(for L2 vs L1) //ie 1b per node for TR-table, 1b per 8-nodes for Aux-L2table, 1b per 2-nodes for AuxL1-table //array size= POOL_SIZE_IN_DWORD for TR, =POOL_SIZE_IN_DWORD/8 for AuxL2, POOL_SIZE_IN_DWORD/2 for AuxL1 SyncInfo* NodeBBInfo; //BB info for pending Gpu usage of each pool node //array of size MaxPoolNodes for TR, =MaxPoolNodes / 8 for Aux, MaxPoolNodes / 2 for AuxL1 SyncInfo PoolBBInfo; //BB info for Gpu usage of the Pool (most recent of pool node BB info) GmmPageTablePool* NextPool; //Next node-Pool in the LinkedList GmmClientContext *pClientContext; ///< ClientContext of the client creating this Object public: GmmPageTablePool() : pGmmResInfo(NULL), PoolHandle(), PoolGfxAddress(0x0), CPUAddress(0x0), PoolType(POOL_TYPE_TRTTL1), NumFreeNodes(PAGETABLE_POOL_MAX_NODES), NodeUsage(NULL), NodeBBInfo(NULL), PoolBBInfo(), NextPool(NULL), pClientContext(NULL) { } GmmPageTablePool(HANDLE hAlloc, GMM_RESOURCE_INFO* pGmmRes, GMM_GFX_ADDRESS SysMem, POOL_TYPE Type) : GmmPageTablePool() { int DwordPoolSize; GMM_LIB_CONTEXT *pGmmLibContext; PoolHandle = hAlloc; pGmmResInfo = pGmmRes; PoolGfxAddress = SysMem; CPUAddress = PoolGfxAddress; NextPool = NULL; NumFreeNodes = PAGETABLE_POOL_MAX_NODES; PoolType = Type; if(pGmmResInfo) { pClientContext = pGmmResInfo->GetGmmClientContext(); } pGmmLibContext = pClientContext ? pClientContext->GetLibContext() : NULL; DwordPoolSize = (Type == POOL_TYPE_AUXTTL1) ? PAGETABLE_POOL_SIZE_IN_DWORD / AUX_L1TABLE_SIZE_IN_POOLNODES_2(pGmmLibContext) : (Type == POOL_TYPE_AUXTTL2) ? PAGETABLE_POOL_SIZE_IN_DWORD / AUX_L2TABLE_SIZE_IN_POOLNODES : PAGETABLE_POOL_SIZE_IN_DWORD; NodeUsage = new uint32_t[DwordPoolSize](); NodeBBInfo = new SyncInfo[DwordPoolSize * 32](); } GmmPageTablePool(HANDLE hAlloc, GMM_RESOURCE_INFO* pGmmRes, GMM_GFX_ADDRESS GfxAdr, GMM_GFX_ADDRESS CPUAdr, POOL_TYPE Type) : GmmPageTablePool(hAlloc, pGmmRes, GfxAdr, Type) { CPUAddress = (CPUAdr != GfxAdr) ? CPUAdr : GfxAdr; } ~GmmPageTablePool() { delete[] NodeUsage; delete[] NodeBBInfo; } GmmPageTablePool* InsertInList(GmmPageTablePool* NewNode) { GmmPageTablePool *Node = this; while (Node->NextPool) { Node = Node->NextPool; } Node->NextPool = NewNode; return Node->NextPool; } GmmPageTablePool* InsertInListAtBegin(GmmPageTablePool* NewNode) { GmmPageTablePool *Node = this; NewNode->NextPool = Node; return NewNode; } GmmPageTablePool* &GetNextPool() { return NextPool; } HANDLE& GetPoolHandle() { return PoolHandle; } POOL_TYPE& GetPoolType() { return PoolType; } int& GetNumFreeNode() { return NumFreeNodes; } SyncInfo& GetPoolBBInfo() { return PoolBBInfo; } uint32_t& GetNodeUsageAtIndex(int j) { return NodeUsage[j]; } SyncInfo& GetNodeBBInfoAtIndex(int j) { GMM_LIB_CONTEXT *pGmmLibContext = pClientContext ? pClientContext->GetLibContext() : NULL; int BBInfoNodeIdx = (PoolType == POOL_TYPE_AUXTTL1) ? j / AUX_L1TABLE_SIZE_IN_POOLNODES_2(pGmmLibContext) : (PoolType == POOL_TYPE_AUXTTL2) ? j / AUX_L2TABLE_SIZE_IN_POOLNODES : j; return NodeBBInfo[BBInfoNodeIdx]; } GMM_GFX_ADDRESS GetGfxAddress() { return PoolGfxAddress; } GMM_GFX_ADDRESS GetCPUAddress() { return CPUAddress; } GMM_RESOURCE_INFO* &GetGmmResInfo() { return pGmmResInfo; } bool IsPoolInUse(SyncInfo BBInfo) { if (NumFreeNodes < PAGETABLE_POOL_MAX_NODES || (PoolBBInfo.BBQueueHandle == BBInfo.BBQueueHandle && PoolBBInfo.BBFence == BBInfo.BBFence + 1)) //Pool will be used by next BB submission, freeing it will cause page fault { return true; } return false; } bool __IsUnusedTRTTPoolOverLimit(GMM_GFX_SIZE_T * OverLimitSize); void ClearBBReference(void * BBQHandle); GMM_STATUS __DestroyPageTablePool(void * DeviceCallbacks,HANDLE hCsr); }; ////////////////////////////////////////////////////////////////////////////////////////////// /// Contains functions and members for Table. /// Table defines basic building block for tables at different page-table levels ///////////////////////////////////////////////////////////////////////////////////////////// class Table { protected: GMM_PAGETABLEPool *PoolElem; //L2 Pool ptr different for L2Tables when Pool_nodes <512 int PoolNodeIdx; //pool node idx used for L2 Table SyncInfo BBInfo; //BB Handle/fence using Table uint32_t * UsedEntries; //Tracks which L1/L2 entries are being used //array size GMM_L1_SIZE_DWORD(TT-type) for LastLevelTable, MidLeveltable(??) //array of 1024/32=32 DWs for TR-table, 4096/32 =512 for Aux-Table public: Table() : PoolElem(NULL), PoolNodeIdx(), BBInfo(), UsedEntries(NULL) { } int& GetNodeIdx() { return PoolNodeIdx; } GmmPageTablePool* &GetPool() { return PoolElem; } GMM_GFX_ADDRESS GetCPUAddress() { return (PoolElem->GetCPUAddress() + (PoolNodeIdx * PAGE_SIZE)); } SyncInfo& GetBBInfo() { return BBInfo; } uint32_t* &GetUsedEntries() { return UsedEntries; } bool TrackTableUsage(TT_TYPE Type, bool IsL1, GMM_GFX_ADDRESS TileAdr, bool NullMapped,GMM_LIB_CONTEXT* pGmmLibContext); bool IsTableNullMapped(TT_TYPE Type, bool IsL1, GMM_GFX_ADDRESS TileAdr,GMM_LIB_CONTEXT *pGmmLibContext); void UpdatePoolFence(GMM_UMD_SYNCCONTEXT * UmdContext, bool ClearNode); }; ////////////////////////////////////////////////////////////////////////////////////////////// /// Contains functions and members for LastLevelTable. /// LastLevelTable defines leaf level tables in multi-level pageTable structure ///////////////////////////////////////////////////////////////////////////////////////////// class LastLevelTable : public Table { private: uint32_t L2eIdx; LastLevelTable *pNext; public: LastLevelTable() : Table(), L2eIdx() //Pass in Aux vs TR table's GMM_L2_SIZE and initialize L2eIdx? { pNext = NULL; } LastLevelTable(GMM_PAGETABLEPool *Elem, int NodeIdx, int DwordL1e, int L2eIndex) : LastLevelTable() { PoolElem = Elem; PoolNodeIdx = NodeIdx; BBInfo = Elem->GetNodeBBInfoAtIndex(NodeIdx); L2eIdx = L2eIndex; pNext = NULL; UsedEntries = new uint32_t[DwordL1e](); } ~LastLevelTable() { delete[] UsedEntries; } int GetL2eIdx() { return L2eIdx; } LastLevelTable* &Next() { return pNext; } }; ////////////////////////////////////////////////////////////////////////////////////////////// /// Contains functions and members for MidLevelTable. /// MidLevelTable defines secondary level tables in multi-level pageTable structure ///////////////////////////////////////////////////////////////////////////////////////////// class MidLevelTable : public Table { private: LastLevelTable *pTTL1; //linked list of L1 tables public: MidLevelTable() :Table() { pTTL1 = NULL; } MidLevelTable(GMM_PAGETABLEPool *Pool, int NodeIdx, SyncInfo Info) : MidLevelTable() { PoolElem = Pool; BBInfo = Info; PoolNodeIdx = NodeIdx; } ~MidLevelTable() { if (pTTL1) { LastLevelTable* item = pTTL1; while (item) { LastLevelTable* nextItem = item->Next(); delete item; item = nextItem; } pTTL1 = NULL; } } LastLevelTable* GetL1Table(GMM_GFX_SIZE_T L2eIdx, LastLevelTable** Prev = NULL) { LastLevelTable* pL1Tbl = pTTL1; LastLevelTable* PrevL1Tbl = NULL; while (pL1Tbl) { if (pL1Tbl->GetL2eIdx() == L2eIdx) { break; } PrevL1Tbl = pL1Tbl; pL1Tbl = pL1Tbl->Next(); } //if requested, save previous node in linked-list if (Prev) { *Prev = PrevL1Tbl; } return pL1Tbl; } void InsertInList(LastLevelTable* pL1Tbl) { LastLevelTable* Prev = pTTL1; //Insert at end while (Prev && Prev->Next()) { Prev = Prev->Next(); } if (Prev) { Prev->Next() = pL1Tbl; } else { pTTL1 = pL1Tbl; } } void DeleteFromList(LastLevelTable* pL1Tbl, LastLevelTable* PrevL1Tbl) { //Save next L1Table in list, before deleting current one if (pL1Tbl) { if (PrevL1Tbl) { PrevL1Tbl->Next() = pL1Tbl->Next(); } else { pTTL1 = pL1Tbl->Next(); } delete pL1Tbl; } } }; ///////////////////////////////////////////////////// /// Contains functions and members for PageTable. /// PageTable defines multi-level pageTable ///////////////////////////////////////////////////// class PageTable : public GmmMemAllocator { protected: const TT_TYPE TTType; //PageTable is AuxTT const int NodesPerTable; //Aux L2/L3 has 32KB size, Aux L1 has 4KB -can't use as selector for PageTable is AuxTT // 1 node for TR-table, 8 nodes for Aux-Table L2, 2 nodes for Aux-table L1 //Root Table structure struct RootTable { GMM_RESOURCE_INFO* pGmmResInfo; HANDLE L3Handle; GMM_GFX_ADDRESS GfxAddress; //L3 Table Adr CPU equivalent GPU addr GMM_GFX_ADDRESS CPUAddress; //LMEM-cpuvisible adr bool NeedRegisterUpdate; //True @ L3 allocation, False when L3AdrRegWrite done SyncInfo BBInfo; RootTable() : pGmmResInfo(NULL), L3Handle(NULL), GfxAddress(0), CPUAddress(0), NeedRegisterUpdate(false), BBInfo() {} } TTL3; MidLevelTable* pTTL2; //array of L2-Tables public: #ifdef _WIN32 CRITICAL_SECTION TTLock; //synchronized access of PageTable obj #elif defined __linux__ pthread_mutex_t TTLock; #endif GmmPageTableMgr* PageTableMgr; GmmClientContext *pClientContext; PageTable(int Size, int NumL3e, TT_TYPE flag) : TTType(flag), NodesPerTable(Size / PAGE_SIZE) { PageTableMgr = NULL; pClientContext = NULL; InitializeCriticalSection(&TTLock); pTTL2 = new MidLevelTable[NumL3e]; } ~PageTable() { delete[] pTTL2; DeleteCriticalSection(&TTLock); } inline GMM_LIB_CONTEXT* GetGmmLibContext() { return pClientContext->GetLibContext(); } GMM_GFX_ADDRESS GetL3Address() { return TTL3.GfxAddress; } bool &GetRegisterStatus() { return TTL3.NeedRegisterUpdate; } GMM_STATUS AllocateL3Table(uint32_t L3TableSize, uint32_t L3AddrAlignment); GMM_STATUS DestroyL3Table(); void AllocateL1L2Table(GMM_GFX_ADDRESS TileAddr, GMM_GFX_ADDRESS * L1TableAdr, GMM_GFX_ADDRESS * L2TableAdr); void AllocateDummyTables(GmmLib::Table **L2Table, GmmLib::Table **L1Table); void GetL1L2TableAddr(GMM_GFX_ADDRESS TileAddr, GMM_GFX_ADDRESS * L1TableAdr, GMM_GFX_ADDRESS* L2TableAdr); uint8_t GetMappingType(GMM_GFX_ADDRESS GfxVA, GMM_GFX_SIZE_T Size, GMM_GFX_ADDRESS& LastAddr); HANDLE GetL3Handle() { return TTL3.L3Handle; } }; ////////////////////////////////////////////////////////////////////////////////////////////// /// Contains functions and members for AuxTable. /// AuxTable defines PageTable for translating VA->AuxVA, ie defines page-walk to get address /// of CCS-cacheline containing auxiliary data (compression tag, etc) for some resource ///////////////////////////////////////////////////////////////////////////////////////////// class AuxTable : public PageTable { public: const int L1Size; Table* NullL2Table; Table* NullL1Table; GMM_GFX_ADDRESS NullCCSTile; AuxTable(GmmClientContext *pClientContextIn) : PageTable(8 * PAGE_SIZE, GMM_AUX_L3_SIZE, TT_TYPE::AUXTT), L1Size((WA16K(pClientContextIn->GetLibContext()) || WA64K(pClientContextIn->GetLibContext())) ? (2 * PAGE_SIZE) : PAGE_SIZE) { NullL2Table = nullptr; NullL1Table = nullptr; NullCCSTile = 0; } AuxTable() : PageTable(8 * PAGE_SIZE, GMM_AUX_L3_SIZE, TT_TYPE::AUXTT), L1Size(2 * PAGE_SIZE) { NullL2Table = nullptr; NullL1Table = nullptr; NullCCSTile = 0; } GMM_STATUS InvalidateTable(GMM_UMD_SYNCCONTEXT * UmdContext, GMM_GFX_ADDRESS BaseAdr, GMM_GFX_SIZE_T Size, uint8_t DoNotWait); GMM_STATUS MapValidEntry(GMM_UMD_SYNCCONTEXT *UmdContext, GMM_GFX_ADDRESS BaseAdr, GMM_GFX_SIZE_T BaseSize, GMM_RESOURCE_INFO* BaseResInfo, GMM_GFX_ADDRESS AuxVA, GMM_RESOURCE_INFO* AuxResInfo, uint64_t PartialData, uint8_t DoNotWait); GMM_STATUS MapNullCCS(GMM_UMD_SYNCCONTEXT *UmdContext, GMM_GFX_ADDRESS BaseAdr, GMM_GFX_SIZE_T Size, uint64_t PartialL1e, uint8_t DoNotWait); GMM_AUXTTL1e CreateAuxL1Data(GMM_RESOURCE_INFO* BaseResInfo); GMM_GFX_ADDRESS GMM_INLINE __GetCCSCacheline(GMM_RESOURCE_INFO* BaseResInfo, GMM_GFX_ADDRESS BaseAdr, GMM_RESOURCE_INFO* AuxResInfo, GMM_GFX_ADDRESS AuxVA, GMM_GFX_SIZE_T AdrOffset); }; typedef struct _GMM_DEVICE_ALLOC { uint32_t Size; uint32_t Alignment; HANDLE Handle; GMM_GFX_ADDRESS GfxVA; GMM_GFX_ADDRESS CPUVA; void * Priv; HANDLE hCsr; } GMM_DEVICE_ALLOC; typedef struct _GMM_DEVICE_DEALLOC { HANDLE Handle; GMM_GFX_ADDRESS GfxVA; void * Priv; HANDLE hCsr; } GMM_DEVICE_DEALLOC; GMM_STATUS __GmmDeviceAlloc(GmmClientContext *pClientContext, GMM_DEVICE_CALLBACKS_INT *pDeviceCbInt, GMM_DEVICE_ALLOC *pAlloc); GMM_STATUS __GmmDeviceDealloc(GMM_CLIENT ClientType, GMM_DEVICE_CALLBACKS_INT *DeviceCb, GMM_DEVICE_DEALLOC *pDealloc, GmmClientContext *pClientContext); } #endif // #ifdef __cplusplus gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/ULT/000077500000000000000000000000001466655022700205175ustar00rootroot00000000000000gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/ULT/CMakeLists.txt000066400000000000000000000124401466655022700232600ustar00rootroot00000000000000# Copyright(c) 2017 Intel Corporation # Permission is hereby granted, free of charge, to any person obtaining a # copy of this software and associated documentation files(the "Software"), # to deal in the Software without restriction, including without limitation # the rights to use, copy, modify, merge, publish, distribute, sublicense, # and / or sell copies of the Software, and to permit persons to whom the # Software is furnished to do so, subject to the following conditions: # The above copyright notice and this permission notice shall be included # in all copies or substantial portions of the Software. # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS # OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL # THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR # OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, # ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR # OTHER DEALINGS IN THE SOFTWARE. set (EXE_NAME GMMULT) set(GMMULT_HEADERS GmmCachePolicyULT.h GmmCommonULT.h GmmMultiAdapterULT.h GmmGen10CachePolicyULT.h GmmGen10ResourceULT.h GmmGen11CachePolicyULT.h GmmGen11ResourceULT.h GmmGen12ResourceULT.h GmmGen12dGPUResourceULT.h GmmXe2_LPGResourceULT.h GmmGen12CachePolicyULT.h GmmGen12dGPUCachePolicyULT.h GmmXe_LPGCachePolicyULT.h GmmGen9CachePolicyULT.h GmmGen9ResourceULT.h GmmResourceULT.h GmmAuxTableULT.h stdafx.h targetver.h ) set(GMMULT_SOURCES GmmCachePolicyULT.cpp GmmCommonULT.cpp GmmMultiAdapterULT.cpp GmmGen10CachePolicyULT.cpp GmmGen10ResourceULT.cpp GmmGen11CachePolicyULT.cpp GmmGen12CachePolicyULT.cpp GmmGen12dGPUCachePolicyULT.cpp GmmXe_LPGCachePolicyULT.cpp GmmGen11ResourceULT.cpp GmmGen12ResourceULT.cpp GmmGen12dGPUResourceULT.cpp GmmXe2_LPGResourceULT.cpp GmmGen9CachePolicyULT.cpp GmmGen9ResourceULT.cpp GmmResourceCpuBltULT.cpp GmmResourceULT.cpp GmmAuxTableULT.cpp googletest/src/gtest-all.cc GmmULT.cpp ) source_group("Source Files\\Cache Policy" FILES GmmCachePolicyULT.cpp GmmGen9CachePolicyULT.cpp GmmGen10CachePolicyULT.cpp GmmGen11CachePolicyULT.cpp GmmGen12CachePolicyULT.cpp GmmGen12dGPUCachePolicyULT.cpp GmmXe_LPGCachePolicyULT.cpp ) source_group("Source Files\\Resource" FILES GmmGen10ResourceULT.cpp GmmGen11ResourceULT.cpp GmmGen12ResourceULT.cpp GmmGen12dGPUResourceULT.cpp GmmXe2_LPGResourceULT.cpp GmmGen9ResourceULT.cpp GmmResourceCpuBltULT.cpp GmmResourceULT.cpp ) source_group("Source Files\\TranslationTable" FILES GmmAuxTableULT.cpp ) source_group("Source Files\\MultiAdapter" FILES GmmMultiAdapterULT.cpp ) source_group("Header Files\\TranslationTable" FILES GmmAuxTableULT.h ) source_group("Header Files\\Cache Policy" FILES GmmCachePolicyULT.h GmmGen10CachePolicyULT.h GmmGen11CachePolicyULT.h GmmGen12CachePolicyULT.h GmmXe_LPGCachePolicyULT.h GmmGen12dGPUCachePolicyULT.h GmmGen9CachePolicyULT.h ) source_group("Header Files\\Resource" FILES GmmGen10ResourceULT.h GmmGen11ResourceULT.h GmmGen12ResourceULT.h GmmGen12dGPUResourceULT.h GmmXe2_LPGResourceULT.h GmmGen9ResourceULT.h GmmResourceULT.h ) source_group("Header Files\\MultiAdapter" FILES GmmMultiAdapterULT.h ) source_group("gtest" FILES googletest/gtest/gtest.h googletest/src/gtest-all.cc ) include_directories(BEFORE ./) include_directories(BEFORE ${PROJECT_SOURCE_DIR}) include_directories( googletest googletest/gtest ${BS_DIR_INC}/umKmInc ${BS_DIR_INC} ${BS_DIR_GMMLIB}/inc ${BS_DIR_INC}/common ) macro(GmmLibULTSetTargetConfig ultTarget) if (TARGET ${ultTarget}) set_property(TARGET ${ultTarget} APPEND PROPERTY COMPILE_DEFINITIONS $<$: _RELEASE> $<$: _RELEASE_INTERNAL> $<$: _DEBUG> ) endif() endmacro() add_executable(${EXE_NAME} ${GMMULT_HEADERS} ${GMMULT_SOURCES}) GmmLibULTSetTargetConfig(${EXE_NAME}) set_property(TARGET ${EXE_NAME} APPEND PROPERTY COMPILE_DEFINITIONS __GMM GMM_LIB_DLL __UMD) if(NOT TARGET igfx_gmmumd_dll) add_subdirectory("${BS_DIR_GMMLIB}" "${CMAKE_BINARY_DIR}/gmmlib/ult") endif() target_link_libraries(${EXE_NAME} igfx_gmmumd_dll) target_link_libraries(${EXE_NAME} pthread dl ) add_custom_target(Run_ULT ALL DEPENDS GMMULT) add_custom_command( TARGET Run_ULT POST_BUILD COMMAND echo running ULTs COMMAND "${CMAKE_COMMAND}" -E env "LD_LIBRARY_PATH=$" ${CMAKE_CFG_INTDIR}/${EXE_NAME} --gtest_filter=CTest* ) add_test( NAME ULT COMMAND env "LD_LIBRARY_PATH=$" $ --gtest_filter=CTest* ) gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/ULT/GmmAuxTableULT.cpp000066400000000000000000000171631466655022700237660ustar00rootroot00000000000000/*============================================================================== Copyright(c) 2019 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ============================================================================*/ #if defined (__linux__) && !defined(__i386__) #include "GmmAuxTableULT.h" using namespace std; using namespace GmmLib; static GMM_DEVICE_CALLBACKS_INT DeviceCBInt; CTestAuxTable::CTestAuxTable() { } CTestAuxTable::~CTestAuxTable() { } int CTestAuxTable::allocCB(void *bufMgr, size_t size, size_t alignment, void **bo, void **cpuAddr, uint64_t *gpuAddr) { if(bufMgr != (void *)0xdeadbeef) return -1; if(!bo || !cpuAddr || !gpuAddr) return -2; *cpuAddr = aligned_alloc(alignment, ALIGN(size, alignment)); if(!*cpuAddr) return -3; *bo = *cpuAddr; *gpuAddr = (uint64_t)*cpuAddr; return 0; } void CTestAuxTable::freeCB(void *bo) { ASSERT_TRUE(bo != NULL); free(bo); } void CTestAuxTable::waitFromCpuCB(void *bo) { } void CTestAuxTable::SetUpTestCase() { GfxPlatform.eProductFamily = IGFX_TIGERLAKE_LP; GfxPlatform.eRenderCoreFamily = IGFX_GEN12_CORE; DeviceCBInt.pBufMgr = (void *)0xdeadbeef; DeviceCBInt.DevCbPtrs_.pfnAllocate = CTestAuxTable::allocCB; DeviceCBInt.DevCbPtrs_.pfnDeallocate = CTestAuxTable::freeCB; DeviceCBInt.DevCbPtrs_.pfnWaitFromCpu = CTestAuxTable::waitFromCpuCB; if(GfxPlatform.eProductFamily == IGFX_UNKNOWN || GfxPlatform.eRenderCoreFamily == IGFX_UNKNOWN_CORE) { GfxPlatform.eProductFamily = IGFX_BROADWELL; GfxPlatform.eRenderCoreFamily = IGFX_GEN8_CORE; } AllocateAdapterInfo(); if(pGfxAdapterInfo) { pGfxAdapterInfo->SkuTable.FtrE2ECompression = true; pGfxAdapterInfo->SkuTable.FtrLinearCCS = true; } CommonULT::SetUpTestCase(); } void CTestAuxTable::TearDownTestCase() { CommonULT::TearDownTestCase(); } TEST_F(CTestAuxTable, TestUpdateAuxTableCompressedSurface) { GmmPageTableMgr *mgr = pGmmULTClientContext->CreatePageTblMgrObject(&DeviceCBInt, TT_TYPE::AUXTT); ASSERT_TRUE(mgr != NULL); Surface *surf = new Surface(7680, 4320); ASSERT_TRUE(surf != NULL && surf->init()); GMM_DDI_UPDATEAUXTABLE updateReq = {0}; updateReq.BaseResInfo = surf->getGMMResourceInfo(); updateReq.BaseGpuVA = surf->getGfxAddress(GMM_PLANE_Y); updateReq.Map = 1; GMM_STATUS res = mgr->UpdateAuxTable(&updateReq); ASSERT_TRUE(res == GMM_SUCCESS); delete surf; pGmmULTClientContext->DestroyPageTblMgrObject(mgr); } TEST_F(CTestAuxTable, DISABLED_TestUpdateAuxTableNonCompressedSurface) { GmmPageTableMgr *mgr = pGmmULTClientContext->CreatePageTblMgrObject(&DeviceCBInt, TT_TYPE::AUXTT); ASSERT_TRUE(mgr != NULL); Surface *surf = new Surface(7680, 4320, false); ASSERT_TRUE(surf != NULL && surf->init()); GMM_DDI_UPDATEAUXTABLE updateReq = {0}; memset(&updateReq, 0, sizeof(GMM_DDI_UPDATEAUXTABLE)); updateReq.BaseResInfo = surf->getGMMResourceInfo(); updateReq.BaseGpuVA = surf->getGfxAddress(GMM_PLANE_Y); updateReq.Map = 1; GMM_STATUS res = mgr->UpdateAuxTable(&updateReq); ASSERT_TRUE(res != GMM_SUCCESS); delete surf; pGmmULTClientContext->DestroyPageTblMgrObject(mgr); } TEST_F(CTestAuxTable, TestInvalidateAuxTable) { GmmPageTableMgr *mgr = pGmmULTClientContext->CreatePageTblMgrObject(&DeviceCBInt, TT_TYPE::AUXTT); ASSERT_TRUE(mgr != NULL); Surface *surf = new Surface(7680, 4320); ASSERT_TRUE(surf != NULL && surf->init()); GMM_DDI_UPDATEAUXTABLE updateReq = {0}; updateReq.BaseResInfo = surf->getGMMResourceInfo(); updateReq.BaseGpuVA = surf->getGfxAddress(GMM_PLANE_Y); updateReq.Map = 1; GMM_STATUS res = mgr->UpdateAuxTable(&updateReq); ASSERT_TRUE(res == GMM_SUCCESS); memset(&updateReq, 0, sizeof(updateReq)); updateReq.BaseResInfo = surf->getGMMResourceInfo(); updateReq.Map = 0; res = mgr->UpdateAuxTable(&updateReq); ASSERT_TRUE(res == GMM_SUCCESS); delete surf; pGmmULTClientContext->DestroyPageTblMgrObject(mgr); } TEST_F(CTestAuxTable, DISABLED_TestUpdateAuxTableStress) { const int num_surf = 1000; Surface * surfaces[num_surf]; Surface * surf; int i; GmmPageTableMgr *mgr = pGmmULTClientContext->CreatePageTblMgrObject(&DeviceCBInt, TT_TYPE::AUXTT); ASSERT_TRUE(mgr != NULL); for(i = 0; i < num_surf; i++) { surf = new Surface(7680, 4320); surfaces[i] = surf; ASSERT_TRUE(surf != NULL && surf->init()); GMM_DDI_UPDATEAUXTABLE updateReq = {0}; updateReq.BaseResInfo = surf->getGMMResourceInfo(); updateReq.BaseGpuVA = surf->getGfxAddress(GMM_PLANE_Y); updateReq.Map = 1; mgr->UpdateAuxTable(&updateReq); } for(i = 0; i < num_surf; i++) { surf = surfaces[i]; delete surf; } pGmmULTClientContext->DestroyPageTblMgrObject(mgr); } TEST_F(CTestAuxTable, TestAuxTableContent) { GmmPageTableMgr *mgr = pGmmULTClientContext->CreatePageTblMgrObject(&DeviceCBInt, TT_TYPE::AUXTT); ASSERT_TRUE(mgr != NULL); Surface *surf = new Surface(720, 480); ASSERT_TRUE(surf != NULL && surf->init()); GMM_DDI_UPDATEAUXTABLE updateReq = {0}; updateReq.BaseResInfo = surf->getGMMResourceInfo(); updateReq.BaseGpuVA = surf->getGfxAddress(GMM_PLANE_Y); updateReq.Map = 1; GMM_STATUS res = mgr->UpdateAuxTable(&updateReq); ASSERT_TRUE(res == GMM_SUCCESS); Walker *ywalker = new Walker(surf->getGfxAddress(GMM_PLANE_Y), surf->getAuxGfxAddress(GMM_AUX_CCS), mgr->GetAuxL3TableAddr()); for(size_t i = 0; i < surf->getSurfaceSize(GMM_PLANE_Y); i++) { GMM_GFX_ADDRESS addr = surf->getGfxAddress(GMM_PLANE_Y) + i; GMM_GFX_ADDRESS val = ywalker->walk(addr); GMM_GFX_ADDRESS expected = ywalker->expected(addr); ASSERT_EQ(expected, val); } Walker *uvwalker = new Walker(surf->getGfxAddress(GMM_PLANE_U), surf->getAuxGfxAddress(GMM_AUX_UV_CCS), mgr->GetAuxL3TableAddr()); for(size_t i = 0; i < surf->getSurfaceSize(GMM_PLANE_U); i++) { GMM_GFX_ADDRESS addr = surf->getGfxAddress(GMM_PLANE_U) + i; GMM_GFX_ADDRESS val = uvwalker->walk(addr); GMM_GFX_ADDRESS expected = uvwalker->expected(addr); ASSERT_EQ(expected, val); } delete uvwalker; delete ywalker; delete surf; pGmmULTClientContext->DestroyPageTblMgrObject(mgr); } #endif /* __linux__ */ gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/ULT/GmmAuxTableULT.h000066400000000000000000000201021466655022700234160ustar00rootroot00000000000000/*============================================================================== Copyright(c) 2019 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ============================================================================*/ #pragma once #if defined (__linux__) && !defined(__i386__) #ifndef _ISOC11_SOURCE #define _ISOC11_SOURCE 1 #endif #include "GmmGen10ResourceULT.h" #include #include #ifndef ALIGN #define ALIGN(v, a) (((v) + ((a)-1)) & ~((a)-1)) #endif class CTestAuxTable : public CTestGen10Resource { public: static void SetUpTestCase(); static void TearDownTestCase(); CTestAuxTable(); ~CTestAuxTable(); static int allocCB(void *bufMgr, size_t size, size_t alignment, void **bo, void **cpuAddr, uint64_t *gpuAddr); static void freeCB(void *bo); static void waitFromCpuCB(void *bo); class Surface { public: Surface(unsigned int width, unsigned int height, bool mmc = true) : mWidth(width), mHeight(height), mMMC(mmc), mResInfo(0), mBuf(0) { } ~Surface() { deinit(); } bool init() { size_t size; size_t alignment; GMM_RESCREATE_PARAMS gmmParams = {}; gmmParams.Type = RESOURCE_2D; gmmParams.Format = GMM_FORMAT_NV12; gmmParams.BaseWidth = mWidth; gmmParams.BaseHeight = mHeight; gmmParams.Depth = 0x1; gmmParams.ArraySize = 1; gmmParams.Flags.Info.TiledY = 1; gmmParams.Flags.Info.MediaCompressed = mMMC ? 1 : 0; //gmmParams.Flags.Gpu.CCS = mmc ? 1 : 0; gmmParams.Flags.Gpu.MMC = mMMC ? 1 : 0; gmmParams.Flags.Gpu.Texture = 1; gmmParams.Flags.Gpu.RenderTarget = 1; gmmParams.Flags.Gpu.UnifiedAuxSurface = mMMC ? 1 : 0; //gmmParams.Flags.Gpu.Depth = 1; gmmParams.Flags.Gpu.Video = true; mResInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); size = mResInfo->GetSizeSurface(); alignment = mResInfo->GetResFlags().Info.TiledYf ? GMM_KBYTE(16) : GMM_KBYTE(64); mBuf = aligned_alloc(alignment, ALIGN(size, alignment)); if(!mResInfo || !mBuf) return false; mYBase = (GMM_GFX_ADDRESS)mBuf; mUVBase = 0; mAuxYBase = mYBase + mResInfo->GetUnifiedAuxSurfaceOffset(GMM_AUX_CCS); mAuxUVBase = 0; mYPlaneSize = mResInfo->GetSizeMainSurface(); if(pGmmULTClientContext->IsPlanar(mResInfo->GetResourceFormat())) { GMM_REQ_OFFSET_INFO ReqInfo = {0}; ReqInfo.Plane = GMM_PLANE_U; ReqInfo.ReqRender = 1; mResInfo->GetOffset(ReqInfo); mYPlaneSize = ReqInfo.Render.Offset64; mUVBase = mYBase + mYPlaneSize; mAuxUVBase = mYBase + mResInfo->GetUnifiedAuxSurfaceOffset(GMM_AUX_UV_CCS); } mUVPlaneSize = mResInfo->GetSizeMainSurface() - mYPlaneSize; return true; } void deinit() { if(mBuf) { free(mBuf); mBuf = NULL; } if(mResInfo) { pGmmULTClientContext->DestroyResInfoObject(mResInfo); mResInfo = NULL; } } GMM_GFX_ADDRESS getGfxAddress(GMM_YUV_PLANE plane) { switch(plane) { case GMM_PLANE_Y: return mYBase; case GMM_PLANE_U: case GMM_PLANE_V: return mUVBase; default: throw; } } GMM_GFX_ADDRESS getAuxGfxAddress(GMM_UNIFIED_AUX_TYPE auxType) { switch(auxType) { case GMM_AUX_CCS: case GMM_AUX_Y_CCS: return mAuxYBase; case GMM_AUX_UV_CCS: return mAuxUVBase; default: throw; } } GMM_RESOURCE_INFO *getGMMResourceInfo() { return mResInfo; } size_t getSurfaceSize(GMM_YUV_PLANE plane) { switch(plane) { case GMM_PLANE_Y: return mYPlaneSize; case GMM_PLANE_U: case GMM_PLANE_V: return mUVPlaneSize; default: throw; } } private: unsigned int mWidth; unsigned int mHeight; bool mMMC; GMM_RESOURCE_INFO *mResInfo; void * mBuf; GMM_GFX_ADDRESS mYBase; GMM_GFX_ADDRESS mUVBase; GMM_GFX_ADDRESS mAuxYBase; GMM_GFX_ADDRESS mAuxUVBase; size_t mYPlaneSize; size_t mUVPlaneSize; }; class Walker { public: Walker(GMM_GFX_ADDRESS mainBase, GMM_GFX_ADDRESS auxBase, GMM_GFX_ADDRESS l3Base) { mMainBase = mainBase; mAuxBase = (auxBase >> 6) << 6; mL3Base = (uint64_t *)l3Base; } GMM_GFX_ADDRESS expected(GMM_GFX_ADDRESS addr) { uint8_t Is64KChunk = (const_cast(pGfxAdapterInfo->WaTable).WaAuxTable16KGranular) ? 0 : 1; uint32_t count = (addr - mMainBase) / (Is64KChunk ? GMM_KBYTE(64) : GMM_KBYTE(16)); return mAuxBase + (Is64KChunk ? 256 : 64) * count; } GMM_GFX_ADDRESS walk(GMM_GFX_ADDRESS addr) { uint64_t mask = (const_cast(pGfxAdapterInfo->WaTable).WaAuxTable16KGranular) ? 0x0000ffffffffffc0 : 0x0000ffffffffff00; uint32_t idx = l3Index(addr); uint64_t *l2Base = (uint64_t *)((mL3Base[idx] >> 15) << 15); idx = l2Index(addr); uint64_t *l1Base = (uint64_t *)((l2Base[idx] >> 13) << 13); idx = l1Index(addr); uint64_t auxAddr = (uint64_t)(l1Base[idx] & mask); return auxAddr; } public: static inline uint32_t l3Index(GMM_GFX_ADDRESS addr) { return GMM_AUX_L3_ENTRY_IDX(addr); } static inline uint32_t l2Index(GMM_GFX_ADDRESS addr) { return GMM_AUX_L2_ENTRY_IDX(addr); } static inline uint32_t l1Index(GMM_GFX_ADDRESS addr) { return GMM_AUX_L1_ENTRY_IDX_EXPORTED_2(addr, (const_cast(pGfxAdapterInfo->WaTable).WaAuxTable64KGranular), (const_cast(pGfxAdapterInfo->WaTable).WaAuxTable16KGranular)); } private: GMM_GFX_ADDRESS mMainBase; GMM_GFX_ADDRESS mAuxBase; uint64_t * mL3Base; }; }; #endif /* __linux__ */ gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/ULT/GmmCachePolicyULT.cpp000066400000000000000000000133471466655022700244440ustar00rootroot00000000000000/*============================================================================== Copyright(c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ============================================================================*/ #include "GmmCachePolicyULT.h" using namespace std; ///////////////////////////////////////////////////////////////////////////////////// /// Sets up common environment for Cache Policy fixture tests. this is called once per /// test case before executing all tests under resource fixture test case. /// It also calls SetupTestCase from CommonULT to initialize global context and others. /// ///////////////////////////////////////////////////////////////////////////////////// void CTestCachePolicy::SetUpTestCase() { GfxPlatform.eProductFamily = IGFX_BROADWELL; GfxPlatform.eRenderCoreFamily = IGFX_GEN8_CORE; AllocateAdapterInfo(); pGfxAdapterInfo->SystemInfo.L3CacheSizeInKb = 768; pGfxAdapterInfo->SystemInfo.LLCCacheSizeInKb = 2 * 1024; //2 MB pGfxAdapterInfo->SystemInfo.EdramSizeInKb = 64 * 1024; //64 MB const_cast(pGfxAdapterInfo->SkuTable).FtrEDram = 1; CommonULT::SetUpTestCase(); printf("%s\n", __FUNCTION__); } ///////////////////////////////////////////////////////////////////////////////////// /// cleans up once all the tests finish execution. It also calls TearDownTestCase /// from CommonULT to destroy global context and others. /// ///////////////////////////////////////////////////////////////////////////////////// void CTestCachePolicy::TearDownTestCase() { printf("%s\n", __FUNCTION__); CommonULT::TearDownTestCase(); } void CTestCachePolicy::CheckL3CachePolicy() { const uint32_t TargetCache_L3_LLC_ELLC = 0x3; // Check Usage MOCS index against MOCS settings for(uint32_t Usage = GMM_RESOURCE_USAGE_UNKNOWN; Usage < GMM_RESOURCE_USAGE_MAX; Usage++) { GMM_CACHE_POLICY_ELEMENT ClientRequest = pGmmULTClientContext->GetCachePolicyElement((GMM_RESOURCE_USAGE_TYPE)Usage); MEMORY_OBJECT_CONTROL_STATE Mocs = ClientRequest.MemoryObjectOverride; // Not check WT/WB/UC since that doesn't really matter for L3 if(ClientRequest.L3) { EXPECT_EQ(TargetCache_L3_LLC_ELLC, Mocs.Gen8.TargetCache) << "Usage# " << Usage << ": Incorrect L3 target cache setting"; } } } TEST_F(CTestCachePolicy, TestL3CachePolicy) { CheckL3CachePolicy(); } void CTestCachePolicy::CheckLlcEdramCachePolicy() { const uint32_t TargetCache_ELLC = 0; const uint32_t TargetCache_LLC = 1; const uint32_t TargetCache_LLC_ELLC = 2; const uint32_t TargetCache_L3_LLC_ELLC = 2; const uint32_t CC_UNCACHED = 0x1; const uint32_t CC_CACHED_WT = 0x2; const uint32_t CC_CACHED_WB = 0x3; // Check Usage MOCS index against MOCS settings for(uint32_t Usage = GMM_RESOURCE_USAGE_UNKNOWN; Usage < GMM_RESOURCE_USAGE_MAX; Usage++) { GMM_CACHE_POLICY_ELEMENT ClientRequest = pGmmULTClientContext->GetCachePolicyElement((GMM_RESOURCE_USAGE_TYPE)Usage); MEMORY_OBJECT_CONTROL_STATE Mocs = ClientRequest.MemoryObjectOverride; // Check for age EXPECT_EQ(ClientRequest.AGE, Mocs.Gen8.Age) << "Usage# " << Usage << ": Incorrect AGE settings"; if(ClientRequest.L3) { continue; } if(!ClientRequest.LLC && !ClientRequest.ELLC) // Uncached { EXPECT_EQ(CC_UNCACHED, Mocs.Gen8.CacheControl) << "Usage# " << Usage << ": Incorrect cache control setting"; } else { if(ClientRequest.WT) // Write-through { EXPECT_EQ(CC_CACHED_WT, Mocs.Gen8.CacheControl) << "Usage# " << Usage << ": Incorrect cache control setting"; } else // Write-back { EXPECT_EQ(CC_CACHED_WB, Mocs.Gen8.CacheControl) << "Usage# " << Usage << ": Incorrect cache control setting"; } if(ClientRequest.LLC && !ClientRequest.ELLC) // LLC only { EXPECT_EQ(TargetCache_LLC, Mocs.Gen8.TargetCache) << "Usage# " << Usage << ": Incorrect target cache setting"; } else if(!ClientRequest.LLC && ClientRequest.ELLC) // eLLC only { EXPECT_EQ(TargetCache_ELLC, Mocs.Gen8.TargetCache) << "Usage# " << Usage << ": Incorrect target cache setting"; } else if(ClientRequest.LLC && ClientRequest.ELLC) { EXPECT_EQ(TargetCache_LLC_ELLC, Mocs.Gen8.TargetCache) << "Usage# " << Usage << ": Incorrect target cache setting"; } } } } TEST_F(CTestCachePolicy, TestLlcEdramCachePolicy) { CheckLlcEdramCachePolicy(); } gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/ULT/GmmCachePolicyULT.h000066400000000000000000000030161466655022700241010ustar00rootroot00000000000000/*============================================================================== Copyright(c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ============================================================================*/ #pragma once #include "GmmCommonULT.h" // Base Class for Cache Policy Compile Time ULT class CTestCachePolicy : public CommonULT { protected: virtual void CheckL3CachePolicy(); virtual void CheckLlcEdramCachePolicy(); public: static void SetUpTestCase(); static void TearDownTestCase(); };gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/ULT/GmmCommonULT.cpp000066400000000000000000000073661466655022700235150ustar00rootroot00000000000000/*============================================================================== Copyright(c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ============================================================================*/ #include "GmmCommonULT.h" #ifndef _WIN32 #include #endif ADAPTER_INFO * CommonULT::pGfxAdapterInfo = NULL; PLATFORM CommonULT::GfxPlatform = {}; GMM_CLIENT_CONTEXT *CommonULT::pGmmULTClientContext = NULL; PFNGMMINIT CommonULT::pfnGmmInit = {0}; PFNGMMDESTROY CommonULT::pfnGmmDestroy = {0}; #ifdef _WIN32 HINSTANCE CommonULT::hGmmLib = NULL; #else void *CommonULT::hGmmLib = NULL; #endif void CommonULT::AllocateAdapterInfo() { if(!pGfxAdapterInfo) { pGfxAdapterInfo = (ADAPTER_INFO *)malloc(sizeof(ADAPTER_INFO)); if(!pGfxAdapterInfo) { ASSERT_TRUE(false); return; } memset(pGfxAdapterInfo, 0, sizeof(ADAPTER_INFO)); pGfxAdapterInfo->SkuTable.FtrTileY = 1; pGfxAdapterInfo->WaTable.WaAuxTable64KGranular = 1; // 64K aux granularity } } void CommonULT::SetUpTestCase() { printf("%s\n", __FUNCTION__); GMM_INIT_IN_ARGS InArgs; GMM_INIT_OUT_ARGS OutArgs; if(GfxPlatform.eProductFamily == IGFX_UNKNOWN || GfxPlatform.eRenderCoreFamily == IGFX_UNKNOWN_CORE) { GfxPlatform.eProductFamily = IGFX_BROADWELL; GfxPlatform.eRenderCoreFamily = IGFX_GEN8_CORE; } AllocateAdapterInfo(); InArgs.ClientType = GMM_EXCITE_VISTA; InArgs.pGtSysInfo = &pGfxAdapterInfo->SystemInfo; InArgs.pSkuTable = &pGfxAdapterInfo->SkuTable; InArgs.pWaTable = &pGfxAdapterInfo->WaTable; InArgs.Platform = GfxPlatform; #ifdef _WIN32 InArgs.stAdapterBDF = {0, 2, 0, 0}; #else InArgs.FileDescriptor = 512; // Initializing BDF to {0,2,0,0} which corresponds to decimal 512 for AdapterBDF.Data #endif hGmmLib = dlopen(GMM_UMD_DLL, RTLD_LAZY); ASSERT_TRUE(hGmmLib); *(void **)(&pfnGmmInit) = dlsym(hGmmLib, "InitializeGmm"); *(void **)(&pfnGmmDestroy) = dlsym(hGmmLib, "GmmAdapterDestroy"); ASSERT_TRUE(pfnGmmInit); ASSERT_TRUE(pfnGmmDestroy); pfnGmmInit(&InArgs, &OutArgs); pGmmULTClientContext = OutArgs.pGmmClientContext; ASSERT_TRUE(pGmmULTClientContext); } void CommonULT::TearDownTestCase() { printf("%s\n", __FUNCTION__); GMM_INIT_OUT_ARGS OutArgs; OutArgs.pGmmClientContext = static_cast(pGmmULTClientContext); pfnGmmDestroy(&OutArgs); if(hGmmLib) { dlclose(hGmmLib); } hGmmLib = NULL; pGmmULTClientContext = NULL; free(pGfxAdapterInfo); pGfxAdapterInfo = NULL; GfxPlatform = {}; } gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/ULT/GmmCommonULT.h000066400000000000000000000037301466655022700231510ustar00rootroot00000000000000/*============================================================================== Copyright(c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ============================================================================*/ #pragma once #include "stdafx.h" typedef GMM_STATUS (GMM_STDCALL *PFNGMMINIT)(GMM_INIT_IN_ARGS *pInArgs, GMM_INIT_OUT_ARGS *pOutArgs); typedef void(GMM_STDCALL *PFNGMMDESTROY)(GMM_INIT_OUT_ARGS *pInArgs); class CommonULT : public testing::Test { public: static void SetUpTestCase(); static void TearDownTestCase(); static void AllocateAdapterInfo(); protected: static ADAPTER_INFO *pGfxAdapterInfo; static PLATFORM GfxPlatform; static GMM_CLIENT_CONTEXT *pGmmULTClientContext; static PFNGMMINIT pfnGmmInit; static PFNGMMDESTROY pfnGmmDestroy; #ifdef _WIN32 static HINSTANCE hGmmLib; #else static void *hGmmLib; #endif }; gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/ULT/GmmGen10CachePolicyULT.cpp000066400000000000000000000025751466655022700252400ustar00rootroot00000000000000/*============================================================================== Copyright(c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ============================================================================*/ #include "GmmGen10CachePolicyULT.h" using namespace std; TEST_F(CTestGen10CachePolicy, TestCachePolicyOverrides) { } TEST_F(CTestGen10CachePolicy, TestCachePolicyConditionals) { } gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/ULT/GmmGen10CachePolicyULT.h000066400000000000000000000024701466655022700246770ustar00rootroot00000000000000/*============================================================================== Copyright(c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ============================================================================*/ #pragma once #include "GmmGen9CachePolicyULT.h" class CTestGen10CachePolicy : public CTestGen9CachePolicy { }; gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/ULT/GmmGen10ResourceULT.cpp000066400000000000000000000260071466655022700246400ustar00rootroot00000000000000/*============================================================================== Copyright(c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ============================================================================*/ #include "GmmGen10ResourceULT.h" using namespace std; ///////////////////////////////////////////////////////////////////////////////////// /// Sets up common environment for Resource fixture tests. this is called once per /// test case before executing all tests under resource fixture test case. // It also calls SetupTestCase from CommonULT to initialize global context and others. /// /// @see CTestGen9Resource::SetUpTestCase() /// ///////////////////////////////////////////////////////////////////////////////////// void CTestGen10Resource::SetUpTestCase() { printf("%s\n", __FUNCTION__); GfxPlatform.eProductFamily = IGFX_CANNONLAKE; GfxPlatform.eRenderCoreFamily = IGFX_GEN10_CORE; CommonULT::SetUpTestCase(); } ///////////////////////////////////////////////////////////////////////////////////// /// cleans up once all the tests finish execution. It also calls TearDownTestCase /// from CommonULT to destroy global context and others. /// /// @see CTestGen10Resource::TearDownTestCase() ///////////////////////////////////////////////////////////////////////////////////// void CTestGen10Resource::TearDownTestCase() { printf("%s\n", __FUNCTION__); CommonULT::TearDownTestCase(); } /// @brief ULT for 2D TileYs Resource TEST_F(CTestGen10Resource, Test2DTileYsResource) { printf("%s\n", __FUNCTION__); } /// @brief ULT for 2D TileYf Resource TEST_F(CTestGen10Resource, Test2DTileYfResource) { printf("%s\n", __FUNCTION__); } TEST_F(CTestGen10Resource, TestMSAA) { //Tile dimensions in Bytes const uint32_t MCSTileSize[1][2] = {128, 32}; //MCS is TileY //Gen9: MSAA 16x no MCS for width > 8K //No MSAA for YUV/compressed formats //Interleaved MSS (IMS) for Depth/Stencil. Arrayed MSS (CMS) for Color RT //MSS (Arrayed): px_wL, px_hL = pixel width/height of single sample at Lod L // MSS width = px_wL, MSS height = NumSamples*px_hL //MSS (Interleaved): px_wL, px_hL = pixel width/height of single sample at Lod L // Samples MSS width MSS Height // 2x 4*ceil(px_wL/2) px_hL // 4x 4*ceil(px_wL/2) 4*ceil(px_hL/2) // 8x 8*ceil(px_wL/2) 4*ceil(px_hL/2) // 16x 8*ceil(px_wL/2) 8*ceil(px_hL/2) //MCS (bpp): 2x/4x - bpp_8, 8x - bpp_32, 16x - bpp_64 const uint32_t TestDimensions[4][2] = { //Input dimensions in #Tiles {15, 20}, //16 Tiles x 20 {0, 0}, //1x1x1 {1, 0}, //2 Tilesx1 {1, 1}, //2 Tiles x 2 }; uint32_t TestArraySize[2] = {1, 5}; uint32_t MinPitch = 32; uint32_t HAlign = 0, VAlign = 0; uint32_t TileDimX = 0, TileDimY = 0; uint32_t MCSHAlign = 0, MCSVAlign = 0, TileSize = 0; uint32_t ExpectedMCSBpp = 0; std::vector> List; //TEST_TILE_TYPE, TEST_BPP, TEST_RESOURCE_TYPE, Depth or RT, TestDimension index, ArraySize auto Size = BuildInputIterator(List, 4, 2, false); // Size of arrays TestDimensions, TestArraySize for(auto element : List) { GMM_RESCREATE_PARAMS gmmParams = {}; gmmParams.Flags.Info = {0}; TEST_TILE_TYPE Tiling = (TEST_TILE_TYPE)std::get<0>(element); TEST_BPP Bpp = (TEST_BPP)std::get<1>(element); TEST_RESOURCE_TYPE ResType = (TEST_RESOURCE_TYPE)std::get<2>(element); bool IsRT = std::get<3>(element); // True for RT, False for Depth int TestDimIdx = std::get<4>(element); //index into TestDimensions array int ArrayIdx = std::get<5>(element); //index into TestArraySize TileSize = (Tiling == TEST_TILEYS) ? GMM_KBYTE(64) : GMM_KBYTE(4); //Discard un-supported Tiling/Res_type/bpp for this test if(ResType != TEST_RESOURCE_2D || //No 1D/3D/Cube. Supported 2D mip-maps/array (!IsRT && (Tiling == TEST_TILEX || !(Bpp == TEST_BPP_16 || Bpp == TEST_BPP_32)))) //depth supported on 16bit, 32bit formats only continue; SetTileFlag(gmmParams, Tiling); SetResType(gmmParams, ResType); SetResGpuFlags(gmmParams, IsRT); SetResArraySize(gmmParams, TestArraySize[ArrayIdx]); gmmParams.NoGfxMemory = 1; gmmParams.Format = SetResourceFormat(Bpp); for(uint32_t k = MSAA_2x; k <= MSAA_16x; k++) { GetAlignmentAndTileDimensionsForMSAA(Bpp, IsRT, Tiling, (TEST_MSAA)k, TileDimX, TileDimY, HAlign, VAlign, ExpectedMCSBpp, MCSHAlign, MCSVAlign); gmmParams.BaseWidth64 = TestDimensions[TestDimIdx][0] * TileDimX + 0x1; gmmParams.BaseHeight = TestDimensions[TestDimIdx][1] * TileDimY + 0x1; gmmParams.Depth = 0x1; gmmParams.MSAA.NumSamples = static_cast(pow((double)2, k)); gmmParams.Flags.Gpu.MCS = 0; //MSS surface GMM_RESOURCE_INFO *MSSResourceInfo; MSSResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); if(MSSResourceInfo) { VerifyResourceHAlign(MSSResourceInfo, HAlign); VerifyResourceVAlign(MSSResourceInfo, VAlign); if(IsRT) //Arrayed MSS { uint32_t ExpectedPitch = 0, ExpectedQPitch = 0; ExpectedPitch = GMM_ULT_ALIGN(GMM_ULT_ALIGN(gmmParams.BaseWidth64, HAlign) * (uint32_t)pow(2.0, Bpp), TileDimX); // Aligned width * bpp, aligned to TileWidth ExpectedPitch = GFX_MAX(ExpectedPitch, MinPitch); VerifyResourcePitch(MSSResourceInfo, ExpectedPitch); if(Tiling != TEST_LINEAR) VerifyResourcePitchInTiles(MSSResourceInfo, ExpectedPitch / TileDimX); ExpectedQPitch = GMM_ULT_ALIGN(gmmParams.BaseHeight, VAlign); if(gmmParams.ArraySize > 1) //Gen9: Qpitch is distance between array slices (not sample slices) { VerifyResourceQPitch(MSSResourceInfo, ExpectedQPitch); } uint32_t ExpectedHeight = GMM_ULT_ALIGN(ExpectedQPitch * gmmParams.MSAA.NumSamples * gmmParams.ArraySize, TileDimY); //Align Height =ExpectedPitch * NumSamples * ExpectedQPitch, to Tile-Height VerifyResourceSize(MSSResourceInfo, GMM_ULT_ALIGN(ExpectedPitch * ExpectedHeight, TileSize)); } else // Interleaved MSS { uint32_t WidthMultiplier, HeightMultiplier; GetInterleaveMSSPattern((TEST_MSAA)k, WidthMultiplier, HeightMultiplier, IsRT, Bpp); gmmParams.BaseWidth64 = WidthMultiplier > 1 ? GMM_ULT_ALIGN(gmmParams.BaseWidth64, 2) : gmmParams.BaseWidth64; gmmParams.BaseHeight = HeightMultiplier > 1 ? GMM_ULT_ALIGN(gmmParams.BaseHeight, 2) : gmmParams.BaseHeight; uint32_t ExpectedPitch = GMM_ULT_ALIGN(GMM_ULT_ALIGN(gmmParams.BaseWidth64 * WidthMultiplier, HAlign) * (uint32_t)pow(2.0, Bpp), TileDimX); VerifyResourcePitch(MSSResourceInfo, ExpectedPitch); if(Tiling != TEST_LINEAR) { VerifyResourcePitchInTiles(MSSResourceInfo, ExpectedPitch / TileDimX); } uint64_t ExpectedQPitch = GMM_ULT_ALIGN(gmmParams.BaseHeight * HeightMultiplier, VAlign); if(gmmParams.ArraySize > 1) { VerifyResourceQPitch(MSSResourceInfo, ExpectedQPitch); } uint64_t ExpectedHeight = GMM_ULT_ALIGN(ExpectedQPitch * gmmParams.ArraySize, TileDimY); //Align Height = ExpectedQPitch*ArraySize, to Tile-Height VerifyResourceSize(MSSResourceInfo, GMM_ULT_ALIGN(ExpectedPitch * ExpectedHeight, TileSize)); //ExpectedPitch *ExpectedHeight } } //No MCS surface if MSS creation failed if(MSSResourceInfo) { gmmParams.Flags.Gpu.MCS = 1; GMM_RESOURCE_INFO *MCSResourceInfo; MCSResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); VerifyResourceHAlign(MCSResourceInfo, MCSHAlign); VerifyResourceVAlign(MCSResourceInfo, MCSVAlign); uint32_t ExpectedPitch = GMM_ULT_ALIGN(GMM_ULT_ALIGN(gmmParams.BaseWidth64, MCSHAlign) * ExpectedMCSBpp, MCSTileSize[0][0]); // Align in texels, tehn multiply w/ Bpt VerifyResourcePitch(MCSResourceInfo, ExpectedPitch); VerifyResourcePitchInTiles(MCSResourceInfo, ExpectedPitch / MCSTileSize[0][0]); uint32_t ExpectedQPitch = GMM_ULT_ALIGN(gmmParams.BaseHeight, MCSVAlign); if(gmmParams.ArraySize > 1) { ExpectedQPitch = GMM_ULT_ALIGN(gmmParams.BaseHeight, MCSVAlign); //QPitch only for array VerifyResourceQPitch(MCSResourceInfo, ExpectedQPitch); } uint32_t ExpectedHeight = GMM_ULT_ALIGN(ExpectedQPitch * gmmParams.ArraySize, MCSTileSize[0][1]); VerifyResourceSize(MCSResourceInfo, GMM_ULT_ALIGN(ExpectedPitch * ExpectedHeight, GMM_KBYTE(4))); //MCS Tile is TileY pGmmULTClientContext->DestroyResInfoObject(MCSResourceInfo); } //MCS pGmmULTClientContext->DestroyResInfoObject(MSSResourceInfo); } //NumSamples = k } //Iterate through all Input types //Mip-mapped, MSAA case: } gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/ULT/GmmGen10ResourceULT.h000066400000000000000000000025721466655022700243060ustar00rootroot00000000000000/*============================================================================== Copyright(c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ============================================================================*/ #pragma once #include "GmmGen9ResourceULT.h" class CTestGen10Resource : public CTestGen9Resource { public: static void SetUpTestCase(); static void TearDownTestCase(); };gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/ULT/GmmGen11CachePolicyULT.cpp000066400000000000000000000204311466655022700252300ustar00rootroot00000000000000/*============================================================================== Copyright(c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ============================================================================*/ #include "GmmGen11CachePolicyULT.h" using namespace std; ///////////////////////////////////////////////////////////////////////////////////// /// Sets up common environment for Cache Policy fixture tests. this is called once per /// test case before executing all tests under resource fixture test case. /// It also calls SetupTestCase from CommonULT to initialize global context and others. /// ///////////////////////////////////////////////////////////////////////////////////// void CTestGen11CachePolicy::SetUpTestCase() { GfxPlatform.eProductFamily = IGFX_ICELAKE; GfxPlatform.eRenderCoreFamily = IGFX_GEN11_CORE; AllocateAdapterInfo(); pGfxAdapterInfo->SystemInfo.L3CacheSizeInKb = 3072; pGfxAdapterInfo->SystemInfo.LLCCacheSizeInKb = 2 * 1024; //2 MB pGfxAdapterInfo->SystemInfo.EdramSizeInKb = 128 * 1024; //128 MB const_cast(pGfxAdapterInfo->SkuTable).FtrEDram = 1; CommonULT::SetUpTestCase(); printf("%s\n", __FUNCTION__); } ///////////////////////////////////////////////////////////////////////////////////// /// cleans up once all the tests finish execution. It also calls TearDownTestCase /// from CommonULT to destroy global context and others. /// ///////////////////////////////////////////////////////////////////////////////////// void CTestGen11CachePolicy::TearDownTestCase() { printf("%s\n", __FUNCTION__); CommonULT::TearDownTestCase(); } void CTestGen11CachePolicy::CheckL3CachePolicy() { const uint32_t L3_WB_CACHEABLE = 0x3; const uint32_t L3_UNCACHEABLE = 0x1; // Check Usage MOCS index against MOCS settings for(uint32_t Usage = GMM_RESOURCE_USAGE_UNKNOWN; Usage < GMM_RESOURCE_USAGE_MAX; Usage++) { GMM_CACHE_POLICY_ELEMENT ClientRequest = pGmmULTClientContext->GetCachePolicyElement((GMM_RESOURCE_USAGE_TYPE)Usage); uint32_t AssignedMocsIdx = ClientRequest.MemoryObjectOverride.Gen11.Index; GMM_CACHE_POLICY_TBL_ELEMENT Mocs = pGmmULTClientContext->GetCachePolicyTlbElement(AssignedMocsIdx); EXPECT_EQ(0, Mocs.L3.ESC) << "Usage# " << Usage << ": ESC is non-zero"; EXPECT_EQ(0, Mocs.L3.SCC) << "Usage# " << Usage << ": SCC is non-zero"; EXPECT_EQ(0, Mocs.L3.Reserved) << "Usage# " << Usage << ": Reserved field is non-zero"; // Check if Mocs Index is not greater than GMM_GEN9_MAX_NUMBER_MOCS_INDEXES EXPECT_GT(GMM_MAX_NUMBER_MOCS_INDEXES, AssignedMocsIdx) << "Usage# " << Usage << ": MOCS Index greater than MAX allowed (62)"; // Check of assigned Index setting is appropriate for HDCL1 setting if(ClientRequest.HDCL1) { EXPECT_GE(AssignedMocsIdx, GMM_GEN10_HDCL1_MOCS_INDEX_START) << "Usage# " << Usage << ": Incorrect Index for HDCL1 setting"; } else { if(Usage == GMM_RESOURCE_USAGE_MOCS_62) { EXPECT_EQ(AssignedMocsIdx, 62) << "Usage# " << Usage << ": Incorrect Index for MOCS62 usage"; } else if(Usage == GMM_RESOURCE_USAGE_L3_EVICTION) { EXPECT_EQ(AssignedMocsIdx, 63) << "Usage# " << Usage << ": Incorrect Index for MOCS63 usage"; } else { EXPECT_LT(AssignedMocsIdx, GMM_GEN10_HDCL1_MOCS_INDEX_START) << "Usage# " << Usage << ": Incorrect Index for HDCL1 setting"; } } if(ClientRequest.L3) { EXPECT_EQ(L3_WB_CACHEABLE, Mocs.L3.Cacheability) << "Usage# " << Usage << ": Incorrect L3 cachebility setting"; } else { EXPECT_EQ(L3_UNCACHEABLE, Mocs.L3.Cacheability) << "Usage# " << Usage << ": Incorrect L3 cachebility setting"; } } } TEST_F(CTestGen11CachePolicy, TestL3CachePolicy) { CheckL3CachePolicy(); } void CTestGen11CachePolicy::CheckLlcEdramCachePolicy() { const uint32_t TargetCache_LLC = 1; const uint32_t LeCC_UNCACHEABLE = 0x1; const uint32_t LeCC_WB_CACHEABLE = 0x3; const uint32_t LeCC_WT_CACHEABLE = 0x2; // Check Usage MOCS index against MOCS settings for(uint32_t Usage = GMM_RESOURCE_USAGE_UNKNOWN; Usage < GMM_RESOURCE_USAGE_MAX; Usage++) { GMM_CACHE_POLICY_ELEMENT ClientRequest = pGmmULTClientContext->GetCachePolicyElement((GMM_RESOURCE_USAGE_TYPE)Usage); uint32_t AssignedMocsIdx = ClientRequest.MemoryObjectOverride.Gen11.Index; GMM_CACHE_POLICY_TBL_ELEMENT Mocs = pGmmULTClientContext->GetCachePolicyTlbElement(AssignedMocsIdx); // Check for unused fields EXPECT_EQ(0, Mocs.LeCC.AOM) << "Usage# " << Usage << ": AOM is non-zero"; EXPECT_EQ(0, Mocs.LeCC.CoS) << "Usage# " << Usage << ": CoS is non-zero"; EXPECT_EQ(0, Mocs.LeCC.PFM) << "Usage# " << Usage << ": PFM is non-zero"; EXPECT_EQ(0, Mocs.LeCC.SCC) << "Usage# " << Usage << ": SCC is non-zero"; EXPECT_EQ(0, Mocs.LeCC.SCF) << "Usage# " << Usage << ": SCF is non-zero"; EXPECT_EQ(0, Mocs.LeCC.ESC) << "Usage# " << Usage << ": ESC is non-zero"; EXPECT_EQ(0, Mocs.LeCC.Reserved) << "Usage# " << Usage << ": Reserved field is non-zero"; // Check for age EXPECT_EQ(ClientRequest.AGE, Mocs.LeCC.LRUM) << "Usage# " << Usage << ": Incorrect AGE settings"; // Check for Snoop Setting EXPECT_EQ(ClientRequest.SSO, Mocs.LeCC.SelfSnoop) << "Usage# " << Usage << ": Self Snoop is non-zero"; // Check if Mocs Index is not greater than GMM_GEN9_MAX_NUMBER_MOCS_INDEXES EXPECT_GT(GMM_MAX_NUMBER_MOCS_INDEXES, AssignedMocsIdx) << "Usage# " << Usage << ": MOCS Index greater than MAX allowed (62)"; // Check of assigned Index setting is appropriate for HDCL1 setting if(ClientRequest.HDCL1) { EXPECT_GE(AssignedMocsIdx, GMM_GEN10_HDCL1_MOCS_INDEX_START) << "Usage# " << Usage << ": Incorrect Index for HDCL1 setting"; } else { if(Usage == GMM_RESOURCE_USAGE_MOCS_62) { EXPECT_EQ(AssignedMocsIdx, 62) << "Usage# " << Usage << ": Incorrect Index for MOCS62 usage"; } else if(Usage == GMM_RESOURCE_USAGE_L3_EVICTION) { EXPECT_EQ(AssignedMocsIdx, 63) << "Usage# " << Usage << ": Incorrect Index for MOCS63 usage"; } else { EXPECT_LT(AssignedMocsIdx, GMM_GEN10_HDCL1_MOCS_INDEX_START) << "Usage# " << Usage << ": Incorrect Index for HDCL1 setting"; } } if(ClientRequest.LLC) // LLC only { EXPECT_EQ(TargetCache_LLC, Mocs.LeCC.TargetCache) << "Usage# " << Usage << ": Incorrect target cache setting"; EXPECT_EQ(LeCC_WB_CACHEABLE, Mocs.LeCC.Cacheability) << "Usage# " << Usage << ": Incorrect LLC/eDRAM cachebility setting"; } else { EXPECT_EQ(LeCC_UNCACHEABLE, Mocs.LeCC.Cacheability) << "Usage# " << Usage << ": Incorrect LLC cachebility setting"; } } } TEST_F(CTestGen11CachePolicy, TestLlcEdramCachePolicy) { CheckLlcEdramCachePolicy(); } gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/ULT/GmmGen11CachePolicyULT.h000066400000000000000000000027511466655022700247020ustar00rootroot00000000000000/*============================================================================== Copyright(c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ============================================================================*/ #pragma once #include "GmmCachePolicyULT.h" class CTestGen11CachePolicy : public CTestCachePolicy { protected: virtual void CheckL3CachePolicy(); virtual void CheckLlcEdramCachePolicy(); public: static void SetUpTestCase(); static void TearDownTestCase(); }; #pragma once gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/ULT/GmmGen11ResourceULT.cpp000066400000000000000000000733661466655022700246530ustar00rootroot00000000000000/*============================================================================== Copyright(c) 2016 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ============================================================================*/ #include "GmmGen11ResourceULT.h" using namespace std; ///////////////////////////////////////////////////////////////////////////////////// /// Sets up common environment for Resource fixture tests. this is called once per /// test case before executing all tests under resource fixture test case. // It also calls SetupTestCase from CommonULT to initialize global context and others. /// /// @see CTestGen9Resource::SetUpTestCase() /// ///////////////////////////////////////////////////////////////////////////////////// void CTestGen11Resource::SetUpTestCase() { printf("%s\n", __FUNCTION__); GfxPlatform.eProductFamily = IGFX_LAKEFIELD; GfxPlatform.eRenderCoreFamily = IGFX_GEN11_CORE; CommonULT::SetUpTestCase(); } ///////////////////////////////////////////////////////////////////////////////////// /// cleans up once all the tests finish execution. It also calls TearDownTestCase /// from CommonULT to destroy global context and others. /// /// @see CTestGen10Resource::TearDownTestCase() ///////////////////////////////////////////////////////////////////////////////////// void CTestGen11Resource::TearDownTestCase() { printf("%s\n", __FUNCTION__); CommonULT::TearDownTestCase(); } /// @brief ULT for 2D TileYs Resource TEST_F(CTestGen11Resource, TestPlanar2D_NV12_MediaCompressed) { /* Test planar surface with hybrid UV planes where UV plane is half the size of Y and U/V data is packed together */ // YYYYYYYY // YYYYYYYY // YYYYYYYY // YYYYYYYY // [UV-Packing] // YccsYccsYccs // YccsYccsYccs // UVccsUVccsUVccs // UVccsUVccsUVccs const uint32_t TileSize[2] = {128, 32}; // TileY GMM_RESCREATE_PARAMS gmmParams = {}; gmmParams.Type = RESOURCE_2D; gmmParams.NoGfxMemory = 1; gmmParams.Flags.Gpu.MMC = 1; gmmParams.Flags.Gpu.Texture = 1; gmmParams.Flags.Gpu.UnifiedAuxSurface = 1; gmmParams.Flags.Info.TiledY = 1; gmmParams.BaseWidth64 = 0x2048; //8264 gmmParams.BaseHeight = 0x274; // 628 gmmParams.Depth = 0x1; SetTileFlag(gmmParams, static_cast(TEST_TILEY)); gmmParams.Format = GMM_FORMAT_NV12; GMM_RESOURCE_INFO *ResourceInfo; //__debugbreak(); ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); uint32_t Pitch = GMM_ULT_ALIGN(gmmParams.BaseWidth64, TileSize[0]); uint32_t Height = GMM_ULT_ALIGN(gmmParams.BaseHeight, TileSize[1]) + GMM_ULT_ALIGN(gmmParams.BaseHeight / 2, TileSize[1]); uint32_t Size = GMM_ULT_ALIGN(Pitch * Height, GMM_KBYTE(4)); VerifyResourcePitch(ResourceInfo, Pitch); VerifyResourcePitchInTiles(ResourceInfo, Pitch / TileSize[0]); VerifyResourceSize(ResourceInfo, Size); VerifyResourceHAlign(ResourceInfo, 0); // Same as any other 2D surface -- tested elsewhere VerifyResourceVAlign(ResourceInfo, 0); // Same as any other 2D surface -- tested elsewhere VerifyResourceQPitch(ResourceInfo, 0); // N/A for planar // Y plane should be at 0,0 EXPECT_EQ(0, ResourceInfo->GetPlanarXOffset(GMM_PLANE_Y)); EXPECT_EQ(0, ResourceInfo->GetPlanarYOffset(GMM_PLANE_Y)); // U/V plane should be at end of Y plane EXPECT_EQ(0, ResourceInfo->GetPlanarXOffset(GMM_PLANE_U)); EXPECT_EQ(GMM_ULT_ALIGN(gmmParams.BaseHeight, TileSize[1]), ResourceInfo->GetPlanarYOffset(GMM_PLANE_U)); EXPECT_EQ(0, ResourceInfo->GetPlanarXOffset(GMM_PLANE_V)); EXPECT_EQ(GMM_ULT_ALIGN(gmmParams.BaseHeight, TileSize[1]), ResourceInfo->GetPlanarYOffset(GMM_PLANE_U)); EXPECT_EQ(GMM_ULT_ALIGN(gmmParams.BaseHeight, TileSize[1]), ResourceInfo->GetPlanarYOffset(GMM_PLANE_V)); // Y Plane CCS should be at the end of NV12 surface. EXPECT_EQ(Size, ResourceInfo->GetUnifiedAuxSurfaceOffset(GMM_AUX_CCS)); EXPECT_EQ(Size, ResourceInfo->GetUnifiedAuxSurfaceOffset(GMM_AUX_Y_CCS)); // UV Plane CCS offset uint32_t YCcsSize = GMM_ULT_ALIGN(((GMM_ULT_ALIGN(gmmParams.BaseHeight, TileSize[1]) * Pitch) / 1024), PAGE_SIZE); EXPECT_EQ(Size + YCcsSize, ResourceInfo->GetUnifiedAuxSurfaceOffset(GMM_AUX_UV_CCS)); uint32_t UVCcsSize = GMM_ULT_ALIGN((Height - GFX_ALIGN(gmmParams.BaseHeight, TileSize[1])) * Pitch / 1024, PAGE_SIZE); uint32_t MediaStateOffset = Size + YCcsSize + UVCcsSize; EXPECT_EQ(MediaStateOffset, ResourceInfo->GetUnifiedAuxSurfaceOffset(GMM_AUX_COMP_STATE)); pGmmULTClientContext->DestroyResInfoObject(ResourceInfo); } TEST_F(CTestGen11Resource, TestPlanar2D_NV12_MediaCompressedArray) { /* Test planar surface with hybrid UV planes where UV plane is half the size of Y and U/V data is packed together */ // YYYYYYYY // YYYYYYYY // YYYYYYYY // YYYYYYYY // [UV-Packing] // YccsYccsYccs // YccsYccsYccs // UVccsUVccsUVccs // UVccsUVccsUVccs // ... const uint32_t TileSize[2] = {128, 32}; // TileY GMM_RESCREATE_PARAMS gmmParams = {}; gmmParams.Type = RESOURCE_2D; gmmParams.NoGfxMemory = 1; gmmParams.Flags.Gpu.MMC = 1; gmmParams.Flags.Gpu.Texture = 1; gmmParams.Flags.Gpu.UnifiedAuxSurface = 1; gmmParams.Flags.Info.TiledY = 1; gmmParams.BaseWidth64 = 0x2048; gmmParams.BaseHeight = 0x274; gmmParams.Depth = 0x1; gmmParams.ArraySize = 20; SetTileFlag(gmmParams, static_cast(TEST_TILEY)); gmmParams.Format = GMM_FORMAT_NV12; GMM_RESOURCE_INFO *ResourceInfo; //__debugbreak(); ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); uint32_t Pitch = GMM_ULT_ALIGN(gmmParams.BaseWidth64, TileSize[0]); uint32_t Height = GMM_ULT_ALIGN(gmmParams.BaseHeight, TileSize[1]) + GMM_ULT_ALIGN(gmmParams.BaseHeight / 2, TileSize[1]); uint32_t Size = GMM_ULT_ALIGN(Pitch * Height, GMM_KBYTE(4)) * gmmParams.ArraySize; VerifyResourcePitch(ResourceInfo, Pitch); VerifyResourcePitchInTiles(ResourceInfo, Pitch / TileSize[0]); VerifyResourceSize(ResourceInfo, Size); VerifyResourceHAlign(ResourceInfo, 0); // Same as any other 2D surface -- tested elsewhere VerifyResourceVAlign(ResourceInfo, 0); // Same as any other 2D surface -- tested elsewhere VerifyResourceQPitch(ResourceInfo, 0); // N/A for planar // Y plane should be at 0,0 EXPECT_EQ(0, ResourceInfo->GetPlanarXOffset(GMM_PLANE_Y)); EXPECT_EQ(0, ResourceInfo->GetPlanarYOffset(GMM_PLANE_Y)); // U/V plane should be at end of Y plane EXPECT_EQ(0, ResourceInfo->GetPlanarXOffset(GMM_PLANE_U)); EXPECT_EQ(GMM_ULT_ALIGN(gmmParams.BaseHeight, TileSize[1]), ResourceInfo->GetPlanarYOffset(GMM_PLANE_U)); EXPECT_EQ(0, ResourceInfo->GetPlanarXOffset(GMM_PLANE_V)); EXPECT_EQ(GMM_ULT_ALIGN(gmmParams.BaseHeight, TileSize[1]), ResourceInfo->GetPlanarYOffset(GMM_PLANE_U)); EXPECT_EQ(GMM_ULT_ALIGN(gmmParams.BaseHeight, TileSize[1]), ResourceInfo->GetPlanarYOffset(GMM_PLANE_V)); // Y Plane CCS should be at the end of NV12 surface. EXPECT_EQ(Size, ResourceInfo->GetUnifiedAuxSurfaceOffset(GMM_AUX_CCS)); EXPECT_EQ(Size, ResourceInfo->GetUnifiedAuxSurfaceOffset(GMM_AUX_Y_CCS)); // UV Plane CCS offset uint32_t YCcsSize = GMM_ULT_ALIGN(((GMM_ULT_ALIGN(gmmParams.BaseHeight, TileSize[1]) * Pitch) / 1024), PAGE_SIZE); EXPECT_EQ(Size + YCcsSize, ResourceInfo->GetUnifiedAuxSurfaceOffset(GMM_AUX_UV_CCS)); uint32_t UVCcsSize = GMM_ULT_ALIGN((Height - GFX_ALIGN(gmmParams.BaseHeight, TileSize[1])) * Pitch / 1024, PAGE_SIZE); uint32_t MediaStateOffset = Size + YCcsSize + UVCcsSize; EXPECT_EQ(MediaStateOffset, ResourceInfo->GetUnifiedAuxSurfaceOffset(GMM_AUX_COMP_STATE)); uint32_t AuxSize = YCcsSize + UVCcsSize + PAGE_SIZE; EXPECT_EQ(AuxSize * gmmParams.ArraySize, ResourceInfo->GetSizeAuxSurface(GMM_AUX_CCS)); for(int i = 0; i < gmmParams.ArraySize; i++) { EXPECT_EQ(Size + AuxSize * i, ResourceInfo->GetPlanarAuxOffset(i, GMM_AUX_Y_CCS)); EXPECT_EQ(Size + (AuxSize * i) + YCcsSize, ResourceInfo->GetPlanarAuxOffset(i, GMM_AUX_UV_CCS)); EXPECT_EQ(Size + (AuxSize * i) + (YCcsSize + UVCcsSize), ResourceInfo->GetPlanarAuxOffset(i, GMM_AUX_COMP_STATE)); } pGmmULTClientContext->DestroyResInfoObject(ResourceInfo); } /// @brief ULT for 2D TileYf Resource TEST_F(CTestGen11Resource, Test2DTileYfResource) { printf("%s\n", __FUNCTION__); } /// @brief ULT for Plannar 2D Resource - RGBP TEST_F(CTestGen11Resource, TestPlanar2D_RGBP) { /* Test planar surfaces where all planes are full-sized */ // YYYYYYYY // YYYYYYYY // YYYYYYYY // YYYYYYYY // UUUUUUUU // UUUUUUUU // UUUUUUUU // UUUUUUUU // VVVVVVVV // VVVVVVVV // VVVVVVVV // VVVVVVVV const TEST_TILE_TYPE TileTypes[] = {TEST_LINEAR, TEST_TILEX, TEST_TILEY}; const uint32_t PlaneRowAlignment = 16; const uint32_t TileSize[3][2] = {{1, 1}, //Linear {512, 8}, // TileX {128, 32}}; // TileY for(uint32_t TileIndex = 0; TileIndex < sizeof(TileTypes) / sizeof(TileTypes[0]); TileIndex++) { TEST_TILE_TYPE Tile = TileTypes[TileIndex]; GMM_RESCREATE_PARAMS gmmParams = {}; gmmParams.Type = RESOURCE_2D; gmmParams.NoGfxMemory = 1; gmmParams.Flags.Gpu.Texture = 1; gmmParams.BaseWidth64 = 0x101; gmmParams.BaseHeight = 0x101; gmmParams.Depth = 0x1; SetTileFlag(gmmParams, static_cast(Tile)); gmmParams.Format = GMM_FORMAT_RGBP; GMM_RESOURCE_INFO *ResourceInfo; ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); uint32_t Pitch, Height; if(Tile != TEST_LINEAR) { Pitch = GMM_ULT_ALIGN(gmmParams.BaseWidth64, TileSize[TileIndex][0]); //Since Tile alignment factor is greater than GMM_IMCx_PLANE_ROW_ALIGNMENT=16 Height = GMM_ULT_ALIGN(gmmParams.BaseHeight, PlaneRowAlignment); Height = GMM_ULT_ALIGN(Height, TileSize[TileIndex][1]) * 3 /*Y, U, V*/; } else { Pitch = GMM_ULT_ALIGN(gmmParams.BaseWidth64, GMM_BYTES(64)); Height = gmmParams.BaseHeight * 3 /*Y, U, V*/; } uint32_t Size = GMM_ULT_ALIGN(Pitch * Height, GMM_KBYTE(4)); VerifyResourcePitch(ResourceInfo, Pitch); if(Tile != TEST_LINEAR) { VerifyResourcePitchInTiles(ResourceInfo, Pitch / TileSize[TileIndex][0]); } VerifyResourceSize(ResourceInfo, Size); VerifyResourceHAlign(ResourceInfo, 0); // Same as any other 2D surface -- tested elsewhere VerifyResourceVAlign(ResourceInfo, 0); // Same as any other 2D surface -- tested elsewhere VerifyResourceQPitch(ResourceInfo, 0); // N/A for planar // Y plane should be at 0,0 EXPECT_EQ(0, ResourceInfo->GetPlanarXOffset(GMM_PLANE_Y)); EXPECT_EQ(0, ResourceInfo->GetPlanarYOffset(GMM_PLANE_Y)); // U plane should be at end of Y plane EXPECT_EQ(0, ResourceInfo->GetPlanarXOffset(GMM_PLANE_U)); EXPECT_EQ(Height / 3, ResourceInfo->GetPlanarYOffset(GMM_PLANE_U)); // V plane should be at end of U plane EXPECT_EQ(0, ResourceInfo->GetPlanarXOffset(GMM_PLANE_V)); EXPECT_EQ(2 * (Height / 3), ResourceInfo->GetPlanarYOffset(GMM_PLANE_V)); pGmmULTClientContext->DestroyResInfoObject(ResourceInfo); } } /// @brief ULT for Plannar 2D Resource - RGBP TEST_F(CTestGen11Resource, TestPlanar2DCustom_RGBP) { /* Test planar surfaces where all planes are full-sized */ // YYYYYYYY // YYYYYYYY // YYYYYYYY // YYYYYYYY // UUUUUUUU // UUUUUUUU // UUUUUUUU // UUUUUUUU // VVVVVVVV // VVVVVVVV // VVVVVVVV // VVVVVVVV const TEST_TILE_TYPE TileTypes[] = {TEST_LINEAR, TEST_TILEX, TEST_TILEY}; const uint32_t PlaneRowAlignment = 16; const uint32_t TileSize[3][2] = {{1, 1}, //Linear {512, 8}, // TileX {128, 32}}; // TileY for(uint32_t TileIndex = 0; TileIndex < sizeof(TileTypes) / sizeof(TileTypes[0]); TileIndex++) { TEST_TILE_TYPE Tile = TileTypes[TileIndex]; GMM_RESCREATE_CUSTOM_PARAMS gmmParams = {}; gmmParams.Type = RESOURCE_2D; gmmParams.Flags.Gpu.Texture = 1; gmmParams.BaseWidth64 = 0x101; gmmParams.BaseHeight = GMM_ULT_ALIGN(0x101, PlaneRowAlignment); SetTileFlag_Custom(gmmParams, static_cast(Tile)); gmmParams.Format = GMM_FORMAT_RGBP; uint32_t Pitch, Height; Pitch = GMM_ULT_ALIGN(gmmParams.BaseWidth64, GMM_BYTES(64)); Height = GMM_ULT_ALIGN(gmmParams.BaseHeight, PlaneRowAlignment /* min16 rows*/) * 3 /*Y, U, V*/; uint32_t Size = Pitch * Height; gmmParams.Pitch = Pitch; gmmParams.Size = Size; gmmParams.PlaneOffset.X[GMM_PLANE_Y] = 0; gmmParams.PlaneOffset.Y[GMM_PLANE_Y] = 0; gmmParams.PlaneOffset.X[GMM_PLANE_U] = 0; gmmParams.PlaneOffset.Y[GMM_PLANE_U] = Height / 3; gmmParams.PlaneOffset.X[GMM_PLANE_V] = 0; gmmParams.PlaneOffset.Y[GMM_PLANE_V] = 2 * (Height / 3); gmmParams.NoOfPlanes = 3; GMM_RESOURCE_INFO *ResourceInfo; ResourceInfo = pGmmULTClientContext->CreateCustomResInfoObject(&gmmParams); VerifyResourcePitch(ResourceInfo, Pitch); if(Tile != TEST_LINEAR) { VerifyResourcePitchInTiles(ResourceInfo, Pitch / TileSize[TileIndex][0]); } VerifyResourceSize(ResourceInfo, Size); VerifyResourceHAlign(ResourceInfo, 0); // Same as any other 2D surface -- tested elsewhere VerifyResourceVAlign(ResourceInfo, 0); // Same as any other 2D surface -- tested elsewhere VerifyResourceQPitch(ResourceInfo, 0); // N/A for planar // Y plane should be at 0,0 EXPECT_EQ(0, ResourceInfo->GetPlanarXOffset(GMM_PLANE_Y)); EXPECT_EQ(0, ResourceInfo->GetPlanarYOffset(GMM_PLANE_Y)); // U plane should be at end of Y plane EXPECT_EQ(0, ResourceInfo->GetPlanarXOffset(GMM_PLANE_U)); EXPECT_EQ(Height / 3, ResourceInfo->GetPlanarYOffset(GMM_PLANE_U)); // V plane should be at end of U plane EXPECT_EQ(0, ResourceInfo->GetPlanarXOffset(GMM_PLANE_V)); EXPECT_EQ(2 * (Height / 3), ResourceInfo->GetPlanarYOffset(GMM_PLANE_V)); pGmmULTClientContext->DestroyResInfoObject(ResourceInfo); } } /// @brief ULT for Plannar 2D Resource - MFX_JPEG_YUV422V , IMC1, IMC3 TEST_F(CTestGen11Resource, TestPlanar2D_MFX_JPEG_YUV422V) { /* Test planar surfaces where both U and V are half the size of Y */ // YYYYYYYY // YYYYYYYY // YYYYYYYY // YYYYYYYY // UUUUUUUU // UUUUUUUU // VVVVVVVV // VVVVVVVV const TEST_TILE_TYPE TileTypes[] = {TEST_LINEAR, TEST_TILEX, TEST_TILEY}; const uint32_t PlaneRowAlignment = 16; const uint32_t TileSize[3][2] = {{1, 1}, //Linear {512, 8}, // TileX {128, 32}}; // TileY for(uint32_t TileIndex = 0; TileIndex < sizeof(TileTypes) / sizeof(TileTypes[0]); TileIndex++) { TEST_TILE_TYPE Tile = TileTypes[TileIndex]; GMM_RESCREATE_PARAMS gmmParams = {}; gmmParams.Type = RESOURCE_2D; gmmParams.NoGfxMemory = 1; gmmParams.Flags.Gpu.Texture = 1; gmmParams.BaseWidth64 = 0x101; gmmParams.BaseHeight = 0x101; gmmParams.Depth = 0x1; SetTileFlag(gmmParams, static_cast(Tile)); gmmParams.Format = GMM_FORMAT_MFX_JPEG_YUV422V; GMM_RESOURCE_INFO *ResourceInfo; ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); uint32_t Pitch, Height; uint32_t YHeight, VHeight; if(Tile != TEST_LINEAR) { Pitch = GMM_ULT_ALIGN(gmmParams.BaseWidth64, TileSize[TileIndex][0]); YHeight = GMM_ULT_ALIGN(gmmParams.BaseHeight, PlaneRowAlignment); YHeight = GMM_ULT_ALIGN(YHeight, TileSize[TileIndex][1]); VHeight = GMM_ULT_ALIGN(GMM_ULT_ALIGN(gmmParams.BaseHeight, 2) / 2, PlaneRowAlignment); VHeight = GMM_ULT_ALIGN(VHeight, TileSize[TileIndex][1]); } else { Pitch = GMM_ULT_ALIGN(gmmParams.BaseWidth64, GMM_BYTES(64)); YHeight = GMM_ULT_ALIGN(gmmParams.BaseHeight, PlaneRowAlignment); VHeight = GMM_ULT_ALIGN(GMM_ULT_ALIGN(gmmParams.BaseHeight, 2) / 2, PlaneRowAlignment); } Height = YHeight + 2 * VHeight; uint32_t Size = GMM_ULT_ALIGN(Pitch * Height, GMM_KBYTE(4)); VerifyResourcePitch(ResourceInfo, Pitch); if(Tile != TEST_LINEAR) { VerifyResourcePitchInTiles(ResourceInfo, Pitch / TileSize[TileIndex][0]); } VerifyResourceSize(ResourceInfo, Size); VerifyResourceHAlign(ResourceInfo, 0); // Same as any other 2D surface -- tested elsewhere VerifyResourceVAlign(ResourceInfo, 0); // Same as any other 2D surface -- tested elsewhere VerifyResourceQPitch(ResourceInfo, 0); // N/A for planar // Y plane should be at 0,0 EXPECT_EQ(0, ResourceInfo->GetPlanarXOffset(GMM_PLANE_Y)); EXPECT_EQ(0, ResourceInfo->GetPlanarYOffset(GMM_PLANE_Y)); // U plane should be at end of Y plane EXPECT_EQ(0, ResourceInfo->GetPlanarXOffset(GMM_PLANE_U)); EXPECT_EQ(YHeight, ResourceInfo->GetPlanarYOffset(GMM_PLANE_U)); // V plane should be at end of U plane EXPECT_EQ(0, ResourceInfo->GetPlanarXOffset(GMM_PLANE_V)); EXPECT_EQ(YHeight + VHeight, ResourceInfo->GetPlanarYOffset(GMM_PLANE_V)); pGmmULTClientContext->DestroyResInfoObject(ResourceInfo); } } /// @brief ULT for Plannar 2D Resource - MFX_JPEG_YUV411R TEST_F(CTestGen11Resource, TestPlanar2D_MFX_JPEG_YUV411R) { /* Test planar surfaces where both U and V are quarter the size of Y */ //YYYYYYYY //YYYYYYYY //YYYYYYYY //YYYYYYYY //UUUUUUUU //VVVVVVVV const TEST_TILE_TYPE TileTypes[] = {TEST_LINEAR, TEST_TILEX, TEST_TILEY}; const uint32_t PlaneRowAlignment = 16; const uint32_t TileSize[3][2] = {{1, 1}, //Linear {512, 8}, // TileX {128, 32}}; // TileY for(uint32_t TileIndex = 0; TileIndex < sizeof(TileTypes) / sizeof(TileTypes[0]); TileIndex++) { TEST_TILE_TYPE Tile = TileTypes[TileIndex]; GMM_RESCREATE_PARAMS gmmParams = {}; gmmParams.Type = RESOURCE_2D; gmmParams.NoGfxMemory = 1; gmmParams.Flags.Gpu.Texture = 1; gmmParams.BaseWidth64 = 0x101; gmmParams.BaseHeight = 0x101; gmmParams.Depth = 0x1; SetTileFlag(gmmParams, static_cast(Tile)); gmmParams.Format = GMM_FORMAT_MFX_JPEG_YUV411R_TYPE; GMM_RESOURCE_INFO *ResourceInfo; ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); uint32_t Pitch, Height; uint32_t YHeight, VHeight; if(Tile != TEST_LINEAR) { Pitch = GMM_ULT_ALIGN(gmmParams.BaseWidth64, TileSize[TileIndex][0]); YHeight = GMM_ULT_ALIGN(gmmParams.BaseHeight, PlaneRowAlignment); YHeight = GMM_ULT_ALIGN(YHeight, TileSize[TileIndex][1]); VHeight = GMM_ULT_ALIGN(GMM_ULT_ALIGN(gmmParams.BaseHeight, 4) / 4, PlaneRowAlignment); VHeight = GMM_ULT_ALIGN(VHeight, TileSize[TileIndex][1]); } else { Pitch = GMM_ULT_ALIGN(gmmParams.BaseWidth64, GMM_BYTES(64)); YHeight = GMM_ULT_ALIGN(gmmParams.BaseHeight, PlaneRowAlignment); VHeight = GMM_ULT_ALIGN(GMM_ULT_ALIGN(gmmParams.BaseHeight, 4) / 4, PlaneRowAlignment); } Height = YHeight + 2 * VHeight; uint32_t Size = GMM_ULT_ALIGN(Pitch * Height, GMM_KBYTE(4)); VerifyResourcePitch(ResourceInfo, Pitch); if(Tile != TEST_LINEAR) { VerifyResourcePitchInTiles(ResourceInfo, Pitch / TileSize[TileIndex][0]); } VerifyResourceSize(ResourceInfo, Size); VerifyResourceHAlign(ResourceInfo, 0); // Same as any other 2D surface -- tested elsewhere VerifyResourceVAlign(ResourceInfo, 0); // Same as any other 2D surface -- tested elsewhere VerifyResourceQPitch(ResourceInfo, 0); // N/A for planar // Y plane should be at 0,0 EXPECT_EQ(0, ResourceInfo->GetPlanarXOffset(GMM_PLANE_Y)); EXPECT_EQ(0, ResourceInfo->GetPlanarYOffset(GMM_PLANE_Y)); // U plane should be at end of Y plane EXPECT_EQ(0, ResourceInfo->GetPlanarXOffset(GMM_PLANE_U)); EXPECT_EQ(YHeight, ResourceInfo->GetPlanarYOffset(GMM_PLANE_U)); // V plane should be at end of U plane EXPECT_EQ(0, ResourceInfo->GetPlanarXOffset(GMM_PLANE_V)); EXPECT_EQ(YHeight + VHeight, ResourceInfo->GetPlanarYOffset(GMM_PLANE_V)); pGmmULTClientContext->DestroyResInfoObject(ResourceInfo); } } /// @brief ULT for Plannar 2D Resource - NV12 TEST_F(CTestGen11Resource, TestPlanar2D_NV12) { /* Test planar surface with hybrid UV planes where UV plane is half the size of Y and U/V data is packed together */ // YYYYYYYY // YYYYYYYY // YYYYYYYY // YYYYYYYY // [UV-Packing] const TEST_TILE_TYPE TileTypes[] = {TEST_LINEAR, TEST_TILEX, TEST_TILEY}; const uint32_t TileSize[3][2] = {{1, 1}, //Linear {512, 8}, // TileX {128, 32}}; // TileY for(uint32_t TileIndex = 0; TileIndex < sizeof(TileTypes) / sizeof(TileTypes[0]); TileIndex++) { TEST_TILE_TYPE Tile = TileTypes[TileIndex]; GMM_RESCREATE_PARAMS gmmParams = {}; gmmParams.Type = RESOURCE_2D; gmmParams.NoGfxMemory = 1; gmmParams.Flags.Gpu.Texture = 1; gmmParams.BaseWidth64 = 0x100; gmmParams.BaseHeight = 0x100; gmmParams.Depth = 0x1; SetTileFlag(gmmParams, static_cast(Tile)); gmmParams.Format = GMM_FORMAT_NV12; GMM_RESOURCE_INFO *ResourceInfo; ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); uint32_t Pitch, Height; if(Tile != TEST_LINEAR) { Pitch = GMM_ULT_ALIGN(gmmParams.BaseWidth64, TileSize[TileIndex][0]); Height = GMM_ULT_ALIGN(gmmParams.BaseHeight, TileSize[TileIndex][1]) + GMM_ULT_ALIGN(gmmParams.BaseHeight / 2, TileSize[TileIndex][1]); } else { Pitch = GMM_ULT_ALIGN(gmmParams.BaseWidth64, TileSize[TileIndex][0]); Height = GMM_ULT_ALIGN(gmmParams.BaseHeight /*Y*/ + gmmParams.BaseHeight / 2 /*UV*/, TileSize[TileIndex][1]); } uint32_t Size = GMM_ULT_ALIGN(Pitch * Height, GMM_KBYTE(4)); VerifyResourcePitch(ResourceInfo, Pitch); if(Tile != TEST_LINEAR) { VerifyResourcePitchInTiles(ResourceInfo, Pitch / TileSize[TileIndex][0]); } VerifyResourceSize(ResourceInfo, Size); VerifyResourceHAlign(ResourceInfo, 0); // Same as any other 2D surface -- tested elsewhere VerifyResourceVAlign(ResourceInfo, 0); // Same as any other 2D surface -- tested elsewhere VerifyResourceQPitch(ResourceInfo, 0); // N/A for planar // Y plane should be at 0,0 EXPECT_EQ(0, ResourceInfo->GetPlanarXOffset(GMM_PLANE_Y)); EXPECT_EQ(0, ResourceInfo->GetPlanarYOffset(GMM_PLANE_Y)); // U/V plane should be at end of Y plane EXPECT_EQ(0, ResourceInfo->GetPlanarXOffset(GMM_PLANE_U)); EXPECT_EQ(0, ResourceInfo->GetPlanarXOffset(GMM_PLANE_V)); if(Tile != TEST_LINEAR) { EXPECT_EQ(GMM_ULT_ALIGN(gmmParams.BaseHeight, TileSize[TileIndex][1]), ResourceInfo->GetPlanarYOffset(GMM_PLANE_U)); EXPECT_EQ(GMM_ULT_ALIGN(gmmParams.BaseHeight, TileSize[TileIndex][1]), ResourceInfo->GetPlanarYOffset(GMM_PLANE_V)); } else { EXPECT_EQ(gmmParams.BaseHeight, ResourceInfo->GetPlanarYOffset(GMM_PLANE_U)); EXPECT_EQ(gmmParams.BaseHeight, ResourceInfo->GetPlanarYOffset(GMM_PLANE_V)); } pGmmULTClientContext->DestroyResInfoObject(ResourceInfo); } } /// @brief ULT for Planar 2D Resource - IMC4 TEST_F(CTestGen11Resource, TestPlanar2D_IMC4) { /* Test planar surface V surface is on the right of U */ // YYYYYYYY // YYYYYYYY // YYYYYYYY // YYYYYYYY // UUUUVVVV // UUUUVVVV const TEST_TILE_TYPE TileTypes[] = {TEST_LINEAR, TEST_TILEX, TEST_TILEY}; const uint32_t PlaneRowAlignment = 16; const uint32_t TileSize[3][2] = {{1, 1}, //Linear {512, 8}, // TileX {128, 32}}; // TileY for(uint32_t TileIndex = 0; TileIndex < sizeof(TileTypes) / sizeof(TileTypes[0]); TileIndex++) { TEST_TILE_TYPE Tile = TileTypes[TileIndex]; GMM_RESCREATE_PARAMS gmmParams = {}; gmmParams.Type = RESOURCE_2D; gmmParams.NoGfxMemory = 1; gmmParams.Flags.Gpu.Texture = 1; gmmParams.BaseWidth64 = 0x101; gmmParams.BaseHeight = 0x101; gmmParams.Depth = 0x1; SetTileFlag(gmmParams, static_cast(Tile)); gmmParams.Format = GMM_FORMAT_IMC4; GMM_RESOURCE_INFO *ResourceInfo; ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); uint32_t Pitch, Height; uint32_t YHeight, VHeight; if(Tile != TEST_LINEAR) { Pitch = GMM_ULT_ALIGN(gmmParams.BaseWidth64, TileSize[TileIndex][0]); if(Pitch / TileSize[TileIndex][0] % 2) { Pitch += TileSize[TileIndex][0]; } YHeight = GMM_ULT_ALIGN(gmmParams.BaseHeight, PlaneRowAlignment); VHeight = YHeight / 2; YHeight = GMM_ULT_ALIGN(YHeight, TileSize[TileIndex][1]); VHeight = GMM_ULT_ALIGN(VHeight, TileSize[TileIndex][1]); // No need of PlaneRowAlignment since last plane } else { Pitch = GMM_ULT_ALIGN(gmmParams.BaseWidth64, GMM_BYTES(64)); YHeight = GMM_ULT_ALIGN(gmmParams.BaseHeight, PlaneRowAlignment); VHeight = YHeight / 2; } Height = YHeight + VHeight; uint32_t Size = GMM_ULT_ALIGN(Pitch * Height, GMM_KBYTE(4)); VerifyResourcePitch(ResourceInfo, Pitch); if(Tile != TEST_LINEAR) { VerifyResourcePitchInTiles(ResourceInfo, Pitch / TileSize[TileIndex][0]); } VerifyResourceSize(ResourceInfo, Size); VerifyResourceHAlign(ResourceInfo, 0); // Same as any other 2D surface -- tested elsewhere VerifyResourceVAlign(ResourceInfo, 0); // Same as any other 2D surface -- tested elsewhere VerifyResourceQPitch(ResourceInfo, 0); // N/A for planar // Y plane should be at 0,0 EXPECT_EQ(0, ResourceInfo->GetPlanarXOffset(GMM_PLANE_Y)); EXPECT_EQ(0, ResourceInfo->GetPlanarYOffset(GMM_PLANE_Y)); // U plane should be at end of Y plane // V plane should be at end of U plane EXPECT_EQ(0, ResourceInfo->GetPlanarXOffset(GMM_PLANE_U)); EXPECT_EQ(Pitch / 2, ResourceInfo->GetPlanarXOffset(GMM_PLANE_V)); if(Tile != TEST_LINEAR) { EXPECT_EQ(YHeight, ResourceInfo->GetPlanarYOffset(GMM_PLANE_U)); EXPECT_EQ(YHeight, ResourceInfo->GetPlanarYOffset(GMM_PLANE_V)); } else { EXPECT_EQ(YHeight, ResourceInfo->GetPlanarYOffset(GMM_PLANE_U)); EXPECT_EQ(YHeight, ResourceInfo->GetPlanarYOffset(GMM_PLANE_V)); } pGmmULTClientContext->DestroyResInfoObject(ResourceInfo); } } gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/ULT/GmmGen11ResourceULT.h000066400000000000000000000025731466655022700243100ustar00rootroot00000000000000/*============================================================================== Copyright(c) 2016 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ============================================================================*/ #pragma once #include "GmmGen10ResourceULT.h" class CTestGen11Resource : public CTestGen10Resource { public: static void SetUpTestCase(); static void TearDownTestCase(); };gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/ULT/GmmGen12CachePolicyULT.cpp000066400000000000000000000270071466655022700252370ustar00rootroot00000000000000/*============================================================================== Copyright(c) 2019 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ============================================================================*/ #include "GmmGen12CachePolicyULT.h" using namespace std; ///////////////////////////////////////////////////////////////////////////////////// /// Sets up common environment for Cache Policy fixture tests. this is called once per /// test case before executing all tests under resource fixture test case. /// It also calls SetupTestCase from CommonULT to initialize global context and others. /// ///////////////////////////////////////////////////////////////////////////////////// void CTestGen12CachePolicy::SetUpTestCase() { GfxPlatform.eProductFamily = IGFX_TIGERLAKE_LP; GfxPlatform.eRenderCoreFamily = IGFX_GEN12_CORE; AllocateAdapterInfo(); pGfxAdapterInfo->SystemInfo.L3CacheSizeInKb = 3072; const_cast(pGfxAdapterInfo->SkuTable).FtrEDram = false; const_cast(pGfxAdapterInfo->SkuTable).FtrLLCBypass = 0; CommonULT::SetUpTestCase(); printf("%s\n", __FUNCTION__); } ///////////////////////////////////////////////////////////////////////////////////// /// cleans up once all the tests finish execution. It also calls TearDownTestCase /// from CommonULT to destroy global context and others. /// ///////////////////////////////////////////////////////////////////////////////////// void CTestGen12CachePolicy::TearDownTestCase() { printf("%s\n", __FUNCTION__); CommonULT::TearDownTestCase(); } void CTestGen12CachePolicy::CheckL3CachePolicy() { const uint32_t L3_WB_CACHEABLE = 0x3; const uint32_t L3_UNCACHEABLE = 0x1; // Check Usage MOCS index against MOCS settings for(uint32_t Usage = GMM_RESOURCE_USAGE_UNKNOWN; Usage < GMM_RESOURCE_USAGE_MAX; Usage++) { GMM_CACHE_POLICY_ELEMENT ClientRequest = pGmmULTClientContext->GetCachePolicyElement((GMM_RESOURCE_USAGE_TYPE)Usage); uint32_t AssignedMocsIdx = ClientRequest.MemoryObjectOverride.Gen12.Index; GMM_CACHE_POLICY_TBL_ELEMENT Mocs = pGmmULTClientContext->GetCachePolicyTlbElement(AssignedMocsIdx); //printf("Usage: %d --> Index: [%d]\n", Usage, AssignedMocsIdx); EXPECT_EQ(0, Mocs.L3.ESC) << "Usage# " << Usage << ": ESC is non-zero"; EXPECT_EQ(0, Mocs.L3.SCC) << "Usage# " << Usage << ": SCC is non-zero"; EXPECT_EQ(0, Mocs.L3.Reserved) << "Usage# " << Usage << ": Reserved field is non-zero"; // Check if Mocs Index is not greater than GMM_MAX_NUMBER_MOCS_INDEXES EXPECT_GT(GMM_MAX_NUMBER_MOCS_INDEXES, AssignedMocsIdx) << "Usage# " << Usage << ": MOCS Index greater than MAX allowed (63)"; if(ClientRequest.L3Eviction == 0x2) //63 { if((GMM_RESOURCE_USAGE_TYPE)Usage == GMM_RESOURCE_USAGE_L3_EVICTION) { EXPECT_EQ(AssignedMocsIdx, 63) << "Usage# " << Usage << ": Incorrect Index for L3Eviction type# " << ClientRequest.L3Eviction; EXPECT_EQ(0, ClientRequest.L3) << "Usage# " << Usage << ": Incorrect L3 cacheability for L3Eviction type# " << ClientRequest.L3Eviction; } else { EXPECT_NE(AssignedMocsIdx, 63) << "Usage# " << Usage << ": Incorrect Index for L3Eviction type# " << ClientRequest.L3Eviction; EXPECT_EQ(1, ClientRequest.L3) << "Usage# " << Usage << ": Incorrect L3 cacheability for L3Eviction type# " << ClientRequest.L3Eviction; } } else if(ClientRequest.L3Eviction == 0x3) //61 { EXPECT_EQ(AssignedMocsIdx, 61) << "Usage# " << Usage << ": Incorrect Index for L3Eviction type# " << ClientRequest.L3Eviction; EXPECT_EQ(1, ClientRequest.L3) << "Usage# " << Usage << ": Incorrect L3 cacheability for L3Eviction type# " << ClientRequest.L3Eviction; } else if(Usage == GMM_RESOURCE_USAGE_CCS) //60 { EXPECT_EQ(AssignedMocsIdx, 60) << "Usage# " << Usage << ": Incorrect Index for CCS"; EXPECT_EQ(0, ClientRequest.L3) << "Usage# " << Usage << ": Incorrect L3 cacheability for CCS"; } else if(Usage == GMM_RESOURCE_USAGE_MOCS_62) //62 { EXPECT_EQ(AssignedMocsIdx, 62) << "Usage# " << Usage << ": Incorrect Index for MOCS_62"; EXPECT_EQ(0, ClientRequest.L3) << "Usage# " << Usage << ": Incorrect L3 cacheability for MOCS#62"; } // Check of assigned Index setting is appropriate for HDCL1 setting else if(ClientRequest.HDCL1) { EXPECT_GE(AssignedMocsIdx, GMM_GEN10_HDCL1_MOCS_INDEX_START) << "Usage# " << Usage << ": Incorrect Index for HDCL1 setting"; } else { EXPECT_LT(AssignedMocsIdx, GMM_GEN10_HDCL1_MOCS_INDEX_START) << "Usage# " << Usage << ": Incorrect Index for HDCL1 setting"; } if(ClientRequest.L3) { EXPECT_EQ(L3_WB_CACHEABLE, Mocs.L3.Cacheability) << "Usage# " << Usage << ": Incorrect L3 cachebility setting"; } else { EXPECT_EQ(L3_UNCACHEABLE, Mocs.L3.Cacheability) << "Usage# " << Usage << ": Incorrect L3 cachebility setting"; } } } TEST_F(CTestGen12CachePolicy, TestL3CachePolicy) { CheckL3CachePolicy(); } void CTestGen12CachePolicy::CheckLlcEdramCachePolicy() { const uint32_t TargetCache_LLC = 1; const uint32_t LeCC_UNCACHEABLE = 0x0; const uint32_t LeCC_WC_UNCACHEABLE = 0x1; const uint32_t LeCC_WB_CACHEABLE = 0x3; const uint32_t LeCC_WT_CACHEABLE = 0x2; // Check Usage MOCS index against MOCS settings for(uint32_t Usage = GMM_RESOURCE_USAGE_UNKNOWN; Usage < GMM_RESOURCE_USAGE_MAX; Usage++) { GMM_CACHE_POLICY_ELEMENT ClientRequest = pGmmULTClientContext->GetCachePolicyElement((GMM_RESOURCE_USAGE_TYPE)Usage); uint32_t AssignedMocsIdx = ClientRequest.MemoryObjectOverride.Gen12.Index; GMM_CACHE_POLICY_TBL_ELEMENT Mocs = pGmmULTClientContext->GetCachePolicyTlbElement(AssignedMocsIdx); // Check for unused fields EXPECT_EQ(0, Mocs.LeCC.AOM) << "Usage# " << Usage << ": AOM is non-zero"; EXPECT_EQ(0, Mocs.LeCC.CoS) << "Usage# " << Usage << ": CoS is non-zero"; EXPECT_EQ(0, Mocs.LeCC.PFM) << "Usage# " << Usage << ": PFM is non-zero"; EXPECT_EQ(0, Mocs.LeCC.SCC) << "Usage# " << Usage << ": SCC is non-zero"; // SCF field might be set for LKF/Gen12+ platforms; EXPECT_EQ(0, Mocs.LeCC.SCF & !const_cast(pGfxAdapterInfo->SkuTable).FtrLLCBypass) << "Usage# " << Usage << ": SCF is non-zero"; EXPECT_EQ(0, Mocs.LeCC.ESC) << "Usage# " << Usage << ": ESC is non-zero"; EXPECT_EQ(0, Mocs.LeCC.Reserved) << "Usage# " << Usage << ": Reserved field is non-zero"; // Check for age EXPECT_EQ(ClientRequest.AGE, Mocs.LeCC.LRUM) << "Usage# " << Usage << ": Incorrect AGE settings"; // Check for Snoop Setting EXPECT_EQ(ClientRequest.SSO, Mocs.LeCC.SelfSnoop) << "Usage# " << Usage << ": Self Snoop is non-zero"; // Check if Mocs Index is not greater than GMM_MAX_NUMBER_MOCS_INDEXES EXPECT_GT(GMM_MAX_NUMBER_MOCS_INDEXES, AssignedMocsIdx) << "Usage# " << Usage << ": MOCS Index greater than MAX allowed (63)"; if(ClientRequest.L3Eviction == 0x2) //63 { GMM_CACHE_POLICY_ELEMENT MOCS63 = pGmmULTClientContext->GetCachePolicyElement(GMM_RESOURCE_USAGE_L3_EVICTION); if((GMM_RESOURCE_USAGE_TYPE)Usage == GMM_RESOURCE_USAGE_L3_EVICTION) { EXPECT_EQ(AssignedMocsIdx, 63) << "Usage# " << Usage << ": Incorrect Index for L3Eviction type# " << ClientRequest.L3Eviction; } else { MOCS63.L3 = 1; //Override L3 to test , since Hw forces it to L3-uncached EXPECT_NE(AssignedMocsIdx, 63) << "Usage# " << Usage << ": Incorrect Index for L3Eviction type# " << ClientRequest.L3Eviction; EXPECT_EQ(MOCS63.Value, ClientRequest.Value) << "Usage# " << Usage << ": Incorrect usage for L3Eviction type# " << ClientRequest.L3Eviction; } } else if(ClientRequest.L3Eviction == 0x3) //61 { GMM_CACHE_POLICY_ELEMENT MOCS61 = pGmmULTClientContext->GetCachePolicyElement(GMM_RESOURCE_USAGE_L3_EVICTION_SPECIAL); EXPECT_EQ(AssignedMocsIdx, 61) << "Usage# " << Usage << ": Incorrect Index for L3Eviction type# " << ClientRequest.L3Eviction; EXPECT_EQ(0, ClientRequest.LLC) << "Usage# " << Usage << ": Incorrect LLC cacheability for L3Eviction type# " << ClientRequest.L3Eviction; EXPECT_EQ(MOCS61.Value, ClientRequest.Value) << "Usage# " << Usage << ": Incorrect usage for L3Eviction type# " << ClientRequest.L3Eviction; } else if(Usage == GMM_RESOURCE_USAGE_CCS) //60 { EXPECT_EQ(AssignedMocsIdx, 60) << "Usage# " << Usage << ": Incorrect Index for CCS"; } else if(Usage == GMM_RESOURCE_USAGE_MOCS_62) //62 { EXPECT_EQ(AssignedMocsIdx, 62) << "Usage# " << Usage << ": Incorrect Index for MOCS_62"; } // Check of assigned Index setting is appropriate for HDCL1 setting else if(ClientRequest.HDCL1) { EXPECT_GE(AssignedMocsIdx, GMM_GEN10_HDCL1_MOCS_INDEX_START) << "Usage# " << Usage << ": Incorrect Index for HDCL1 setting"; } else { EXPECT_LT(AssignedMocsIdx, GMM_GEN10_HDCL1_MOCS_INDEX_START) << "Usage# " << Usage << ": Incorrect Index for HDCL1 setting"; } if(!ClientRequest.LLC && !ClientRequest.ELLC) // Uncached { EXPECT_EQ(LeCC_WC_UNCACHEABLE, Mocs.LeCC.Cacheability) << "Usage# " << Usage << ": Incorrect LLC/eDRAM cachebility setting"; } else { if(ClientRequest.LLC) // LLC only { EXPECT_EQ(TargetCache_LLC, Mocs.LeCC.TargetCache) << "Usage# " << Usage << ": Incorrect target cache setting"; EXPECT_EQ(LeCC_WB_CACHEABLE, Mocs.LeCC.Cacheability) << "Usage# " << Usage << ": Incorrect LLC cachebility setting"; } else { EXPECT_EQ(TargetCache_LLC, Mocs.LeCC.TargetCache) << "Usage# " << Usage << ": Incorrect target cache setting"; EXPECT_EQ(LeCC_WC_UNCACHEABLE, Mocs.LeCC.Cacheability) << "Usage# " << Usage << ": Incorrect LLC cachebility setting"; } } } } TEST_F(CTestGen12CachePolicy, TestLlcEdramCachePolicy) { CheckLlcEdramCachePolicy(); } gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/ULT/GmmGen12CachePolicyULT.h000066400000000000000000000027511466655022700247030ustar00rootroot00000000000000/*============================================================================== Copyright(c) 2019 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ============================================================================*/ #pragma once #include "GmmCachePolicyULT.h" class CTestGen12CachePolicy : public CTestCachePolicy { protected: virtual void CheckL3CachePolicy(); virtual void CheckLlcEdramCachePolicy(); public: static void SetUpTestCase(); static void TearDownTestCase(); }; #pragma once gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/ULT/GmmGen12ResourceULT.cpp000066400000000000000000004520171466655022700246460ustar00rootroot00000000000000/*============================================================================== Copyright(c) 2019 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ============================================================================*/ #include "GmmGen12ResourceULT.h" using namespace std; ///////////////////////////////////////////////////////////////////////////////////// /// Sets up common environment for Resource fixture tests. this is called once per /// test case before executing all tests under resource fixture test case. // It also calls SetupTestCase from CommonULT to initialize global context and others. /// /// @see CTestGen12Resource::SetUpTestCase() /// ///////////////////////////////////////////////////////////////////////////////////// void CTestGen12Resource::SetUpTestCase() { printf("%s\n", __FUNCTION__); GfxPlatform.eProductFamily = IGFX_TIGERLAKE_LP; GfxPlatform.eRenderCoreFamily = IGFX_GEN12_CORE; pGfxAdapterInfo = (ADAPTER_INFO *)malloc(sizeof(ADAPTER_INFO)); if(pGfxAdapterInfo) { memset(pGfxAdapterInfo, 0, sizeof(ADAPTER_INFO)); pGfxAdapterInfo->SkuTable.FtrLinearCCS = 1; //legacy y =>0 - test both pGfxAdapterInfo->SkuTable.FtrTileY = 1; pGfxAdapterInfo->SkuTable.FtrLLCBypass = 0; pGfxAdapterInfo->WaTable.WaAuxTable64KGranular= 1; CommonULT::SetUpTestCase(); } } ///////////////////////////////////////////////////////////////////////////////////// /// cleans up once all the tests finish execution. It also calls TearDownTestCase /// from CommonULT to destroy global context and others. /// /// @see CTestGen12Resource::TearDownTestCase() ///////////////////////////////////////////////////////////////////////////////////// void CTestGen12Resource::TearDownTestCase() { printf("%s\n", __FUNCTION__); CommonULT::TearDownTestCase(); } /// @brief ULT for 2D TileYs Compressed Resource /// tests both Separate and Unified CCS allcoation TEST_F(CTestGen12Resource, Test2DTileYsCompressedResource) { const uint32_t HAlign[TEST_BPP_MAX] = {256, 256, 128, 128, 64}; //REM-comment: YS-shape in pixels per-bpp const uint32_t VAlign[TEST_BPP_MAX] = {256, 128, 128, 64, 64}; const uint32_t TileSize[TEST_BPP_MAX][2] = {{256, 256}, //REM-comment: YS-shape in bytes per-bpp {512, 128}, {512, 128}, {1024, 64}, {1024, 64}}; GMM_RESCREATE_PARAMS gmmParams = {}; gmmParams.Type = RESOURCE_2D; gmmParams.NoGfxMemory = 1; gmmParams.Flags.Info.TiledY = 1; gmmParams.Flags.Info.TiledYs = 1; gmmParams.Flags.Gpu.Texture = 1; gmmParams.Flags.Info.RenderCompressed = 1; // Turn on .MC or .RC flag - mandatory to tell compression-type, for Yf its also used to pad surf // to 4x1 tile (reqd by HW for perf reasons) // If unifiedAuxSurf reqd (mandatory for displayable or cross-adapter shared), turn on .CCS/.MMC and .UnifiedAuxSurface too //Allocate 1x1 surface for(uint32_t i = 0; i < TEST_BPP_MAX; i++) { gmmParams.Flags.Gpu.UnifiedAuxSurface = 1; //Turn off for separate aux creation gmmParams.Flags.Gpu.CCS = 1; //Turn off for separate aux creation TEST_BPP bpp = static_cast(i); GMM_TILE_MODE TileMode = DEFINE_TILE(YS_2D, bpp); gmmParams.Format = SetResourceFormat(bpp); gmmParams.BaseWidth64 = 0x1; gmmParams.BaseHeight = 0x1; GMM_RESOURCE_INFO *ResourceInfo; ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); VerifyResourceHAlign(ResourceInfo, HAlign[i]); VerifyResourceVAlign(ResourceInfo, VAlign[i]); VerifyResourcePitch(ResourceInfo, TileSize[i][0]); // As wide as 1 Tile VerifyResourcePitchInTiles(ResourceInfo, 1); // 1 Tile wide VerifyResourceSize(ResourceInfo, GMM_KBYTE(64)); // 1 Tile Big VerifyResourceQPitch(ResourceInfo, 0); // Not Tested //test main surface base alignment is 64KB //For Yf test main surface pitch is 16KB aligned EXPECT_EQ(GMM_KBYTE(64), ResourceInfo->GetBaseAlignment()); //EXPECT_EQ(0, ResourceInfo->GetRenderPitchInTiles() % GMM_KBYTE(16)); // Check on YF only if(const_cast(pGfxAdapterInfo->SkuTable).FtrLinearCCS) { EXPECT_EQ(0, ResourceInfo->GetUnifiedAuxSurfaceOffset(GMM_AUX_CCS) % PAGE_SIZE); EXPECT_GE(ResourceInfo->GetSizeAuxSurface(GMM_AUX_CCS), ResourceInfo->GetSizeMainSurface() >> 8); } else { //Test AuxSurf H/Valign, size etc (Not POR- can be removed) ALIGNMENT UnitAlign; pGmmULTClientContext->GetExtendedTextureAlign(CCS_MODE(TileMode), UnitAlign); EXPECT_EQ(UnitAlign.Width, ResourceInfo->GetAuxHAlign()); EXPECT_EQ(UnitAlign.Height, ResourceInfo->GetAuxVAlign()); EXPECT_EQ(0x80, ResourceInfo->GetUnifiedAuxPitch()); //TileY = 0x80 x 0x20 } EXPECT_EQ(GMM_KBYTE(4), ResourceInfo->GetSizeAuxSurface(GMM_AUX_CCS)); { //separate Aux gmmParams.Flags.Gpu.UnifiedAuxSurface = 0; GMM_RESOURCE_INFO *AuxResourceInfo; AuxResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); EXPECT_EQ(ResourceInfo->GetAuxHAlign(), AuxResourceInfo->GetHAlign()); EXPECT_EQ(ResourceInfo->GetAuxVAlign(), AuxResourceInfo->GetVAlign()); EXPECT_EQ(ResourceInfo->GetUnifiedAuxPitch(), AuxResourceInfo->GetRenderPitch()); EXPECT_EQ(ResourceInfo->GetSizeAuxSurface(GMM_AUX_CCS), AuxResourceInfo->GetSizeAllocation()); pGmmULTClientContext->DestroyResInfoObject(AuxResourceInfo); } pGmmULTClientContext->DestroyResInfoObject(ResourceInfo); } // Allocate surface that requires multi tiles in two dimension // Allocate 2 tiles in X dimension for(uint32_t i = 0; i < TEST_BPP_MAX; i++) { gmmParams.Flags.Gpu.UnifiedAuxSurface = 1; //Turn off for separate aux creation gmmParams.Flags.Gpu.CCS = 1; //Turn off for separate aux creation TEST_BPP bpp = static_cast(i); GMM_TILE_MODE TileMode = DEFINE_TILE(YS_2D, bpp); gmmParams.Format = SetResourceFormat(bpp); gmmParams.BaseWidth64 = (TileSize[i][0] / GetBppValue(bpp)) + 1; // 1 pixel larger than 1 tile width gmmParams.BaseHeight = 0x1; gmmParams.Depth = 0x1; GMM_RESOURCE_INFO *ResourceInfo; ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); VerifyResourceHAlign(ResourceInfo, HAlign[i]); VerifyResourceVAlign(ResourceInfo, VAlign[i]); VerifyResourcePitch(ResourceInfo, TileSize[i][0] * 2); // As wide as 2 tile VerifyResourcePitchInTiles(ResourceInfo, 2); // 2 tile wide VerifyResourceSize(ResourceInfo, GMM_KBYTE(64) * 2); // 2 tile big VerifyResourceQPitch(ResourceInfo, 0); // Not tested //test main surface base alignment is 64KB //For Yf test main surface pitch is 16KB aligned if(const_cast(pGfxAdapterInfo->SkuTable).FtrLinearCCS) { EXPECT_EQ(0, ResourceInfo->GetUnifiedAuxSurfaceOffset(GMM_AUX_CCS) % PAGE_SIZE); EXPECT_GE(ResourceInfo->GetSizeAuxSurface(GMM_AUX_CCS), ResourceInfo->GetSizeMainSurface() >> 8); } else { //Not POR } EXPECT_EQ(GMM_KBYTE(4), ResourceInfo->GetSizeAuxSurface(GMM_AUX_CCS)); { //separate Aux gmmParams.Flags.Gpu.UnifiedAuxSurface = 0; GMM_RESOURCE_INFO *AuxResourceInfo; AuxResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); EXPECT_EQ(ResourceInfo->GetAuxHAlign(), AuxResourceInfo->GetHAlign()); EXPECT_EQ(ResourceInfo->GetAuxVAlign(), AuxResourceInfo->GetVAlign()); EXPECT_EQ(ResourceInfo->GetUnifiedAuxPitch(), AuxResourceInfo->GetRenderPitch()); EXPECT_EQ(ResourceInfo->GetSizeAuxSurface(GMM_AUX_CCS), AuxResourceInfo->GetSizeSurface()); pGmmULTClientContext->DestroyResInfoObject(AuxResourceInfo); } pGmmULTClientContext->DestroyResInfoObject(ResourceInfo); } // Allocate 2 tiles in X/Y dimension for(uint32_t i = 0; i < TEST_BPP_MAX; i++) { gmmParams.Flags.Gpu.UnifiedAuxSurface = 1; //Turn off for separate aux creation gmmParams.Flags.Gpu.CCS = 1; //Turn off for separate aux creation TEST_BPP bpp = static_cast(i); GMM_TILE_MODE TileMode = DEFINE_TILE(YS_2D, bpp); gmmParams.Format = SetResourceFormat(bpp); gmmParams.BaseWidth64 = (TileSize[i][0] / GetBppValue(bpp)) + 1; // 1 pixel larger than 1 tile width gmmParams.BaseHeight = TileSize[i][1] + 1; // 1 row larger than 1 tile height gmmParams.Depth = 0x1; GMM_RESOURCE_INFO *ResourceInfo; ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); //**Not compression specific -BEGIN VerifyResourceHAlign(ResourceInfo, HAlign[i]); VerifyResourceVAlign(ResourceInfo, VAlign[i]); VerifyResourcePitch(ResourceInfo, TileSize[i][0] * 2); // As wide as 2 tile VerifyResourcePitchInTiles(ResourceInfo, 2); // 2 tile wide VerifyResourceSize(ResourceInfo, GMM_KBYTE(64) * 4); // 4 tile big VerifyResourceQPitch(ResourceInfo, 0); // Not tested //**Not compression specific -END if(const_cast(pGfxAdapterInfo->SkuTable).FtrLinearCCS) { EXPECT_EQ(0, ResourceInfo->GetUnifiedAuxSurfaceOffset(GMM_AUX_CCS) % PAGE_SIZE); EXPECT_GE(ResourceInfo->GetSizeAuxSurface(GMM_AUX_CCS), ResourceInfo->GetSizeMainSurface() >> 8); } EXPECT_EQ(GMM_KBYTE(4), ResourceInfo->GetSizeAuxSurface(GMM_AUX_CCS)); { //separate Aux gmmParams.Flags.Gpu.UnifiedAuxSurface = 0; GMM_RESOURCE_INFO *AuxResourceInfo; AuxResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); EXPECT_EQ(ResourceInfo->GetAuxHAlign(), AuxResourceInfo->GetHAlign()); EXPECT_EQ(ResourceInfo->GetAuxVAlign(), AuxResourceInfo->GetVAlign()); EXPECT_EQ(ResourceInfo->GetUnifiedAuxPitch(), AuxResourceInfo->GetRenderPitch()); EXPECT_EQ(ResourceInfo->GetSizeAuxSurface(GMM_AUX_CCS), AuxResourceInfo->GetSizeSurface()); pGmmULTClientContext->DestroyResInfoObject(AuxResourceInfo); } pGmmULTClientContext->DestroyResInfoObject(ResourceInfo); } } /// @brief ULT for 2D TileYf Compressed Resource TEST_F(CTestGen12Resource, Test2DTileYfCompressedResource) { const uint32_t HAlign[TEST_BPP_MAX] = {64, 64, 32, 32, 16}; const uint32_t VAlign[TEST_BPP_MAX] = {64, 32, 32, 16, 16}; const uint32_t TileSize[TEST_BPP_MAX][2] = {{64, 64}, {128, 32}, {128, 32}, {256, 16}, {256, 16}}; GMM_RESCREATE_PARAMS gmmParams = {}; gmmParams.Type = RESOURCE_2D; gmmParams.NoGfxMemory = 1; gmmParams.Flags.Info.TiledY = 1; gmmParams.Flags.Info.TiledYf = 1; gmmParams.Flags.Gpu.Texture = 1; gmmParams.Flags.Info.RenderCompressed = 1; // Turn on .MC or .RC flag - mandatory to tell compression-type, for Yf its also used to pad surf // to 4x1 tile (reqd by HW ) // If unifiedAuxSurf reqd (mandatory for displayable or cross-adapter shared), turn on .CCS/.MMC and .UnifiedAuxSurface too //Allocate 1x1 surface for(uint32_t i = 0; i < TEST_BPP_MAX; i++) { gmmParams.Flags.Gpu.UnifiedAuxSurface = 1; //Turn off for separate aux creation gmmParams.Flags.Gpu.CCS = 1; //Turn off for separate aux creation TEST_BPP bpp = static_cast(i); GMM_TILE_MODE TileMode = DEFINE_TILE(YF_2D, bpp); gmmParams.Format = SetResourceFormat(bpp); gmmParams.BaseWidth64 = 0x1; gmmParams.BaseHeight = 0x1; GMM_RESOURCE_INFO *ResourceInfo; ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); VerifyResourceHAlign(ResourceInfo, HAlign[i]); VerifyResourceVAlign(ResourceInfo, VAlign[i]); VerifyResourcePitch(ResourceInfo, 4 * TileSize[i][0]); // As wide as 4 Tile VerifyResourcePitchInTiles(ResourceInfo, 4); // 4 Tile wide VerifyResourceSize(ResourceInfo, 4 * GMM_KBYTE(4)); // 4 Tile Big VerifyResourceQPitch(ResourceInfo, 0); // Not Tested //test main surface base alignment is 64KB //For Yf/Y test main surface pitch is 4-tileYF/Y aligned EXPECT_EQ(GMM_KBYTE(64), ResourceInfo->GetBaseAlignment()); EXPECT_EQ(0, ResourceInfo->GetRenderPitchTiles() % 4); if(const_cast(pGfxAdapterInfo->SkuTable).FtrLinearCCS) { EXPECT_EQ(0, ResourceInfo->GetUnifiedAuxSurfaceOffset(GMM_AUX_CCS) % PAGE_SIZE); EXPECT_GE(ResourceInfo->GetSizeAuxSurface(GMM_AUX_CCS), ResourceInfo->GetSizeMainSurface() >> 8); } EXPECT_EQ(GMM_KBYTE(4), ResourceInfo->GetSizeAuxSurface(GMM_AUX_CCS)); { //separate Aux gmmParams.Flags.Gpu.UnifiedAuxSurface = 0; GMM_RESOURCE_INFO *AuxResourceInfo; AuxResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); EXPECT_EQ(ResourceInfo->GetAuxHAlign(), AuxResourceInfo->GetHAlign()); EXPECT_EQ(ResourceInfo->GetAuxVAlign(), AuxResourceInfo->GetVAlign()); EXPECT_EQ(ResourceInfo->GetUnifiedAuxPitch(), AuxResourceInfo->GetRenderPitch()); EXPECT_EQ(ResourceInfo->GetSizeAuxSurface(GMM_AUX_CCS), AuxResourceInfo->GetSizeSurface()); pGmmULTClientContext->DestroyResInfoObject(AuxResourceInfo); } pGmmULTClientContext->DestroyResInfoObject(ResourceInfo); } // Allocate surface that requires multi tiles in two dimension // Allocate 2 tiles in X dimension for(uint32_t i = 0; i < TEST_BPP_MAX; i++) { gmmParams.Flags.Gpu.UnifiedAuxSurface = 1; //Turn off for separate aux creation gmmParams.Flags.Gpu.CCS = 1; //Turn off for separate aux creation TEST_BPP bpp = static_cast(i); GMM_TILE_MODE TileMode = DEFINE_TILE(YF_2D, bpp); gmmParams.Format = SetResourceFormat(bpp); gmmParams.BaseWidth64 = (TileSize[i][0] / GetBppValue(bpp)) + 1; // 1 pixel larger than 1 tile width gmmParams.BaseHeight = 0x1; gmmParams.Depth = 0x1; GMM_RESOURCE_INFO *ResourceInfo; ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); VerifyResourceHAlign(ResourceInfo, HAlign[i]); VerifyResourceVAlign(ResourceInfo, VAlign[i]); VerifyResourcePitch(ResourceInfo, TileSize[i][0] * 4); // As wide as 2 tile, but 4-tile pitch alignment VerifyResourcePitchInTiles(ResourceInfo, 4); // 2 tile wide, but 4-tile pitch alignment VerifyResourceSize(ResourceInfo, GMM_KBYTE(4) * 4); // 2 tile big, but 4-tile pitch alignment VerifyResourceQPitch(ResourceInfo, 0); // Not tested //test main surface base alignment is 64KB //For Yf/Y test main surface pitch is 4-tileYF/Y aligned EXPECT_EQ(GMM_KBYTE(64), ResourceInfo->GetBaseAlignment()); EXPECT_EQ(0, ResourceInfo->GetRenderPitchTiles() % 4); if(const_cast(pGfxAdapterInfo->SkuTable).FtrLinearCCS) { EXPECT_EQ(0, ResourceInfo->GetUnifiedAuxSurfaceOffset(GMM_AUX_CCS) % PAGE_SIZE); EXPECT_GE(ResourceInfo->GetSizeAuxSurface(GMM_AUX_CCS), ResourceInfo->GetSizeMainSurface() >> 8); } EXPECT_EQ(GMM_KBYTE(4), ResourceInfo->GetSizeAuxSurface(GMM_AUX_CCS)); { //separate Aux gmmParams.Flags.Gpu.UnifiedAuxSurface = 0; GMM_RESOURCE_INFO *AuxResourceInfo; AuxResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); EXPECT_EQ(ResourceInfo->GetAuxHAlign(), AuxResourceInfo->GetHAlign()); EXPECT_EQ(ResourceInfo->GetAuxVAlign(), AuxResourceInfo->GetVAlign()); EXPECT_EQ(ResourceInfo->GetUnifiedAuxPitch(), AuxResourceInfo->GetRenderPitch()); EXPECT_EQ(ResourceInfo->GetSizeAuxSurface(GMM_AUX_CCS), AuxResourceInfo->GetSizeSurface()); pGmmULTClientContext->DestroyResInfoObject(AuxResourceInfo); } pGmmULTClientContext->DestroyResInfoObject(ResourceInfo); } // Allocate surface that requires multi tiles in two dimension // Allocate 2 tiles in X/Y dimension for(uint32_t i = 0; i < TEST_BPP_MAX; i++) { gmmParams.Flags.Gpu.UnifiedAuxSurface = 1; //Turn off for separate aux creation gmmParams.Flags.Gpu.CCS = 1; //Turn off for separate aux creation TEST_BPP bpp = static_cast(i); GMM_TILE_MODE TileMode = DEFINE_TILE(YF_2D, bpp); gmmParams.Format = SetResourceFormat(bpp); gmmParams.BaseWidth64 = (TileSize[i][0] / GetBppValue(bpp)) + 1; // 1 pixel larger than 1 tile width gmmParams.BaseHeight = TileSize[i][1] + 1; // 1 row larger than 1 tile height gmmParams.Depth = 0x1; GMM_RESOURCE_INFO *ResourceInfo; ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); VerifyResourceHAlign(ResourceInfo, HAlign[i]); VerifyResourceVAlign(ResourceInfo, VAlign[i]); VerifyResourcePitch(ResourceInfo, TileSize[i][0] * 4); // As wide as 2 tile, but 4-tile pitch alignment VerifyResourcePitchInTiles(ResourceInfo, 4); // 2 tile wide, but 4-tile pitch alignment VerifyResourceSize(ResourceInfo, GMM_KBYTE(4) * 4 * 2); // 4 tile wide; and 2-tile high VerifyResourceQPitch(ResourceInfo, 0); // Not tested //test main surface base alignment is 64KB //For Yf/Y test main surface pitch is 4-tileYF/Y aligned EXPECT_EQ(GMM_KBYTE(64), ResourceInfo->GetBaseAlignment()); EXPECT_EQ(0, ResourceInfo->GetRenderPitchTiles() % 4); if(const_cast(pGfxAdapterInfo->SkuTable).FtrLinearCCS) { EXPECT_EQ(0, ResourceInfo->GetUnifiedAuxSurfaceOffset(GMM_AUX_CCS) % PAGE_SIZE); EXPECT_GE(ResourceInfo->GetSizeAuxSurface(GMM_AUX_CCS), ResourceInfo->GetSizeMainSurface() >> 8); } EXPECT_EQ(GMM_KBYTE(4), ResourceInfo->GetSizeAuxSurface(GMM_AUX_CCS)); { //separate Aux gmmParams.Flags.Gpu.UnifiedAuxSurface = 0; GMM_RESOURCE_INFO *AuxResourceInfo; AuxResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); EXPECT_EQ(ResourceInfo->GetAuxHAlign(), AuxResourceInfo->GetHAlign()); EXPECT_EQ(ResourceInfo->GetAuxVAlign(), AuxResourceInfo->GetVAlign()); EXPECT_EQ(ResourceInfo->GetUnifiedAuxPitch(), AuxResourceInfo->GetRenderPitch()); EXPECT_EQ(ResourceInfo->GetSizeAuxSurface(GMM_AUX_CCS), AuxResourceInfo->GetSizeSurface()); pGmmULTClientContext->DestroyResInfoObject(AuxResourceInfo); } pGmmULTClientContext->DestroyResInfoObject(ResourceInfo); } } /// @brief ULT for 2D TileY Compressed Resource TEST_F(CTestGen12Resource, Test2DTileYCompressedResource) { const uint32_t HAlign = {16}; const uint32_t VAlign = {4}; const uint32_t TileSize[2] = {128, 32}; GMM_RESCREATE_PARAMS gmmParams = {}; gmmParams.Type = RESOURCE_2D; gmmParams.NoGfxMemory = 1; gmmParams.Flags.Info.TiledY = 1; gmmParams.Flags.Gpu.Texture = 1; gmmParams.Flags.Info.RenderCompressed = 1; // Turn on .MC or .RC flag - mandatory to tell compression-type, for Yf/Y its also used to pad surf // to 4x1 tile (reqd by HW for perf reasons) // If unifiedAuxSurf reqd (mandatory for displayable or cross-adapter shared), turn on .CCS/.MMC and .UnifiedAuxSurface too //Allocate 1x1 surface for(uint32_t i = 0; i < TEST_BPP_MAX; i++) { gmmParams.Flags.Gpu.UnifiedAuxSurface = 1; //Turn off for separate aux creation gmmParams.Flags.Gpu.CCS = 1; //Turn off for separate aux creation TEST_BPP bpp = static_cast(i); GMM_TILE_MODE TileMode = LEGACY_TILE_Y; gmmParams.Format = SetResourceFormat(bpp); gmmParams.BaseWidth64 = 0x1; gmmParams.BaseHeight = 0x1; GMM_RESOURCE_INFO *ResourceInfo; ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); VerifyResourceHAlign(ResourceInfo, HAlign); VerifyResourceVAlign(ResourceInfo, VAlign); VerifyResourcePitch(ResourceInfo, 4 * TileSize[0]); // As wide as 4 Tile VerifyResourcePitchInTiles(ResourceInfo, 4); // 4 Tile wide VerifyResourceSize(ResourceInfo, 4 * GMM_KBYTE(4)); // 4 Tile Big VerifyResourceQPitch(ResourceInfo, 0); // Not Tested //test main surface base alignment is 64KB //For Yf/Y test main surface pitch is 4-tileYF/Y aligned EXPECT_EQ(GMM_KBYTE(64), ResourceInfo->GetBaseAlignment()); EXPECT_EQ(0, ResourceInfo->GetRenderPitchTiles() % 4); if(const_cast(pGfxAdapterInfo->SkuTable).FtrLinearCCS) { EXPECT_EQ(0, ResourceInfo->GetUnifiedAuxSurfaceOffset(GMM_AUX_CCS) % PAGE_SIZE); EXPECT_GE(ResourceInfo->GetSizeAuxSurface(GMM_AUX_CCS), ResourceInfo->GetSizeMainSurface() >> 8); } EXPECT_EQ(GMM_KBYTE(4), ResourceInfo->GetSizeAuxSurface(GMM_AUX_CCS)); { //separate Aux gmmParams.Flags.Gpu.UnifiedAuxSurface = 0; GMM_RESOURCE_INFO *AuxResourceInfo; AuxResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); EXPECT_EQ(ResourceInfo->GetAuxHAlign(), AuxResourceInfo->GetHAlign()); EXPECT_EQ(ResourceInfo->GetAuxVAlign(), AuxResourceInfo->GetVAlign()); EXPECT_EQ(ResourceInfo->GetUnifiedAuxPitch(), AuxResourceInfo->GetRenderPitch()); EXPECT_EQ(ResourceInfo->GetSizeAuxSurface(GMM_AUX_CCS), AuxResourceInfo->GetSizeSurface()); pGmmULTClientContext->DestroyResInfoObject(AuxResourceInfo); } pGmmULTClientContext->DestroyResInfoObject(ResourceInfo); } // Allocate surface that requires multi tiles in two dimension // Allocate 2 tiles in X dimension for(uint32_t i = 0; i < TEST_BPP_MAX; i++) { gmmParams.Flags.Gpu.UnifiedAuxSurface = 1; //Turn off for separate aux creation gmmParams.Flags.Gpu.CCS = 1; //Turn off for separate aux creation TEST_BPP bpp = static_cast(i); GMM_TILE_MODE TileMode = LEGACY_TILE_Y; gmmParams.Format = SetResourceFormat(bpp); gmmParams.BaseWidth64 = (TileSize[0] / GetBppValue(bpp)) + 1; // 1 pixel larger than 1 tile width gmmParams.BaseHeight = 0x1; gmmParams.Depth = 0x1; GMM_RESOURCE_INFO *ResourceInfo; ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); VerifyResourceHAlign(ResourceInfo, HAlign); VerifyResourceVAlign(ResourceInfo, VAlign); VerifyResourcePitch(ResourceInfo, TileSize[0] * 4); // As wide as 2 tile, but 4-tile pitch alignment VerifyResourcePitchInTiles(ResourceInfo, 4); // 2 tile wide, but 4-tile pitch alignment VerifyResourceSize(ResourceInfo, GMM_KBYTE(4) * 4); // 2 tile big, but 4-tile pitch alignment VerifyResourceQPitch(ResourceInfo, 0); // Not tested //test main surface base alignment is 64KB //For Yf test main surface pitch is 4-tileYF aligned EXPECT_EQ(GMM_KBYTE(64), ResourceInfo->GetBaseAlignment()); EXPECT_EQ(0, ResourceInfo->GetRenderPitchTiles() % 4); // Check on YF only if(const_cast(pGfxAdapterInfo->SkuTable).FtrLinearCCS) { EXPECT_EQ(0, ResourceInfo->GetUnifiedAuxSurfaceOffset(GMM_AUX_CCS) % PAGE_SIZE); EXPECT_GE(ResourceInfo->GetSizeAuxSurface(GMM_AUX_CCS), ResourceInfo->GetSizeMainSurface() >> 8); } EXPECT_EQ(GMM_KBYTE(4), ResourceInfo->GetSizeAuxSurface(GMM_AUX_CCS)); { //separate Aux gmmParams.Flags.Gpu.UnifiedAuxSurface = 0; GMM_RESOURCE_INFO *AuxResourceInfo; AuxResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); EXPECT_EQ(ResourceInfo->GetAuxHAlign(), AuxResourceInfo->GetHAlign()); EXPECT_EQ(ResourceInfo->GetAuxVAlign(), AuxResourceInfo->GetVAlign()); EXPECT_EQ(ResourceInfo->GetUnifiedAuxPitch(), AuxResourceInfo->GetRenderPitch()); EXPECT_EQ(ResourceInfo->GetSizeAuxSurface(GMM_AUX_CCS), AuxResourceInfo->GetSizeSurface()); pGmmULTClientContext->DestroyResInfoObject(AuxResourceInfo); } pGmmULTClientContext->DestroyResInfoObject(ResourceInfo); } // Allocate surface that requires multi tiles in two dimension // Allocate 2 tiles in X/Y dimension for(uint32_t i = 0; i < TEST_BPP_MAX; i++) { gmmParams.Flags.Gpu.UnifiedAuxSurface = 1; //Turn off for separate aux creation gmmParams.Flags.Gpu.CCS = 1; //Turn off for separate aux creation TEST_BPP bpp = static_cast(i); GMM_TILE_MODE TileMode = LEGACY_TILE_Y; gmmParams.Format = SetResourceFormat(bpp); gmmParams.BaseWidth64 = (TileSize[0] / GetBppValue(bpp)) + 1; // 1 pixel larger than 1 tile width gmmParams.BaseHeight = TileSize[1] + 1; // 1 row larger than 1 tile height gmmParams.Depth = 0x1; GMM_RESOURCE_INFO *ResourceInfo; ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); VerifyResourceHAlign(ResourceInfo, HAlign); VerifyResourceVAlign(ResourceInfo, VAlign); VerifyResourcePitch(ResourceInfo, TileSize[0] * 4); // As wide as 2 tile, but 4-tile pitch alignment VerifyResourcePitchInTiles(ResourceInfo, 4); // 2 tile wide, but 4-tile pitch alignment VerifyResourceSize(ResourceInfo, GMM_KBYTE(4) * 4 * 2); // 4 tile wide; and 2-tile high VerifyResourceQPitch(ResourceInfo, 0); // Not tested //test main surface base alignment is 64KB //For Yf/Y test main surface pitch is 4-tileYF/Y aligned EXPECT_EQ(GMM_KBYTE(64), ResourceInfo->GetBaseAlignment()); EXPECT_EQ(0, ResourceInfo->GetRenderPitchTiles() % 4); // Check on YF only if(const_cast(pGfxAdapterInfo->SkuTable).FtrLinearCCS) { EXPECT_EQ(0, ResourceInfo->GetUnifiedAuxSurfaceOffset(GMM_AUX_CCS) % PAGE_SIZE); EXPECT_GE(ResourceInfo->GetSizeAuxSurface(GMM_AUX_CCS), ResourceInfo->GetSizeMainSurface() >> 8); } EXPECT_EQ(GMM_KBYTE(4), ResourceInfo->GetSizeAuxSurface(GMM_AUX_CCS)); { //separate Aux gmmParams.Flags.Gpu.UnifiedAuxSurface = 0; GMM_RESOURCE_INFO *AuxResourceInfo; AuxResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); EXPECT_EQ(ResourceInfo->GetAuxHAlign(), AuxResourceInfo->GetHAlign()); EXPECT_EQ(ResourceInfo->GetAuxVAlign(), AuxResourceInfo->GetVAlign()); EXPECT_EQ(ResourceInfo->GetUnifiedAuxPitch(), AuxResourceInfo->GetRenderPitch()); EXPECT_EQ(ResourceInfo->GetSizeAuxSurface(GMM_AUX_CCS), AuxResourceInfo->GetSizeSurface()); pGmmULTClientContext->DestroyResInfoObject(AuxResourceInfo); } pGmmULTClientContext->DestroyResInfoObject(ResourceInfo); } } /// @brief ULT for 2D TileY lossless Compressed lossy Resource TEST_F(CTestGen12Resource, Test2DTileYLossyCompressedResource) { const uint32_t HAlign = {4}; const uint32_t VAlign = {4}; const uint32_t TileSize[2] = {128, 32}; GMM_RESCREATE_PARAMS gmmParams = {}; gmmParams.Type = RESOURCE_2D; gmmParams.NoGfxMemory = 1; gmmParams.Flags.Info.TiledY = 1; gmmParams.Flags.Gpu.Texture = 1; gmmParams.Flags.Info.RenderCompressed = 1; // Turn on .MC or .RC flag - mandatory to tell compression-type, for Yf its also used to pad surf // to 4x1 tile (reqd by HW for perf reasons) // If unifiedAuxSurf reqd (mandatory for displayable or cross-adapter shared), turn on .CCS/.MMC and .UnifiedAuxSurface too //Allocate 1x1 surface for(uint32_t i = 0; i < TEST_BPP_MAX; i++) { gmmParams.Flags.Gpu.UnifiedAuxSurface = 1; //Turn off for separate aux creation gmmParams.Flags.Gpu.CCS = 1; //Turn off for separate aux creation TEST_BPP bpp = static_cast(i); GMM_TILE_MODE TileMode = LEGACY_TILE_Y; gmmParams.Format = GMM_FORMAT_ETC2_RGB8; gmmParams.BaseWidth64 = 0x80; gmmParams.BaseHeight = 0x20; GMM_RESOURCE_INFO *ResourceInfo; ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); VerifyResourceHAlign(ResourceInfo, HAlign); VerifyResourceVAlign(ResourceInfo, VAlign); VerifyResourcePitch(ResourceInfo, 4 * TileSize[0]); // As wide as 4 Tile VerifyResourcePitchInTiles(ResourceInfo, 4); // 4 Tile wide VerifyResourceSize(ResourceInfo, 4 * GMM_KBYTE(4)); // 4 Tile Big VerifyResourceQPitch(ResourceInfo, 0); // Not Tested //test main surface base alignment is 64KB //For Yf/Y test main surface pitch is 4-tileYF/Y aligned EXPECT_EQ(GMM_KBYTE(64), ResourceInfo->GetBaseAlignment()); EXPECT_EQ(0, ResourceInfo->GetRenderPitchTiles() % 4); if(const_cast(pGfxAdapterInfo->SkuTable).FtrLinearCCS) { EXPECT_EQ(0, ResourceInfo->GetUnifiedAuxSurfaceOffset(GMM_AUX_CCS) % PAGE_SIZE); EXPECT_GE(ResourceInfo->GetSizeAuxSurface(GMM_AUX_CCS), ResourceInfo->GetSizeMainSurface() >> 8); } EXPECT_EQ(GMM_KBYTE(4), ResourceInfo->GetSizeAuxSurface(GMM_AUX_CCS)); { //separate Aux gmmParams.Flags.Gpu.UnifiedAuxSurface = 0; GMM_RESOURCE_INFO *AuxResourceInfo; AuxResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); EXPECT_EQ(ResourceInfo->GetAuxHAlign(), AuxResourceInfo->GetHAlign()); EXPECT_EQ(ResourceInfo->GetAuxVAlign(), AuxResourceInfo->GetVAlign()); EXPECT_EQ(ResourceInfo->GetUnifiedAuxPitch(), AuxResourceInfo->GetRenderPitch()); EXPECT_EQ(ResourceInfo->GetSizeAuxSurface(GMM_AUX_CCS), AuxResourceInfo->GetSizeSurface()); pGmmULTClientContext->DestroyResInfoObject(AuxResourceInfo); } pGmmULTClientContext->DestroyResInfoObject(ResourceInfo); } // Allocate surface that requires multi tiles in two dimension // Allocate 2 tiles in X dimension for(uint32_t i = 0; i < TEST_BPP_MAX; i++) { gmmParams.Flags.Gpu.UnifiedAuxSurface = 1; //Turn off for separate aux creation gmmParams.Flags.Gpu.CCS = 1; //Turn off for separate aux creation TEST_BPP bpp = static_cast(i); GMM_TILE_MODE TileMode = LEGACY_TILE_Y; gmmParams.Format = GMM_FORMAT_ETC2_RGB8; gmmParams.BaseWidth64 = (TileSize[0] / GetBppValue(bpp)) + 1; // 1 pixel larger than 1 tile width gmmParams.BaseHeight = 0x1; gmmParams.Depth = 0x1; GMM_RESOURCE_INFO *ResourceInfo; ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); VerifyResourceHAlign(ResourceInfo, HAlign); VerifyResourceVAlign(ResourceInfo, VAlign); VerifyResourcePitch(ResourceInfo, TileSize[0] * 4); // As wide as 2 tile, but 4-tile pitch alignment VerifyResourcePitchInTiles(ResourceInfo, 4); // 2 tile wide, but 4-tile pitch alignment VerifyResourceSize(ResourceInfo, GMM_KBYTE(4) * 4); // 2 tile big, but 4-tile pitch alignment VerifyResourceQPitch(ResourceInfo, 0); // Not tested //test main surface base alignment is 64KB //For Yf/Y test main surface pitch is 4-tileYF/Y aligned EXPECT_EQ(GMM_KBYTE(64), ResourceInfo->GetBaseAlignment()); EXPECT_EQ(0, ResourceInfo->GetRenderPitchTiles() % 4); if(const_cast(pGfxAdapterInfo->SkuTable).FtrLinearCCS) { EXPECT_EQ(0, ResourceInfo->GetUnifiedAuxSurfaceOffset(GMM_AUX_CCS) % PAGE_SIZE); EXPECT_GE(ResourceInfo->GetSizeAuxSurface(GMM_AUX_CCS), ResourceInfo->GetSizeMainSurface() >> 8); } EXPECT_EQ(GMM_KBYTE(4), ResourceInfo->GetSizeAuxSurface(GMM_AUX_CCS)); { //separate Aux gmmParams.Flags.Gpu.UnifiedAuxSurface = 0; GMM_RESOURCE_INFO *AuxResourceInfo; AuxResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); EXPECT_EQ(ResourceInfo->GetAuxHAlign(), AuxResourceInfo->GetHAlign()); EXPECT_EQ(ResourceInfo->GetAuxVAlign(), AuxResourceInfo->GetVAlign()); EXPECT_EQ(ResourceInfo->GetUnifiedAuxPitch(), AuxResourceInfo->GetRenderPitch()); EXPECT_EQ(ResourceInfo->GetSizeAuxSurface(GMM_AUX_CCS), AuxResourceInfo->GetSizeSurface()); pGmmULTClientContext->DestroyResInfoObject(AuxResourceInfo); } pGmmULTClientContext->DestroyResInfoObject(ResourceInfo); } // Allocate surface that requires multi tiles in two dimension // Allocate 2 tiles in X/Y dimension for(uint32_t i = 0; i < TEST_BPP_MAX; i++) { gmmParams.Flags.Gpu.UnifiedAuxSurface = 1; //Turn off for separate aux creation gmmParams.Flags.Gpu.CCS = 1; //Turn off for separate aux creation TEST_BPP bpp = static_cast(i); GMM_TILE_MODE TileMode = LEGACY_TILE_Y; gmmParams.Format = GMM_FORMAT_ETC2_RGB8; gmmParams.BaseWidth64 = (TileSize[0] / GetBppValue(bpp)) + 1; // 1 pixel larger than 1 tile width gmmParams.BaseHeight = TileSize[1] + 1; // 1 row larger than 1 tile height gmmParams.Depth = 0x1; GMM_RESOURCE_INFO *ResourceInfo; ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); VerifyResourceHAlign(ResourceInfo, HAlign); VerifyResourceVAlign(ResourceInfo, VAlign); VerifyResourcePitch(ResourceInfo, TileSize[0] * 4); // As wide as 2 tile, but 4-tile pitch alignment VerifyResourcePitchInTiles(ResourceInfo, 4); // 2 tile wide, but 4-tile pitch alignment VerifyResourceSize(ResourceInfo, GMM_KBYTE(4) * 4); // 4 tile wide; max compressed height = 0x24/4 = 9, so fits in 1 tile-height VerifyResourceQPitch(ResourceInfo, 0); // Not tested //test main surface base alignment is 64KB //For Yf/Y test main surface pitch is 4-tileYF/Y aligned EXPECT_EQ(GMM_KBYTE(64), ResourceInfo->GetBaseAlignment()); EXPECT_EQ(0, ResourceInfo->GetRenderPitchTiles() % 4); if(const_cast(pGfxAdapterInfo->SkuTable).FtrLinearCCS) { EXPECT_EQ(0, ResourceInfo->GetUnifiedAuxSurfaceOffset(GMM_AUX_CCS) % PAGE_SIZE); EXPECT_GE(ResourceInfo->GetSizeAuxSurface(GMM_AUX_CCS), ResourceInfo->GetSizeMainSurface() >> 8); } EXPECT_EQ(GMM_KBYTE(4), ResourceInfo->GetSizeAuxSurface(GMM_AUX_CCS)); { //separate Aux gmmParams.Flags.Gpu.UnifiedAuxSurface = 0; GMM_RESOURCE_INFO *AuxResourceInfo; AuxResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); EXPECT_EQ(ResourceInfo->GetAuxHAlign(), AuxResourceInfo->GetHAlign()); EXPECT_EQ(ResourceInfo->GetAuxVAlign(), AuxResourceInfo->GetVAlign()); EXPECT_EQ(ResourceInfo->GetUnifiedAuxPitch(), AuxResourceInfo->GetRenderPitch()); EXPECT_EQ(ResourceInfo->GetSizeAuxSurface(GMM_AUX_CCS), AuxResourceInfo->GetSizeSurface()); pGmmULTClientContext->DestroyResInfoObject(AuxResourceInfo); } pGmmULTClientContext->DestroyResInfoObject(ResourceInfo); } } //Y416(64bpp -how is 10/12/16bit depth given?) //Y410(32bpp), Y216(64bpp), YCRCB_NORMAL(16bpp), YCRCB_SWAPUV(16bpp), //YCRCB_SWAPUVY(16bpp), YCRCB_SWAPY(16bpp) /// @brief ULT for Planar Compressed Resource TEST_F(CTestGen12Resource, DISABLED_TestPlanarYfCompressedResource) { const uint32_t TileSize[TEST_BPP_MAX][2] = { {64, 64}, {128, 32}, {128, 32}, {256, 16}, {256, 16}}; // TileYf GMM_RESCREATE_PARAMS gmmParams = {}; gmmParams.Type = RESOURCE_2D; gmmParams.NoGfxMemory = 1; gmmParams.Flags.Gpu.Texture = 1; //gmmParams.Flags.Gpu.MMC = 1; gmmParams.Flags.Gpu.CCS = 1; gmmParams.Flags.Info.MediaCompressed = 1; gmmParams.BaseWidth64 = 0x100; gmmParams.BaseHeight = 0x50; gmmParams.Depth = 0x1; SetTileFlag(gmmParams, TEST_TILEYF); // TileYF only //UV-Packed formats GMM_RESOURCE_FORMAT Format[4] = {GMM_FORMAT_NV12, GMM_FORMAT_NV21, GMM_FORMAT_P010, GMM_FORMAT_P016}; for(auto fmt : Format) { gmmParams.Format = fmt; // 8bpp (NV12, NV21), 16bpp (P016,P010) TEST_BPP Ybpp, UVbpp; //Yf/Ys could be accessed on CPU/app where UV plane bpp is double switch(pGmmULTClientContext->GetPlatformInfo().FormatTable[fmt].Element.BitsPer) { case 8: Ybpp = TEST_BPP_8; UVbpp = TEST_BPP_16; break; case 16: Ybpp = TEST_BPP_16; UVbpp = TEST_BPP_32; break; default: return; } gmmParams.Flags.Gpu.UnifiedAuxSurface = 1; /*Aux is TileY (later Linear), not redescribing, its bytes are allocated using one bpp*/ GMM_TILE_MODE TileMode = DEFINE_TILE(YF_2D, Ybpp); GMM_RESOURCE_INFO *ResourceInfo; ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); //Redescribed Pitch isn't modified unless Y, UV pitch differ //But, original Pitch is padded to have even Tile, hence use Ybpp ExpectedPitch //to verify Pitch, but redescribed size uint32_t ExpectedPitch = GMM_ULT_ALIGN(gmmParams.BaseWidth64 * (int)pow(2.0, Ybpp), TileSize[Ybpp][0] * 4); uint32_t RedescribedPitch = GMM_ULT_ALIGN(gmmParams.BaseWidth64 / 2 * (int)pow(2.0, UVbpp), TileSize[UVbpp][0] * 4); //ExpectedPitch = GMM_ULT_ALIGN(ExpectedPitch, 2 * TileSize[Ybpp][0]); //pad to even tile if(ExpectedPitch != RedescribedPitch) { ExpectedPitch = RedescribedPitch; } VerifyResourcePitch(ResourceInfo, ExpectedPitch); VerifyResourcePitchInTiles(ResourceInfo, ExpectedPitch / TileSize[Ybpp][0]); int YSizeInTiles = (GMM_ULT_ALIGN(gmmParams.BaseHeight, TileSize[Ybpp][1]) / TileSize[Ybpp][1]) * RedescribedPitch / TileSize[Ybpp][0]; int UVSizeInTiles = (GMM_ULT_ALIGN(gmmParams.BaseHeight / 2, TileSize[UVbpp][1]) / TileSize[UVbpp][1]) * RedescribedPitch / TileSize[UVbpp][0]; VerifyResourceSize(ResourceInfo, GMM_KBYTE(4) * (YSizeInTiles + UVSizeInTiles)); VerifyResourceHAlign(ResourceInfo, TileSize[UVbpp][0] / pow(2.0, UVbpp)); // For Yf/Ys planar redescription causes UV width, Y height alignment VerifyResourceVAlign(ResourceInfo, TileSize[Ybpp][1]); VerifyResourceQPitch(ResourceInfo, 0); // N/A for non-mipped surface //test main surface base alignment is 64KB //For Yf test main surface pitch is 4-tileYF aligned EXPECT_EQ(GMM_KBYTE(64), ResourceInfo->GetBaseAlignment()); EXPECT_EQ(0, ResourceInfo->GetRenderPitchTiles() % 4); // Check on YF only if(const_cast(pGfxAdapterInfo->SkuTable).FtrLinearCCS) { EXPECT_EQ(0, ResourceInfo->GetUnifiedAuxSurfaceOffset(GMM_AUX_CCS) % PAGE_SIZE); EXPECT_GE(ResourceInfo->GetSizeAuxSurface(GMM_AUX_CCS), ResourceInfo->GetSizeMainSurface() >> 8); } EXPECT_EQ(GMM_KBYTE(4) * 2, ResourceInfo->GetSizeAuxSurface(GMM_AUX_CCS)); // Y and UV Aux are on separate tiles { //separate Aux gmmParams.Flags.Gpu.UnifiedAuxSurface = 0; GMM_RESOURCE_INFO *AuxResourceInfo; AuxResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); EXPECT_EQ(GMM_KBYTE(4) * 2, AuxResourceInfo->GetSizeSurface()); pGmmULTClientContext->DestroyResInfoObject(AuxResourceInfo); } pGmmULTClientContext->DestroyResInfoObject(ResourceInfo); } } /// @brief ULT for Planar Y Compressed Resource TEST_F(CTestGen12Resource, TestPlanarYCompressedResource) { const uint32_t TileSize[2] = {128, 32}; const uint32_t HAlign = 16; const uint32_t VAlign = 4; GMM_RESCREATE_PARAMS gmmParams = {}; gmmParams.Type = RESOURCE_2D; gmmParams.NoGfxMemory = 1; gmmParams.Flags.Gpu.Texture = 1; gmmParams.Flags.Gpu.RenderTarget = 1; gmmParams.Flags.Gpu.MMC = 1; gmmParams.Flags.Gpu.CCS = 1; gmmParams.Flags.Gpu.IndirectClearColor = 1; gmmParams.Flags.Info.MediaCompressed = 1; gmmParams.Flags.Info.NotLockable = 1; gmmParams.Flags.Info.Cacheable = 1; gmmParams.BaseWidth64 = 0xB2; gmmParams.BaseHeight = 0x92; gmmParams.Depth = 0x1; SetTileFlag(gmmParams, TEST_TILEY); // TileYF only GMM_RESOURCE_FORMAT Format[4] = {GMM_FORMAT_NV12, GMM_FORMAT_NV21, GMM_FORMAT_P010, GMM_FORMAT_P016}; for(auto fmt : Format) { gmmParams.Format = fmt; // 8bpp (NV12, NV21), 16bpp (P016, P010) TEST_BPP Ybpp, UVbpp; //Yf/Ys could be accessed on CPU/app where UV plane bpp is double switch(pGmmULTClientContext->GetPlatformInfo().FormatTable[fmt].Element.BitsPer) { case 8: Ybpp = TEST_BPP_8; UVbpp = TEST_BPP_16; break; case 16: Ybpp = TEST_BPP_16; UVbpp = TEST_BPP_32; break; default: return; } gmmParams.Flags.Gpu.UnifiedAuxSurface = 1; GMM_TILE_MODE TileMode = LEGACY_TILE_Y; GMM_RESOURCE_INFO *ResourceInfo; ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); //Redescribed Pitch isn't modified unless Y, UV pitch differ //But, original Pitch is padded to have even Tile, hence use Ybpp ExpectedPitch //to verify Pitch, but redescribed size uint32_t ExpectedPitch = GMM_ULT_ALIGN(gmmParams.BaseWidth64 * (int)pow(2.0, Ybpp), TileSize[0] * 4); uint32_t RedescribedPitch = GMM_ULT_ALIGN(gmmParams.BaseWidth64 / 2 * (int)pow(2.0, UVbpp), TileSize[0] * 4); //ExpectedPitch = GMM_ULT_ALIGN(ExpectedPitch, 2 * TileSize[Ybpp][0]); //pad to even tile if(ExpectedPitch != RedescribedPitch) { ExpectedPitch = RedescribedPitch; } VerifyResourcePitch(ResourceInfo, ExpectedPitch); VerifyResourcePitchInTiles(ResourceInfo, ExpectedPitch / TileSize[0]); int YSizeInTiles = (GMM_ULT_ALIGN(gmmParams.BaseHeight, 4 * TileSize[1]) / TileSize[1]) * //Default 64K-alignment for Y/UV base (AuxT 64K) RedescribedPitch / TileSize[0]; int UVSizeInTiles = (GMM_ULT_ALIGN(gmmParams.BaseHeight / 2, 4 * TileSize[1]) / TileSize[1]) * //Default 64K-alignment for Y/UV base (AuxT 64K) RedescribedPitch / TileSize[0]; VerifyResourceSize(ResourceInfo, GMM_KBYTE(4) * (YSizeInTiles + UVSizeInTiles)); //when main-surf planes are tile-aligned, make it verify-true VerifyResourceHAlign(ResourceInfo, HAlign); VerifyResourceVAlign(ResourceInfo, VAlign); VerifyResourceQPitch(ResourceInfo, 0); // N/A for non-mipped surface //test main surface base alignment is 64KB //For Yf test main surface pitch is 4-tileY aligned EXPECT_EQ(GMM_KBYTE(64), ResourceInfo->GetBaseAlignment()); EXPECT_EQ(0, ResourceInfo->GetRenderPitchTiles() % 4); if(const_cast(pGfxAdapterInfo->SkuTable).FtrLinearCCS) { EXPECT_EQ(0, ResourceInfo->GetUnifiedAuxSurfaceOffset(GMM_AUX_CCS) % PAGE_SIZE); EXPECT_EQ(0, ResourceInfo->GetUnifiedAuxSurfaceOffset(GMM_AUX_UV_CCS) % PAGE_SIZE); EXPECT_GE(ResourceInfo->GetSizeAuxSurface(GMM_AUX_CCS), ResourceInfo->GetSizeMainSurface() >> 8); } EXPECT_EQ(GMM_KBYTE(4) * 2, ResourceInfo->GetSizeAuxSurface(GMM_AUX_CCS)); // Y and UV Aux are on separate tiles pGmmULTClientContext->DestroyResInfoObject(ResourceInfo); } } /// @brief ULT for Planar Ys Compressed resource TEST_F(CTestGen12Resource, DISABLED_TestPlanarYsCompressedResource) { const TEST_TILE_TYPE TileTypeSupported = {TEST_TILEYS}; const uint32_t TileSize[TEST_BPP_MAX][2] = { {256, 256}, {512, 128}, {512, 128}, {1024, 64}, {1024, 64}}; // TileYS GMM_RESCREATE_PARAMS gmmParams = {}; gmmParams.Type = RESOURCE_2D; gmmParams.NoGfxMemory = 1; gmmParams.Flags.Gpu.Texture = 1; gmmParams.Flags.Gpu.MMC = 1; //gmmParams.Flags.Gpu.CCS = 1; gmmParams.Flags.Gpu.UnifiedAuxSurface = 1; gmmParams.Flags.Info.MediaCompressed = 1; gmmParams.BaseWidth64 = 0x100; gmmParams.BaseHeight = 0x50; gmmParams.Depth = 0x1; SetTileFlag(gmmParams, TEST_TILEYS); // TileYS only GMM_RESOURCE_FORMAT Format[4] = {GMM_FORMAT_NV12, GMM_FORMAT_NV21, GMM_FORMAT_P010, GMM_FORMAT_P016}; for(auto fmt : Format) { gmmParams.Format = fmt; // 8bpp(NV12) , P016 (16bpp), P010 (16bpp), NV21(8bpp) TEST_BPP Ybpp, UVbpp; //Yf/Ys could be accessed on CPU/app where UV plane bpp is double switch(pGmmULTClientContext->GetPlatformInfo().FormatTable[gmmParams.Format].Element.BitsPer) { case 8: Ybpp = TEST_BPP_8; UVbpp = TEST_BPP_16; break; case 16: Ybpp = TEST_BPP_16; UVbpp = TEST_BPP_32; break; default: return; } gmmParams.Flags.Gpu.UnifiedAuxSurface = 1; GMM_TILE_MODE TileMode = DEFINE_TILE(YS_2D, Ybpp); GMM_RESOURCE_INFO *ResourceInfo; ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); //Redescribed Pitch isn't modified unless Y, UV pitch differ //But, original Pitch is padded to have even Tile, hence use Ybpp ExpectedPitch //to verify Pitch, but redescribed pitch to verify size uint32_t ExpectedPitch = GMM_ULT_ALIGN(gmmParams.BaseWidth64 * (int)pow(2.0, Ybpp), TileSize[Ybpp][0]); uint32_t RedescribedPitch = GMM_ULT_ALIGN(gmmParams.BaseWidth64 / 2 * (int)pow(2.0, UVbpp), TileSize[UVbpp][0]); if(ExpectedPitch != RedescribedPitch) { ExpectedPitch = RedescribedPitch; } else { //ExpectedPitch = GMM_ULT_ALIGN(ExpectedPitch, 2 * TileSize[Ybpp][0]); //pad to even tile //ExpectedPitch = GMM_ULT_ALIGN(ExpectedPitch, (2 * TileSize[UVbpp][0]/ (int)pow(2.0, UVbpp))); //pad to even tile } VerifyResourcePitch(ResourceInfo, ExpectedPitch); VerifyResourcePitchInTiles(ResourceInfo, ExpectedPitch / TileSize[Ybpp][0]); int YSizeInTiles = (GMM_ULT_ALIGN(gmmParams.BaseHeight, TileSize[Ybpp][1]) / TileSize[Ybpp][1]) * RedescribedPitch / TileSize[Ybpp][0]; int UVSizeInTiles = (GMM_ULT_ALIGN(gmmParams.BaseHeight / 2, TileSize[UVbpp][1]) / TileSize[UVbpp][1]) * RedescribedPitch / TileSize[UVbpp][0]; VerifyResourceSize(ResourceInfo, GMM_KBYTE(64) * (YSizeInTiles + UVSizeInTiles)); VerifyResourceHAlign(ResourceInfo, TileSize[UVbpp][0] / pow(2.0, UVbpp)); // For Yf/Ys planar redescription causes UV width, Y height alignment VerifyResourceVAlign(ResourceInfo, TileSize[Ybpp][1]); VerifyResourceQPitch(ResourceInfo, 0); // N/A for non-mipped surface //test main surface base alignment is 64KB //For Yf test main surface pitch is 4-tileYF aligned EXPECT_EQ(GMM_KBYTE(64), ResourceInfo->GetBaseAlignment()); //EXPECT_EQ(0, ResourceInfo->GetRenderPitchTiles() % 4); // Check on YF only if(const_cast(pGfxAdapterInfo->SkuTable).FtrLinearCCS) { EXPECT_EQ(0, ResourceInfo->GetUnifiedAuxSurfaceOffset(GMM_AUX_CCS) % PAGE_SIZE); EXPECT_EQ(0, ResourceInfo->GetUnifiedAuxSurfaceOffset(GMM_AUX_UV_CCS) % PAGE_SIZE); EXPECT_GE(ResourceInfo->GetSizeAuxSurface(GMM_AUX_CCS), ResourceInfo->GetSizeMainSurface() >> 8); } EXPECT_EQ(GMM_KBYTE(4) * 2, ResourceInfo->GetSizeAuxSurface(GMM_AUX_CCS)); // Y and UV Aux are on separate tiles { //separate Aux gmmParams.Flags.Gpu.UnifiedAuxSurface = 0; GMM_RESOURCE_INFO *AuxResourceInfo; AuxResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); EXPECT_EQ(ResourceInfo->GetSizeAuxSurface(GMM_AUX_CCS), AuxResourceInfo->GetSizeSurface()); pGmmULTClientContext->DestroyResInfoObject(AuxResourceInfo); } pGmmULTClientContext->DestroyResInfoObject(ResourceInfo); } } /// @brief ULT for 2D arrayed compressed Resource TEST_F(CTestGen12Resource, TestArrayedCompressedResource) { //printf("%s\n", __FUNCTION__); //Test for 3D array } /// @brief ULT for mip-mapped compressed Resource TEST_F(CTestGen12Resource, TestMipMapCompressedResource) { //printf("%s\n", __FUNCTION__); } /// @brief ULT for cube Compressed Resource TEST_F(CTestGen12Resource, TestCubeCompressedResource) { //Tests 2D array const uint32_t HAlign[5][TEST_BPP_MAX] = {{0}, {0}, {0}, {256, 256, 128, 128, 64}, {64, 64, 32, 32, 16}}; const uint32_t VAlign[5][TEST_BPP_MAX] = {{0}, {0}, {0}, {256, 128, 128, 64, 64}, {64, 32, 32, 16, 16}}; const TEST_TILE_TYPE TileTypeSupported[2] = {TEST_TILEYS, TEST_TILEYF}; const uint32_t TileSize[5][TEST_BPP_MAX][2] = { {0}, {0}, {0}, {{256, 256}, {512, 128}, {512, 128}, {1024, 64}, {1024, 64}}, // TileYS {{64, 64}, {128, 32}, {128, 32}, {256, 16}, {256, 16}}}; //TileYf GMM_RESCREATE_PARAMS gmmParams = {}; gmmParams.Type = RESOURCE_CUBE; gmmParams.NoGfxMemory = 1; gmmParams.Flags.Gpu.Texture = 1; gmmParams.Flags.Info.RenderCompressed = 1; // Allocate 1x1 surface so that it occupies 1 Tile in X dimension for(auto Tiling : TileTypeSupported) { gmmParams.Flags.Info.TiledY = 1; gmmParams.Flags.Info.TiledYf = (Tiling == TEST_TILEYF); gmmParams.Flags.Info.TiledYs = (Tiling == TEST_TILEYS); for(uint32_t i = 0; i < TEST_BPP_MAX; i++) { gmmParams.Flags.Gpu.UnifiedAuxSurface = 1; gmmParams.Flags.Gpu.CCS = 1; TEST_BPP bpp = static_cast(i); GMM_TILE_MODE TileMode = (Tiling == TEST_TILEYF) ? DEFINE_TILE(YF_2D, bpp) : DEFINE_TILE(YS_2D, bpp); gmmParams.Format = SetResourceFormat(bpp); gmmParams.BaseWidth64 = 0x1; gmmParams.BaseHeight = 0x1; gmmParams.Depth = 0x1; GMM_RESOURCE_INFO *ResourceInfo; ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); VerifyResourceHAlign(ResourceInfo, HAlign[Tiling][i]); VerifyResourceVAlign(ResourceInfo, VAlign[Tiling][i]); uint32_t ExpectedPitch = 4 * TileSize[TEST_TILEYF][i][0]; VerifyResourcePitch(ResourceInfo, ExpectedPitch); // As wide as 4 tile-YF VerifyResourcePitchInTiles(ResourceInfo, (Tiling == TEST_TILEYF) ? 4 : 1); // 1 tile wide uint32_t ExpectedQPitch = VAlign[Tiling][i]; VerifyResourceQPitch(ResourceInfo, ExpectedQPitch); // Each face should be VAlign rows apart within a tile VerifyResourceSize(ResourceInfo, // PitchInBytes * Rows where Rows = __GMM_MAX_CUBE_FACE x QPitch, then aligned to tile boundary ExpectedPitch * __GMM_MAX_CUBE_FACE * ExpectedQPitch); //test main surface base alignment is 64KB //For Yf test main surface pitch is 4-tileYF aligned EXPECT_EQ(GMM_KBYTE(64), ResourceInfo->GetBaseAlignment()); EXPECT_EQ(0, ResourceInfo->GetRenderPitchTiles() % ((Tiling == TEST_TILEYF) ? 4 : 1)); if(const_cast(pGfxAdapterInfo->SkuTable).FtrLinearCCS) { EXPECT_EQ(0, ResourceInfo->GetUnifiedAuxSurfaceOffset(GMM_AUX_CCS) % PAGE_SIZE); EXPECT_GE(ResourceInfo->GetSizeAuxSurface(GMM_AUX_CCS), ResourceInfo->GetSizeMainSurface() >> 8); } EXPECT_EQ(GMM_KBYTE(4), ResourceInfo->GetSizeAuxSurface(GMM_AUX_CCS)); { //separate Aux gmmParams.Flags.Gpu.UnifiedAuxSurface = 0; GMM_RESOURCE_INFO *AuxResourceInfo; AuxResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); EXPECT_EQ(ResourceInfo->GetAuxHAlign(), AuxResourceInfo->GetHAlign()); EXPECT_EQ(ResourceInfo->GetAuxVAlign(), AuxResourceInfo->GetVAlign()); EXPECT_EQ(ResourceInfo->GetUnifiedAuxPitch(), AuxResourceInfo->GetRenderPitch()); EXPECT_EQ(ResourceInfo->GetSizeAuxSurface(GMM_AUX_CCS), AuxResourceInfo->GetSizeSurface()); pGmmULTClientContext->DestroyResInfoObject(AuxResourceInfo); } for(uint32_t CubeFaceIndex = 0; CubeFaceIndex < __GMM_MAX_CUBE_FACE; CubeFaceIndex++) { GMM_REQ_OFFSET_INFO OffsetInfo = {}; OffsetInfo.ReqRender = 1; OffsetInfo.CubeFace = static_cast(CubeFaceIndex); ResourceInfo->GetOffset(OffsetInfo); EXPECT_EQ((CubeFaceIndex * ExpectedQPitch) * ExpectedPitch, OffsetInfo.Render.Offset64); // Render offset is tile's base address on which cube face begins. EXPECT_EQ(0, OffsetInfo.Render.XOffset); // X Offset should be 0 as cube face starts on tile boundary EXPECT_EQ(0, OffsetInfo.Render.YOffset); // Y Offset should be 0 as cube face starts on tile boundary EXPECT_EQ(0, OffsetInfo.Render.ZOffset); // Z offset N/A should be 0 } pGmmULTClientContext->DestroyResInfoObject(ResourceInfo); } // Allocate 2 tiles in X dimension. // Width and Height must be equal for(uint32_t i = 0; i < TEST_BPP_MAX; i++) { gmmParams.Flags.Gpu.UnifiedAuxSurface = 1; gmmParams.Flags.Gpu.CCS = 1; TEST_BPP bpp = static_cast(i); GMM_TILE_MODE TileMode = (Tiling == TEST_TILEYF) ? DEFINE_TILE(YF_2D, bpp) : DEFINE_TILE(YS_2D, bpp); gmmParams.Format = SetResourceFormat(bpp); gmmParams.BaseWidth64 = (TileSize[Tiling][i][0] / GetBppValue(bpp)) + 1; // 1 pixel larger than 1 tile width gmmParams.BaseHeight = gmmParams.BaseWidth64; // Heigth must be equal to width. gmmParams.Depth = 0x1; GMM_RESOURCE_INFO *ResourceInfo; ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); VerifyResourceHAlign(ResourceInfo, HAlign[Tiling][i]); VerifyResourceVAlign(ResourceInfo, VAlign[Tiling][i]); uint32_t ExpectedPitch = TileSize[Tiling][i][0] * 2 * ((Tiling == TEST_TILEYF) ? 2 : 1); // As wide as 2 tile, padded to 4 tile-pitch VerifyResourcePitch(ResourceInfo, ExpectedPitch); VerifyResourcePitchInTiles(ResourceInfo, 2 * ((Tiling == TEST_TILEYF) ? 2 : 1)); // 2 tile wide uint32_t ExpectedQPitch = GMM_ULT_ALIGN(gmmParams.BaseHeight, VAlign[Tiling][i]); VerifyResourceQPitch(ResourceInfo, ExpectedQPitch); // Each face should be Valigned-BaseHeight rows apart VerifyResourceSize(ResourceInfo, // PitchInBytes * Rows where Rows = __GMM_MAX_CUBE_FACE x QPitch, then aligned to tile boundary ExpectedPitch * __GMM_MAX_CUBE_FACE * ExpectedQPitch); //test main surface base alignment is 64KB //For Yf test main surface pitch is 4-tileYF aligned EXPECT_EQ(GMM_KBYTE(64), ResourceInfo->GetBaseAlignment()); EXPECT_EQ(0, ResourceInfo->GetRenderPitchTiles() % ((Tiling == TEST_TILEYF) ? 4 : 1)); // Check on YF only if(const_cast(pGfxAdapterInfo->SkuTable).FtrLinearCCS) { EXPECT_EQ(0, ResourceInfo->GetUnifiedAuxSurfaceOffset(GMM_AUX_CCS) % PAGE_SIZE); EXPECT_GE(ResourceInfo->GetSizeAuxSurface(GMM_AUX_CCS), ResourceInfo->GetSizeMainSurface() >> 8); } { //separate Aux gmmParams.Flags.Gpu.UnifiedAuxSurface = 0; GMM_RESOURCE_INFO *AuxResourceInfo; AuxResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); EXPECT_EQ(ResourceInfo->GetAuxHAlign(), AuxResourceInfo->GetHAlign()); EXPECT_EQ(ResourceInfo->GetAuxVAlign(), AuxResourceInfo->GetVAlign()); EXPECT_EQ(ResourceInfo->GetUnifiedAuxPitch(), AuxResourceInfo->GetRenderPitch()); EXPECT_EQ(ResourceInfo->GetSizeAuxSurface(GMM_AUX_CCS), AuxResourceInfo->GetSizeSurface()); pGmmULTClientContext->DestroyResInfoObject(AuxResourceInfo); } for(uint32_t CubeFaceIndex = 0; CubeFaceIndex < __GMM_MAX_CUBE_FACE; CubeFaceIndex++) { GMM_REQ_OFFSET_INFO OffsetInfo = {}; OffsetInfo.ReqRender = 1; OffsetInfo.CubeFace = static_cast(CubeFaceIndex); ResourceInfo->GetOffset(OffsetInfo); EXPECT_EQ((CubeFaceIndex * ExpectedQPitch) * ExpectedPitch, OffsetInfo.Render.Offset64); // Render offset is tile's base address on which cube face begins. EXPECT_EQ(0, OffsetInfo.Render.XOffset); // X Offset should be 0 as cube face starts on tile boundary EXPECT_EQ(0, OffsetInfo.Render.YOffset); // Y Offset should be 0 as cube face starts on tile boundary EXPECT_EQ(0, OffsetInfo.Render.ZOffset); // Z offset N/A should be 0 } pGmmULTClientContext->DestroyResInfoObject(ResourceInfo); } } } /// @brief ULT for 3D TileYs Compressed Resource TEST_F(CTestGen12Resource, Test3DTileYsCompressedResource) { if(!const_cast(pGfxAdapterInfo->SkuTable).FtrLinearCCS) { return; } // Horizontal/Vertical pixel alignment const uint32_t HAlign[TEST_BPP_MAX] = {64, 32, 32, 32, 16}; const uint32_t VAlign[TEST_BPP_MAX] = {32, 32, 32, 16, 16}; const uint32_t TileSize[TEST_BPP_MAX][3] = {{64, 32, 32}, {64, 32, 32}, {128, 32, 16}, {256, 16, 16}, {256, 16, 16}}; GMM_RESCREATE_PARAMS gmmParams = {}; gmmParams.Type = RESOURCE_3D; gmmParams.NoGfxMemory = 1; gmmParams.Flags.Info.TiledY = 1; gmmParams.Flags.Info.TiledYs = 1; gmmParams.Flags.Gpu.Texture = 1; gmmParams.Flags.Info.RenderCompressed = 1; // Turn on .MC or .RC flag - mandatory to tell compression-type, for Yf its also used to pad surf // to 4x1 tile (reqd by HW for perf reasons) // Allocate 1x1x1 surface for(uint32_t i = 0; i < TEST_BPP_MAX; i++) { // If unifiedAuxSurf reqd (mandatory for displayable or cross-device shared), turn on .CCS/.MMC and .UnifiedAuxSurface too gmmParams.Flags.Gpu.UnifiedAuxSurface = 1; //Turn off for separate aux creation gmmParams.Flags.Gpu.CCS = 1; //Turn off for separate aux creation TEST_BPP bpp = static_cast(i); GMM_TILE_MODE TileMode = DEFINE_TILE(YS_3D, bpp); gmmParams.Format = SetResourceFormat(bpp); gmmParams.BaseWidth64 = 0x1; gmmParams.BaseHeight = 0x1; gmmParams.Depth = 0x1; GMM_RESOURCE_INFO *ResourceInfo; ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); VerifyResourceHAlign(ResourceInfo, HAlign[i]); VerifyResourceVAlign(ResourceInfo, VAlign[i]); VerifyResourcePitch(ResourceInfo, TileSize[i][0]); // As wide as 1 tile VerifyResourcePitchInTiles(ResourceInfo, 1); // 1 tile wide VerifyResourceSize(ResourceInfo, GMM_KBYTE(64)); // 1 tile big VerifyResourceQPitch(ResourceInfo, 0); // Not tested //test main surface base alignment is 64KB //For Yf test main surface pitch is 4-tileYF aligned EXPECT_EQ(GMM_KBYTE(64), ResourceInfo->GetBaseAlignment()); if(const_cast(pGfxAdapterInfo->SkuTable).FtrLinearCCS) { EXPECT_EQ(0, ResourceInfo->GetUnifiedAuxSurfaceOffset(GMM_AUX_CCS) % PAGE_SIZE); EXPECT_GE(ResourceInfo->GetSizeAuxSurface(GMM_AUX_CCS), ResourceInfo->GetSizeMainSurface() >> 8); } EXPECT_EQ(GMM_KBYTE(4), ResourceInfo->GetSizeAuxSurface(GMM_AUX_CCS)); { //separate Aux gmmParams.Flags.Gpu.UnifiedAuxSurface = 0; GMM_RESOURCE_INFO *AuxResourceInfo; AuxResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); EXPECT_EQ(ResourceInfo->GetAuxHAlign(), AuxResourceInfo->GetHAlign()); EXPECT_EQ(ResourceInfo->GetAuxVAlign(), AuxResourceInfo->GetVAlign()); EXPECT_EQ(ResourceInfo->GetUnifiedAuxPitch(), AuxResourceInfo->GetRenderPitch()); EXPECT_EQ(ResourceInfo->GetSizeAuxSurface(GMM_AUX_CCS), AuxResourceInfo->GetSizeSurface()); pGmmULTClientContext->DestroyResInfoObject(AuxResourceInfo); } pGmmULTClientContext->DestroyResInfoObject(ResourceInfo); } // Allocate 2 tiles in X dimension for(uint32_t i = 0; i < TEST_BPP_MAX; i++) { // If unifiedAuxSurf reqd (mandatory for displayable or cross-device shared), turn on .CCS/.MMC and .UnifiedAuxSurface too gmmParams.Flags.Gpu.UnifiedAuxSurface = 1; //Turn off for separate aux creation gmmParams.Flags.Gpu.CCS = 1; //Turn off for separate aux creation TEST_BPP bpp = static_cast(i); GMM_TILE_MODE TileMode = DEFINE_TILE(YS_3D, bpp); gmmParams.Format = SetResourceFormat(bpp); gmmParams.BaseWidth64 = (TileSize[i][0] / GetBppValue(bpp)) + 1; // 1 pixel larger than 1 tile width gmmParams.BaseHeight = 0x1; gmmParams.Depth = 0x1; GMM_RESOURCE_INFO *ResourceInfo; ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); VerifyResourceHAlign(ResourceInfo, HAlign[i]); VerifyResourceVAlign(ResourceInfo, VAlign[i]); VerifyResourcePitch(ResourceInfo, TileSize[i][0] * 2); // As wide as 2 tile VerifyResourcePitchInTiles(ResourceInfo, 2); // 2 tile wide VerifyResourceSize(ResourceInfo, GMM_KBYTE(64) * 2); // 2 tile big VerifyResourceQPitch(ResourceInfo, 0); // Not tested //test main surface base alignment is 64KB //For Yf test main surface pitch is 4-tileYF aligned EXPECT_EQ(GMM_KBYTE(64), ResourceInfo->GetBaseAlignment()); if(const_cast(pGfxAdapterInfo->SkuTable).FtrLinearCCS) { EXPECT_EQ(0, ResourceInfo->GetUnifiedAuxSurfaceOffset(GMM_AUX_CCS) % PAGE_SIZE); EXPECT_GE(ResourceInfo->GetSizeAuxSurface(GMM_AUX_CCS), ResourceInfo->GetSizeMainSurface() >> 8); } EXPECT_EQ(GMM_KBYTE(4), ResourceInfo->GetSizeAuxSurface(GMM_AUX_CCS)); { //separate Aux gmmParams.Flags.Gpu.UnifiedAuxSurface = 0; GMM_RESOURCE_INFO *AuxResourceInfo; AuxResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); EXPECT_EQ(ResourceInfo->GetAuxHAlign(), AuxResourceInfo->GetHAlign()); EXPECT_EQ(ResourceInfo->GetAuxVAlign(), AuxResourceInfo->GetVAlign()); EXPECT_EQ(ResourceInfo->GetUnifiedAuxPitch(), AuxResourceInfo->GetRenderPitch()); EXPECT_EQ(ResourceInfo->GetSizeAuxSurface(GMM_AUX_CCS), AuxResourceInfo->GetSizeSurface()); pGmmULTClientContext->DestroyResInfoObject(AuxResourceInfo); } pGmmULTClientContext->DestroyResInfoObject(ResourceInfo); } // Allocate 2 tiles in X/Y dimension for(uint32_t i = 0; i < TEST_BPP_MAX; i++) { // If unifiedAuxSurf reqd (mandatory for displayable or cross-device shared), turn on .CCS/.MMC and .UnifiedAuxSurface too gmmParams.Flags.Gpu.UnifiedAuxSurface = 1; //Turn off for separate aux creation gmmParams.Flags.Gpu.CCS = 1; //Turn off for separate aux creation TEST_BPP bpp = static_cast(i); GMM_TILE_MODE TileMode = DEFINE_TILE(YS_3D, bpp); gmmParams.Format = SetResourceFormat(bpp); gmmParams.BaseWidth64 = (TileSize[i][0] / GetBppValue(bpp)) + 1; // 1 pixel larger than 1 tile width gmmParams.BaseHeight = TileSize[i][1] + 1; // 1 row larger than 1 tile height gmmParams.Depth = 0x1; GMM_RESOURCE_INFO *ResourceInfo; ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); VerifyResourceHAlign(ResourceInfo, HAlign[i]); VerifyResourceVAlign(ResourceInfo, VAlign[i]); VerifyResourcePitch(ResourceInfo, TileSize[i][0] * 2); // As wide as 2 tile VerifyResourcePitchInTiles(ResourceInfo, 2); // 2 tile wide VerifyResourceSize(ResourceInfo, GMM_KBYTE(64) * 4); // 4 tile big VerifyResourceQPitch(ResourceInfo, 0); // Not tested //test main surface base alignment is 64KB //For Yf test main surface pitch is 4-tileYF aligned EXPECT_EQ(GMM_KBYTE(64), ResourceInfo->GetBaseAlignment()); if(const_cast(pGfxAdapterInfo->SkuTable).FtrLinearCCS) { EXPECT_EQ(0, ResourceInfo->GetUnifiedAuxSurfaceOffset(GMM_AUX_CCS) % PAGE_SIZE); EXPECT_GE(ResourceInfo->GetSizeAuxSurface(GMM_AUX_CCS), ResourceInfo->GetSizeMainSurface() >> 8); } EXPECT_EQ(GMM_KBYTE(4), ResourceInfo->GetSizeAuxSurface(GMM_AUX_CCS)); { //separate Aux gmmParams.Flags.Gpu.UnifiedAuxSurface = 0; GMM_RESOURCE_INFO *AuxResourceInfo; AuxResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); EXPECT_EQ(ResourceInfo->GetAuxHAlign(), AuxResourceInfo->GetHAlign()); EXPECT_EQ(ResourceInfo->GetAuxVAlign(), AuxResourceInfo->GetVAlign()); EXPECT_EQ(ResourceInfo->GetUnifiedAuxPitch(), AuxResourceInfo->GetRenderPitch()); EXPECT_EQ(ResourceInfo->GetSizeAuxSurface(GMM_AUX_CCS), AuxResourceInfo->GetSizeSurface()); pGmmULTClientContext->DestroyResInfoObject(AuxResourceInfo); } pGmmULTClientContext->DestroyResInfoObject(ResourceInfo); } // Allocate 2 tiles in X/Y/Z dimension for(uint32_t i = 0; i < TEST_BPP_MAX; i++) { // If unifiedAuxSurf reqd (mandatory for displayable or cross-device shared), turn on .CCS/.MMC and .UnifiedAuxSurface too gmmParams.Flags.Gpu.UnifiedAuxSurface = 1; //Turn off for separate aux creation gmmParams.Flags.Gpu.CCS = 1; //Turn off for separate aux creation TEST_BPP bpp = static_cast(i); GMM_TILE_MODE TileMode = DEFINE_TILE(YS_3D, bpp); gmmParams.Format = SetResourceFormat(bpp); gmmParams.BaseWidth64 = (TileSize[i][0] / GetBppValue(bpp)) + 1; // 1 pixel larger than 1 tile width gmmParams.BaseHeight = TileSize[i][1] + 1; // 1 row larger than 1 tile height gmmParams.Depth = TileSize[i][2] + 1; // 1 plane larger than 1 tile depth GMM_RESOURCE_INFO *ResourceInfo; ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); VerifyResourceHAlign(ResourceInfo, HAlign[i]); VerifyResourceVAlign(ResourceInfo, VAlign[i]); VerifyResourcePitch(ResourceInfo, TileSize[i][0] * 2); // As wide as 2 tile VerifyResourcePitchInTiles(ResourceInfo, 2); // 2 tile wide VerifyResourceSize(ResourceInfo, GMM_KBYTE(64) * 8); // 8 tile big VerifyResourceQPitch(ResourceInfo, 0); // Not tested //test main surface base alignment is 64KB //For Yf test main surface pitch is 4-tileYF aligned EXPECT_EQ(GMM_KBYTE(64), ResourceInfo->GetBaseAlignment()); if(const_cast(pGfxAdapterInfo->SkuTable).FtrLinearCCS) { EXPECT_EQ(0, ResourceInfo->GetUnifiedAuxSurfaceOffset(GMM_AUX_CCS) % PAGE_SIZE); EXPECT_GE(ResourceInfo->GetSizeAuxSurface(GMM_AUX_CCS), ResourceInfo->GetSizeMainSurface() >> 8); } EXPECT_EQ(GMM_KBYTE(4), ResourceInfo->GetSizeAuxSurface(GMM_AUX_CCS)); { //separate Aux gmmParams.Flags.Gpu.UnifiedAuxSurface = 0; GMM_RESOURCE_INFO *AuxResourceInfo; AuxResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); EXPECT_EQ(ResourceInfo->GetAuxHAlign(), AuxResourceInfo->GetHAlign()); EXPECT_EQ(ResourceInfo->GetAuxVAlign(), AuxResourceInfo->GetVAlign()); EXPECT_EQ(ResourceInfo->GetUnifiedAuxPitch(), AuxResourceInfo->GetRenderPitch()); EXPECT_EQ(ResourceInfo->GetSizeAuxSurface(GMM_AUX_CCS), AuxResourceInfo->GetSizeSurface()); pGmmULTClientContext->DestroyResInfoObject(AuxResourceInfo); } pGmmULTClientContext->DestroyResInfoObject(ResourceInfo); } } /// @brief ULT for 3D TileYf Compressed Resource TEST_F(CTestGen12Resource, Test3DTileYfCompressedResource) { if(!const_cast(pGfxAdapterInfo->SkuTable).FtrLinearCCS) { return; } // Horizontal/Verticle pixel alignment const uint32_t HAlign[TEST_BPP_MAX] = {16, 8, 8, 8, 4}; const uint32_t VAlign[TEST_BPP_MAX] = {16, 16, 16, 8, 8}; const uint32_t TileSize[TEST_BPP_MAX][3] = {{16, 16, 16}, {16, 16, 16}, {32, 16, 8}, {64, 8, 8}, {64, 8, 8}}; GMM_RESCREATE_PARAMS gmmParams = {}; gmmParams.Type = RESOURCE_3D; gmmParams.NoGfxMemory = 1; gmmParams.Flags.Info.TiledY = 1; gmmParams.Flags.Info.TiledYf = 1; gmmParams.Flags.Gpu.Texture = 1; gmmParams.Flags.Info.RenderCompressed = 1; // Turn on .MC or .RC flag - mandatory to tell compression-type, for Yf its also used to pad surf // to 4x1 tile (reqd by HW for perf reasons) // Allocate 1x1x1 surface for(uint32_t i = 0; i < TEST_BPP_MAX; i++) { // If unifiedAuxSurf reqd (mandatory for displayable or cross-device shared), turn on .CCS/.MMC and .UnifiedAuxSurface too gmmParams.Flags.Gpu.UnifiedAuxSurface = 1; //Turn off for separate aux creation gmmParams.Flags.Gpu.CCS = 1; //Turn off for separate aux creation //gmmParams.Flags.Gpu.MMC = 0; //Turn on to check unifiedaux creation TEST_BPP bpp = static_cast(i); GMM_TILE_MODE TileMode = DEFINE_TILE(YF_3D, bpp); gmmParams.Format = SetResourceFormat(bpp); //gmmParams.BaseWidth64 = 0x30; //gmmParams.BaseHeight = 0x30; //gmmParams.Depth = 0x20; gmmParams.BaseWidth64 = 1; gmmParams.BaseHeight = 1; gmmParams.Depth = 1; const uint32_t PitchAlignment = 32; GMM_RESOURCE_INFO *ResourceInfo; ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); VerifyResourceHAlign(ResourceInfo, HAlign[i]); VerifyResourceVAlign(ResourceInfo, VAlign[i]); VerifyResourcePitch(ResourceInfo, GMM_ULT_ALIGN(gmmParams.BaseWidth64, TileSize[i][0] * 4)); VerifyResourcePitchInTiles(ResourceInfo, GMM_ULT_ALIGN(gmmParams.BaseWidth64, TileSize[i][0] * 4) / TileSize[i][0]); VerifyResourceSize(ResourceInfo, (GMM_ULT_ALIGN(gmmParams.BaseWidth64, TileSize[i][0] * 4) / TileSize[i][0]) * (GMM_ULT_ALIGN(gmmParams.BaseHeight, TileSize[i][1]) / TileSize[i][1]) * (GMM_ULT_ALIGN(gmmParams.Depth, TileSize[i][2]) / TileSize[i][2]) * GMM_KBYTE(4)); VerifyResourceQPitch(ResourceInfo, (GMM_ULT_ALIGN(gmmParams.BaseHeight, TileSize[i][1]))); //test main surface base alignment is 64KB //For Yf test main surface pitch is 4-tileYF aligned EXPECT_EQ(GMM_KBYTE(64), ResourceInfo->GetBaseAlignment()); EXPECT_EQ(0, ResourceInfo->GetRenderPitchTiles() % 4); // Check on YF only if(const_cast(pGfxAdapterInfo->SkuTable).FtrLinearCCS) { EXPECT_EQ(0, ResourceInfo->GetUnifiedAuxSurfaceOffset(GMM_AUX_CCS) % PAGE_SIZE); EXPECT_GE(ResourceInfo->GetSizeAuxSurface(GMM_AUX_CCS), ResourceInfo->GetSizeMainSurface() >> 8); } ASSERT_LE(GMM_ULT_ALIGN(ResourceInfo->GetSizeMainSurface() / (GMM_KBYTE(16) / GMM_BYTES(64)), GMM_KBYTE(4)), ResourceInfo->GetSizeAuxSurface(GMM_AUX_CCS)); { //separate Aux gmmParams.Flags.Gpu.UnifiedAuxSurface = 0; GMM_RESOURCE_INFO *AuxResourceInfo; AuxResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); EXPECT_EQ(ResourceInfo->GetAuxHAlign(), AuxResourceInfo->GetHAlign()); EXPECT_EQ(ResourceInfo->GetAuxVAlign(), AuxResourceInfo->GetVAlign()); EXPECT_EQ(ResourceInfo->GetUnifiedAuxPitch(), AuxResourceInfo->GetRenderPitch()); EXPECT_EQ(ResourceInfo->GetSizeAuxSurface(GMM_AUX_CCS), AuxResourceInfo->GetSizeSurface()); pGmmULTClientContext->DestroyResInfoObject(AuxResourceInfo); } pGmmULTClientContext->DestroyResInfoObject(ResourceInfo); } // Allocate 2 tiles in X dimension for(uint32_t i = 0; i < TEST_BPP_MAX; i++) { // If unifiedAuxSurf reqd (mandatory for displayable or cross-device shared), turn on .CCS/.MMC and .UnifiedAuxSurface too gmmParams.Flags.Gpu.UnifiedAuxSurface = 1; //Turn off for separate aux creation gmmParams.Flags.Gpu.CCS = 1; //Turn off for separate aux creation TEST_BPP bpp = static_cast(i); GMM_TILE_MODE TileMode = DEFINE_TILE(YF_3D, bpp); gmmParams.Format = SetResourceFormat(bpp); gmmParams.BaseWidth64 = (TileSize[i][0] / GetBppValue(bpp)) + 1; gmmParams.BaseHeight = 0x1; gmmParams.Depth = 0x1; const uint32_t PitchAlignment = 32; GMM_RESOURCE_INFO *ResourceInfo; ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); VerifyResourceHAlign(ResourceInfo, HAlign[i]); VerifyResourceVAlign(ResourceInfo, VAlign[i]); VerifyResourcePitch(ResourceInfo, GMM_ULT_ALIGN(TileSize[i][0] * 4, PitchAlignment)); VerifyResourcePitchInTiles(ResourceInfo, GMM_ULT_ALIGN(TileSize[i][0] * 4, PitchAlignment) / TileSize[i][0]); VerifyResourceSize(ResourceInfo, GMM_ULT_ALIGN(TileSize[i][0] * 4, PitchAlignment) / TileSize[i][0] * GMM_KBYTE(4)); VerifyResourceQPitch(ResourceInfo, TileSize[i][1]); //test main surface base alignment is 64KB //For Yf test main surface pitch is 4-tileYF aligned EXPECT_EQ(GMM_KBYTE(64), ResourceInfo->GetBaseAlignment()); EXPECT_EQ(0, ResourceInfo->GetRenderPitchTiles() % 4); // Check on YF only if(const_cast(pGfxAdapterInfo->SkuTable).FtrLinearCCS) { EXPECT_EQ(0, ResourceInfo->GetUnifiedAuxSurfaceOffset(GMM_AUX_CCS) % PAGE_SIZE); EXPECT_GE(ResourceInfo->GetSizeAuxSurface(GMM_AUX_CCS), ResourceInfo->GetSizeMainSurface() >> 8); } EXPECT_EQ(GMM_KBYTE(4), ResourceInfo->GetSizeAuxSurface(GMM_AUX_CCS)); ASSERT_LE(GMM_ULT_ALIGN(ResourceInfo->GetSizeMainSurface() / (GMM_KBYTE(16) / GMM_BYTES(64)), GMM_KBYTE(4)), ResourceInfo->GetSizeAuxSurface(GMM_AUX_CCS)); { //separate Aux gmmParams.Flags.Gpu.UnifiedAuxSurface = 0; GMM_RESOURCE_INFO *AuxResourceInfo; AuxResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); EXPECT_EQ(ResourceInfo->GetAuxHAlign(), AuxResourceInfo->GetHAlign()); EXPECT_EQ(ResourceInfo->GetAuxVAlign(), AuxResourceInfo->GetVAlign()); EXPECT_EQ(ResourceInfo->GetUnifiedAuxPitch(), AuxResourceInfo->GetRenderPitch()); EXPECT_EQ(ResourceInfo->GetSizeAuxSurface(GMM_AUX_CCS), AuxResourceInfo->GetSizeSurface()); pGmmULTClientContext->DestroyResInfoObject(AuxResourceInfo); } pGmmULTClientContext->DestroyResInfoObject(ResourceInfo); } // Allocate 2 tiles in X/Y dimension for(uint32_t i = 0; i < TEST_BPP_MAX; i++) { // If unifiedAuxSurf reqd (mandatory for displayable or cross-device shared), turn on .CCS/.MMC and .UnifiedAuxSurface too gmmParams.Flags.Gpu.UnifiedAuxSurface = 1; //Turn off for separate aux creation gmmParams.Flags.Gpu.CCS = 1; //Turn off for separate aux creation TEST_BPP bpp = static_cast(i); GMM_TILE_MODE TileMode = DEFINE_TILE(YF_3D, bpp); gmmParams.Format = SetResourceFormat(bpp); gmmParams.BaseWidth64 = (TileSize[i][0] / GetBppValue(bpp)) + 1; gmmParams.BaseHeight = TileSize[i][1] + 1; gmmParams.Depth = 0x1; const uint32_t PitchAlignment = 32; GMM_RESOURCE_INFO *ResourceInfo; ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); VerifyResourceHAlign(ResourceInfo, HAlign[i]); VerifyResourceVAlign(ResourceInfo, VAlign[i]); VerifyResourcePitch(ResourceInfo, GMM_ULT_ALIGN(TileSize[i][0] * 4, PitchAlignment)); VerifyResourcePitchInTiles(ResourceInfo, GMM_ULT_ALIGN(TileSize[i][0] * 4, PitchAlignment) / TileSize[i][0]); VerifyResourceSize(ResourceInfo, GMM_ULT_ALIGN(TileSize[i][0] * 4, PitchAlignment) / TileSize[i][0] * 2 * GMM_KBYTE(4)); VerifyResourceQPitch(ResourceInfo, TileSize[i][1] * 2); //test main surface base alignment is 64KB //For Yf test main surface pitch is 4-tileYF aligned EXPECT_EQ(GMM_KBYTE(64), ResourceInfo->GetBaseAlignment()); EXPECT_EQ(0, ResourceInfo->GetRenderPitchTiles() % 4); // Check on YF only if(const_cast(pGfxAdapterInfo->SkuTable).FtrLinearCCS) { EXPECT_EQ(0, ResourceInfo->GetUnifiedAuxSurfaceOffset(GMM_AUX_CCS) % PAGE_SIZE); EXPECT_GE(ResourceInfo->GetSizeAuxSurface(GMM_AUX_CCS), ResourceInfo->GetSizeMainSurface() >> 8); } EXPECT_EQ(GMM_KBYTE(4), ResourceInfo->GetSizeAuxSurface(GMM_AUX_CCS)); ASSERT_LE(GMM_ULT_ALIGN(ResourceInfo->GetSizeMainSurface() / (GMM_KBYTE(16) / GMM_BYTES(64)), GMM_KBYTE(4)), ResourceInfo->GetSizeAuxSurface(GMM_AUX_CCS)); { //separate Aux gmmParams.Flags.Gpu.UnifiedAuxSurface = 0; GMM_RESOURCE_INFO *AuxResourceInfo; AuxResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); EXPECT_EQ(ResourceInfo->GetAuxHAlign(), AuxResourceInfo->GetHAlign()); EXPECT_EQ(ResourceInfo->GetAuxVAlign(), AuxResourceInfo->GetVAlign()); EXPECT_EQ(ResourceInfo->GetUnifiedAuxPitch(), AuxResourceInfo->GetRenderPitch()); EXPECT_EQ(ResourceInfo->GetSizeAuxSurface(GMM_AUX_CCS), AuxResourceInfo->GetSizeSurface()); pGmmULTClientContext->DestroyResInfoObject(AuxResourceInfo); } pGmmULTClientContext->DestroyResInfoObject(ResourceInfo); } // Allocate 2 tiles in X/Y/Z dimension for(uint32_t i = 0; i < TEST_BPP_MAX; i++) { // If unifiedAuxSurf reqd (mandatory for displayable or cross-device shared), turn on .CCS/.MMC and .UnifiedAuxSurface too gmmParams.Flags.Gpu.UnifiedAuxSurface = 1; //Turn off for separate aux creation gmmParams.Flags.Gpu.CCS = 1; //Turn off for separate aux creation TEST_BPP bpp = static_cast(i); GMM_TILE_MODE TileMode = DEFINE_TILE(YF_3D, bpp); gmmParams.Format = SetResourceFormat(bpp); gmmParams.BaseWidth64 = (TileSize[i][0] / GetBppValue(bpp)) + 1; gmmParams.BaseHeight = TileSize[i][1] + 1; gmmParams.Depth = TileSize[i][2] + 1; const uint32_t PitchAlignment = 32; GMM_RESOURCE_INFO *ResourceInfo; ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); VerifyResourceHAlign(ResourceInfo, HAlign[i]); VerifyResourceVAlign(ResourceInfo, VAlign[i]); VerifyResourcePitch(ResourceInfo, GMM_ULT_ALIGN(TileSize[i][0] * 4, PitchAlignment)); VerifyResourcePitchInTiles(ResourceInfo, GMM_ULT_ALIGN(TileSize[i][0] * 4, PitchAlignment) / TileSize[i][0]); VerifyResourceSize(ResourceInfo, GMM_ULT_ALIGN(TileSize[i][0] * 4, PitchAlignment) / TileSize[i][0] * 2 * 2 * GMM_KBYTE(4)); VerifyResourceQPitch(ResourceInfo, TileSize[i][1] * 2); //test main surface base alignment is 64KB //For Yf test main surface pitch is 4-tileYF aligned EXPECT_EQ(GMM_KBYTE(64), ResourceInfo->GetBaseAlignment()); EXPECT_EQ(0, ResourceInfo->GetRenderPitchTiles() % 4); // Check on YF only if(const_cast(pGfxAdapterInfo->SkuTable).FtrLinearCCS) { EXPECT_EQ(0, ResourceInfo->GetUnifiedAuxSurfaceOffset(GMM_AUX_CCS) % PAGE_SIZE); EXPECT_GE(ResourceInfo->GetSizeAuxSurface(GMM_AUX_CCS), ResourceInfo->GetSizeMainSurface() >> 8); } EXPECT_EQ(GMM_KBYTE(4), ResourceInfo->GetSizeAuxSurface(GMM_AUX_CCS)); ASSERT_LE(GMM_ULT_ALIGN(ResourceInfo->GetSizeMainSurface() / (GMM_KBYTE(16) / GMM_BYTES(64)), GMM_KBYTE(4)), ResourceInfo->GetSizeAuxSurface(GMM_AUX_CCS)); { //separate Aux gmmParams.Flags.Gpu.UnifiedAuxSurface = 0; GMM_RESOURCE_INFO *AuxResourceInfo; AuxResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); EXPECT_EQ(ResourceInfo->GetAuxHAlign(), AuxResourceInfo->GetHAlign()); EXPECT_EQ(ResourceInfo->GetAuxVAlign(), AuxResourceInfo->GetVAlign()); EXPECT_EQ(ResourceInfo->GetUnifiedAuxPitch(), AuxResourceInfo->GetRenderPitch()); EXPECT_EQ(ResourceInfo->GetSizeAuxSurface(GMM_AUX_CCS), AuxResourceInfo->GetSizeSurface()); pGmmULTClientContext->DestroyResInfoObject(AuxResourceInfo); } pGmmULTClientContext->DestroyResInfoObject(ResourceInfo); } } /// @brief ULT for 3D TileY Compressed Resource TEST_F(CTestGen12Resource, Test3DTileYCompressedResource) { if(!const_cast(pGfxAdapterInfo->SkuTable).FtrLinearCCS) { return; } // Horizontal/Verticle pixel alignment const uint32_t HAlign = {16}; const uint32_t VAlign = {4}; const uint32_t TileSize[3] = {128, 32, 1}; GMM_RESCREATE_PARAMS gmmParams = {}; gmmParams.Type = RESOURCE_3D; gmmParams.NoGfxMemory = 1; gmmParams.Flags.Info.TiledY = 1; gmmParams.Flags.Gpu.Texture = 1; gmmParams.Flags.Info.RenderCompressed = 1; // Turn on .MC or .RC flag - mandatory to tell compression-type, for Yf its also used to pad surf // to 4x1 tile (reqd by HW for perf reasons) // Allocate 1x1x1 surface for(uint32_t i = 0; i < TEST_BPP_MAX; i++) { // If unifiedAuxSurf reqd (mandatory for displayable or cross-device shared), turn on .CCS/.MMC and .UnifiedAuxSurface too gmmParams.Flags.Gpu.UnifiedAuxSurface = 1; //Turn off for separate aux creation gmmParams.Flags.Gpu.CCS = 1; //Turn off for separate aux creation TEST_BPP bpp = static_cast(i); GMM_TILE_MODE TileMode = LEGACY_TILE_Y; gmmParams.Format = SetResourceFormat(bpp); //gmmParams.BaseWidth64 = 0x30; //gmmParams.BaseHeight = 0x30; //gmmParams.Depth = 0x20; gmmParams.BaseWidth64 = 1; gmmParams.BaseHeight = 1; gmmParams.Depth = 1; const uint32_t PitchAlignment = 32; GMM_RESOURCE_INFO *ResourceInfo; ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); VerifyResourceHAlign(ResourceInfo, HAlign); VerifyResourceVAlign(ResourceInfo, VAlign); VerifyResourcePitch(ResourceInfo, GMM_ULT_ALIGN(gmmParams.BaseWidth64, TileSize[0] * 4)); VerifyResourcePitchInTiles(ResourceInfo, GMM_ULT_ALIGN(gmmParams.BaseWidth64, TileSize[0] * 4) / TileSize[0]); VerifyResourceSize(ResourceInfo, (GMM_ULT_ALIGN(gmmParams.BaseWidth64, TileSize[0] * 4) / TileSize[0]) * (GMM_ULT_ALIGN(gmmParams.BaseHeight, TileSize[1]) / TileSize[1]) * (GMM_ULT_ALIGN(gmmParams.Depth, TileSize[2]) / TileSize[2]) * GMM_KBYTE(4)); VerifyResourceQPitch(ResourceInfo, (GMM_ULT_ALIGN(gmmParams.BaseHeight, TileSize[1]))); //test main surface base alignment is 64KB //For Yf test main surface pitch is 4-tileYF aligned EXPECT_EQ(GMM_KBYTE(64), ResourceInfo->GetBaseAlignment()); EXPECT_EQ(0, ResourceInfo->GetRenderPitchTiles() % 4); // Check on YF only EXPECT_EQ(0, ResourceInfo->GetUnifiedAuxSurfaceOffset(GMM_AUX_CCS) % PAGE_SIZE); ASSERT_LE(GMM_ULT_ALIGN(ResourceInfo->GetSizeMainSurface() / (GMM_KBYTE(16) / GMM_BYTES(64)), GMM_KBYTE(4)), ResourceInfo->GetSizeAuxSurface(GMM_AUX_CCS)); { //separate Aux gmmParams.Flags.Gpu.UnifiedAuxSurface = 0; GMM_RESOURCE_INFO *AuxResourceInfo; AuxResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); EXPECT_EQ(ResourceInfo->GetAuxHAlign(), AuxResourceInfo->GetHAlign()); EXPECT_EQ(ResourceInfo->GetAuxVAlign(), AuxResourceInfo->GetVAlign()); EXPECT_EQ(ResourceInfo->GetUnifiedAuxPitch(), AuxResourceInfo->GetRenderPitch()); EXPECT_EQ(ResourceInfo->GetSizeAuxSurface(GMM_AUX_CCS), AuxResourceInfo->GetSizeSurface()); pGmmULTClientContext->DestroyResInfoObject(AuxResourceInfo); } pGmmULTClientContext->DestroyResInfoObject(ResourceInfo); } // Allocate 2 tiles in X dimension for(uint32_t i = 0; i < TEST_BPP_MAX; i++) { // If unifiedAuxSurf reqd (mandatory for displayable or cross-device shared), turn on .CCS/.MMC and .UnifiedAuxSurface too gmmParams.Flags.Gpu.UnifiedAuxSurface = 1; //Turn off for separate aux creation gmmParams.Flags.Gpu.CCS = 1; //Turn off for separate aux creation TEST_BPP bpp = static_cast(i); GMM_TILE_MODE TileMode = LEGACY_TILE_Y; gmmParams.Format = SetResourceFormat(bpp); gmmParams.BaseWidth64 = (TileSize[0] / GetBppValue(bpp)) + 1; gmmParams.BaseHeight = 0x1; gmmParams.Depth = 0x1; const uint32_t PitchAlignment = 32; GMM_RESOURCE_INFO *ResourceInfo; ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); VerifyResourceHAlign(ResourceInfo, HAlign); VerifyResourceVAlign(ResourceInfo, VAlign); VerifyResourcePitch(ResourceInfo, GMM_ULT_ALIGN(TileSize[0] * 4, PitchAlignment)); VerifyResourcePitchInTiles(ResourceInfo, GMM_ULT_ALIGN(TileSize[0] * 4, PitchAlignment) / TileSize[0]); VerifyResourceSize(ResourceInfo, GMM_ULT_ALIGN(TileSize[0] * 4, PitchAlignment) / TileSize[0] * GMM_KBYTE(4)); VerifyResourceQPitch(ResourceInfo, TileSize[1]); //test main surface base alignment is 64KB //For Yf test main surface pitch is 4-tileYF aligned EXPECT_EQ(GMM_KBYTE(64), ResourceInfo->GetBaseAlignment()); EXPECT_EQ(0, ResourceInfo->GetRenderPitchTiles() % 4); // Check on YF only EXPECT_EQ(GMM_KBYTE(4), ResourceInfo->GetSizeAuxSurface(GMM_AUX_CCS)); ASSERT_LE(GMM_ULT_ALIGN(ResourceInfo->GetSizeMainSurface() / (GMM_KBYTE(16) / GMM_BYTES(64)), GMM_KBYTE(4)), ResourceInfo->GetSizeAuxSurface(GMM_AUX_CCS)); { //separate Aux gmmParams.Flags.Gpu.UnifiedAuxSurface = 0; GMM_RESOURCE_INFO *AuxResourceInfo; AuxResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); EXPECT_EQ(ResourceInfo->GetAuxHAlign(), AuxResourceInfo->GetHAlign()); EXPECT_EQ(ResourceInfo->GetAuxVAlign(), AuxResourceInfo->GetVAlign()); EXPECT_EQ(ResourceInfo->GetUnifiedAuxPitch(), AuxResourceInfo->GetRenderPitch()); EXPECT_EQ(ResourceInfo->GetSizeAuxSurface(GMM_AUX_CCS), AuxResourceInfo->GetSizeSurface()); pGmmULTClientContext->DestroyResInfoObject(AuxResourceInfo); } pGmmULTClientContext->DestroyResInfoObject(ResourceInfo); } // Allocate 2 tiles in X/Y dimension for(uint32_t i = 0; i < TEST_BPP_MAX; i++) { // If unifiedAuxSurf reqd (mandatory for displayable or cross-device shared), turn on .CCS/.MMC and .UnifiedAuxSurface too gmmParams.Flags.Gpu.UnifiedAuxSurface = 1; //Turn off for separate aux creation gmmParams.Flags.Gpu.CCS = 1; //Turn off for separate aux creation TEST_BPP bpp = static_cast(i); GMM_TILE_MODE TileMode = LEGACY_TILE_Y; gmmParams.Format = SetResourceFormat(bpp); gmmParams.BaseWidth64 = (TileSize[0] / GetBppValue(bpp)) + 1; gmmParams.BaseHeight = TileSize[1] + 1; gmmParams.Depth = 0x1; const uint32_t PitchAlignment = 32; GMM_RESOURCE_INFO *ResourceInfo; ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); VerifyResourceHAlign(ResourceInfo, HAlign); VerifyResourceVAlign(ResourceInfo, VAlign); VerifyResourcePitch(ResourceInfo, GMM_ULT_ALIGN(TileSize[0] * 4, PitchAlignment)); VerifyResourcePitchInTiles(ResourceInfo, GMM_ULT_ALIGN(TileSize[0] * 4, PitchAlignment) / TileSize[0]); VerifyResourceSize(ResourceInfo, GMM_ULT_ALIGN(TileSize[0] * 4, PitchAlignment) / TileSize[0] * 2 * GMM_KBYTE(4)); VerifyResourceQPitch(ResourceInfo, TileSize[1] * 2); //test main surface base alignment is 64KB //For Yf test main surface pitch is 4-tileYF aligned EXPECT_EQ(GMM_KBYTE(64), ResourceInfo->GetBaseAlignment()); EXPECT_EQ(0, ResourceInfo->GetRenderPitchTiles() % 4); // Check on YF only EXPECT_EQ(0, ResourceInfo->GetUnifiedAuxSurfaceOffset(GMM_AUX_CCS) % PAGE_SIZE); EXPECT_EQ(GMM_KBYTE(4), ResourceInfo->GetSizeAuxSurface(GMM_AUX_CCS)); ASSERT_LE(GMM_ULT_ALIGN(ResourceInfo->GetSizeMainSurface() / (GMM_KBYTE(16) / GMM_BYTES(64)), GMM_KBYTE(4)), ResourceInfo->GetSizeAuxSurface(GMM_AUX_CCS)); { //separate Aux gmmParams.Flags.Gpu.UnifiedAuxSurface = 0; GMM_RESOURCE_INFO *AuxResourceInfo; AuxResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); EXPECT_EQ(ResourceInfo->GetAuxHAlign(), AuxResourceInfo->GetHAlign()); EXPECT_EQ(ResourceInfo->GetAuxVAlign(), AuxResourceInfo->GetVAlign()); EXPECT_EQ(ResourceInfo->GetUnifiedAuxPitch(), AuxResourceInfo->GetRenderPitch()); EXPECT_EQ(ResourceInfo->GetSizeAuxSurface(GMM_AUX_CCS), AuxResourceInfo->GetSizeSurface()); pGmmULTClientContext->DestroyResInfoObject(AuxResourceInfo); } pGmmULTClientContext->DestroyResInfoObject(ResourceInfo); } // Allocate 2 tiles in X/Y/Z dimension for(uint32_t i = 0; i < TEST_BPP_MAX; i++) { // If unifiedAuxSurf reqd (mandatory for displayable or cross-device shared), turn on .CCS/.MMC and .UnifiedAuxSurface too gmmParams.Flags.Gpu.UnifiedAuxSurface = 1; //Turn off for separate aux creation gmmParams.Flags.Gpu.CCS = 1; //Turn off for separate aux creation TEST_BPP bpp = static_cast(i); GMM_TILE_MODE TileMode = LEGACY_TILE_Y; gmmParams.Format = SetResourceFormat(bpp); gmmParams.BaseWidth64 = (TileSize[0] / GetBppValue(bpp)) + 1; gmmParams.BaseHeight = TileSize[1] + 1; gmmParams.Depth = TileSize[2] + 1; const uint32_t PitchAlignment = 32; GMM_RESOURCE_INFO *ResourceInfo; ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); VerifyResourceHAlign(ResourceInfo, HAlign); VerifyResourceVAlign(ResourceInfo, VAlign); VerifyResourcePitch(ResourceInfo, GMM_ULT_ALIGN(TileSize[0] * 4, PitchAlignment)); VerifyResourcePitchInTiles(ResourceInfo, GMM_ULT_ALIGN(TileSize[0] * 4, PitchAlignment) / TileSize[0]); VerifyResourceSize(ResourceInfo, GMM_ULT_ALIGN(TileSize[0] * 4, PitchAlignment) / TileSize[0] * 2 * 2 * GMM_KBYTE(4)); VerifyResourceQPitch(ResourceInfo, TileSize[1] * 2); //test main surface base alignment is 64KB //For Yf test main surface pitch is 4-tileYF aligned EXPECT_EQ(GMM_KBYTE(64), ResourceInfo->GetBaseAlignment()); EXPECT_EQ(0, ResourceInfo->GetRenderPitchTiles() % 4); // Check on YF only EXPECT_EQ(0, ResourceInfo->GetUnifiedAuxSurfaceOffset(GMM_AUX_CCS) % PAGE_SIZE); EXPECT_EQ(GMM_KBYTE(4), ResourceInfo->GetSizeAuxSurface(GMM_AUX_CCS)); ASSERT_LE(GMM_ULT_ALIGN(ResourceInfo->GetSizeMainSurface() / (GMM_KBYTE(16) / GMM_BYTES(64)), GMM_KBYTE(4)), ResourceInfo->GetSizeAuxSurface(GMM_AUX_CCS)); { //separate Aux gmmParams.Flags.Gpu.UnifiedAuxSurface = 0; GMM_RESOURCE_INFO *AuxResourceInfo; AuxResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); EXPECT_EQ(ResourceInfo->GetAuxHAlign(), AuxResourceInfo->GetHAlign()); EXPECT_EQ(ResourceInfo->GetAuxVAlign(), AuxResourceInfo->GetVAlign()); EXPECT_EQ(ResourceInfo->GetUnifiedAuxPitch(), AuxResourceInfo->GetRenderPitch()); EXPECT_EQ(ResourceInfo->GetSizeAuxSurface(GMM_AUX_CCS), AuxResourceInfo->GetSizeSurface()); pGmmULTClientContext->DestroyResInfoObject(AuxResourceInfo); } pGmmULTClientContext->DestroyResInfoObject(ResourceInfo); } } /// @brief ULT for 2D Yf mipped compressed resource TEST_F(CTestGen12Resource, Test2DTileYfMippedCompressedResource) { if(!const_cast(pGfxAdapterInfo->SkuTable).FtrLinearCCS) { return; } const uint32_t HAlign[TEST_BPP_MAX] = {64, 64, 32, 32, 16}; const uint32_t VAlign[TEST_BPP_MAX] = {64, 32, 32, 16, 16}; const uint32_t TileSize[TEST_BPP_MAX][2] = {{64, 64}, {128, 32}, {128, 32}, {256, 16}, {256, 16}}; const uint32_t MtsWidth[TEST_BPP_MAX] = {32, 32, 16, 16, 8}; const uint32_t MtsHeight[TEST_BPP_MAX] = {64, 32, 32, 16, 16}; GMM_RESCREATE_PARAMS gmmParams = {}; gmmParams.Type = RESOURCE_2D; gmmParams.NoGfxMemory = 1; gmmParams.Flags.Info.TiledY = 1; gmmParams.Flags.Info.TiledYf = 1; gmmParams.Flags.Gpu.Texture = 1; gmmParams.Flags.Info.RenderCompressed = 1; // Turn on .MC or .RC flag - mandatory to tell compression-type, for Yf its also used to pad surf // to 4x1 tile (reqd by HW for perf reasons) gmmParams.MaxLod = 4; gmmParams.ArraySize = 4; for(uint32_t i = 0; i < TEST_BPP_MAX; i++) { uint32_t AlignedWidth = 0; uint32_t AlignedHeight = 0; uint32_t ExpectedPitch = 0; uint32_t MipTailStartLod = 0; // Valigned Mip Heights uint32_t Mip0Height = 0; uint32_t Mip1Height = 0; uint32_t Mip2Height = 0; uint32_t Mip3Height = 0; uint32_t Mip2Higher = 0; // Sum of aligned heights of Mip2 and above uint32_t MipTailHeight = 0; // Haligned Mip Widths uint32_t Mip0Width = 0; uint32_t Mip1Width = 0; uint32_t Mip2Width = 0; TEST_BPP bpp = static_cast(i); gmmParams.Format = SetResourceFormat(bpp); gmmParams.BaseWidth64 = 0x38; gmmParams.BaseHeight = 0x38; // If unifiedAuxSurf reqd (mandatory for displayable or cross-device shared), turn on .CCS/.MMC and .UnifiedAuxSurface too gmmParams.Flags.Gpu.UnifiedAuxSurface = 1; //Turn off for separate aux creation gmmParams.Flags.Gpu.CCS = 1; //Turn off for separate aux creation GMM_RESOURCE_INFO *ResourceInfo; ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); VerifyResourceHAlign(ResourceInfo, HAlign[i]); VerifyResourceVAlign(ResourceInfo, VAlign[i]); // find the miptail start level { uint32_t MipWidth = gmmParams.BaseWidth64; uint32_t MipHeight = gmmParams.BaseHeight; while(!(MipWidth <= MtsWidth[i] && MipHeight <= MtsHeight[i])) { MipTailStartLod++; MipWidth = (uint32_t)(GMM_ULT_MAX(1, gmmParams.BaseWidth64 >> MipTailStartLod)); MipHeight = GMM_ULT_MAX(1, gmmParams.BaseHeight >> MipTailStartLod); } } // Mip resource Aligned Width calculation Mip0Width = GMM_ULT_ALIGN(gmmParams.BaseWidth64, HAlign[i]); Mip0Height = GMM_ULT_ALIGN(gmmParams.BaseHeight, VAlign[i]); if(MipTailStartLod == 1) { EXPECT_EQ(1, ResourceInfo->GetPackedMipTailStartLod()); // Block height...Mip0Height + Max(Mip1Height, Sum of Mip2Height..MipnHeight) Mip1Height = GMM_ULT_ALIGN(gmmParams.BaseHeight >> 1, VAlign[i]); AlignedWidth = Mip0Width; } if(MipTailStartLod == 2) { EXPECT_EQ(2, ResourceInfo->GetPackedMipTailStartLod()); // Block height...Mip0Height + Max(Mip1Height, Sum of Mip2Height..MipnHeight) Mip1Height = GMM_ULT_ALIGN(gmmParams.BaseHeight >> 1, VAlign[i]); Mip2Height = Mip2Higher = GMM_ULT_ALIGN(gmmParams.BaseHeight >> 2, VAlign[i]); Mip1Width = GMM_ULT_ALIGN(gmmParams.BaseWidth64 >> 1, HAlign[i]); Mip2Width = GMM_ULT_ALIGN(gmmParams.BaseWidth64 >> 2, HAlign[i]); AlignedWidth = GMM_ULT_MAX(Mip0Width, Mip1Width + Mip2Width); } if(MipTailStartLod == 3) { EXPECT_EQ(3, ResourceInfo->GetPackedMipTailStartLod()); // Block height...Mip0Height + Max(Mip1Height, Sum of Mip2Height..MipnHeight) Mip1Height = GMM_ULT_ALIGN(gmmParams.BaseHeight >> 1, VAlign[i]); Mip2Height = GMM_ULT_ALIGN(gmmParams.BaseHeight >> 2, VAlign[i]); // Miptail started lod MipTailHeight = VAlign[i]; Mip2Higher = Mip2Height + Mip3Height + MipTailHeight; Mip1Width = GMM_ULT_ALIGN(gmmParams.BaseWidth64 >> 1, HAlign[i]); Mip2Width = GMM_ULT_ALIGN(gmmParams.BaseWidth64 >> 2, HAlign[i]); AlignedWidth = GMM_ULT_MAX(Mip0Width, Mip1Width + Mip2Width); } uint32_t MaxHeight = GMM_ULT_MAX(Mip1Height, Mip2Higher); AlignedHeight = Mip0Height + MaxHeight; AlignedHeight = GMM_ULT_ALIGN(AlignedHeight, VAlign[i]); ExpectedPitch = AlignedWidth * GetBppValue(bpp); ExpectedPitch = GMM_ULT_ALIGN(ExpectedPitch, GMM_BYTES(32)); ExpectedPitch = GMM_ULT_ALIGN(ExpectedPitch, TileSize[i][0] * 4); //Only for displayables - 16K pitch align VerifyResourcePitch(ResourceInfo, ExpectedPitch); VerifyResourcePitchInTiles(ResourceInfo, static_cast(ExpectedPitch / TileSize[i][0])); VerifyResourceSize(ResourceInfo, GMM_ULT_ALIGN(ExpectedPitch * AlignedHeight * gmmParams.ArraySize, PAGE_SIZE)); VerifyResourceQPitch(ResourceInfo, AlignedHeight); //test main surface base alignment is 64KB //For Yf test main surface pitch is 4-tileYF aligned EXPECT_EQ(GMM_KBYTE(64), ResourceInfo->GetBaseAlignment()); EXPECT_EQ(0, ResourceInfo->GetRenderPitchTiles() % 4); // Check on YF only //Aux-size enough to cover all if(const_cast(pGfxAdapterInfo->SkuTable).FtrLinearCCS) { EXPECT_EQ(0, ResourceInfo->GetUnifiedAuxSurfaceOffset(GMM_AUX_CCS) % PAGE_SIZE); } EXPECT_EQ(GMM_KBYTE(4), ResourceInfo->GetSizeAuxSurface(GMM_AUX_CCS)); ASSERT_LE(GMM_ULT_ALIGN(ResourceInfo->GetSizeMainSurface() / (GMM_KBYTE(16) / GMM_BYTES(64)), GMM_KBYTE(4)), ResourceInfo->GetSizeAuxSurface(GMM_AUX_CCS)); pGmmULTClientContext->DestroyResInfoObject(ResourceInfo); } } /// @brief ULT for Linear Buffer Compressed Resource TEST_F(CTestGen12Resource, TestLinearCompressedResource) { // Horizontal pixel alignment const uint32_t MinPitch = 32; GMM_RESCREATE_PARAMS gmmParams = {}; gmmParams.Type = RESOURCE_BUFFER; gmmParams.NoGfxMemory = 1; gmmParams.Flags.Info.Linear = 1; gmmParams.Flags.Gpu.Texture = 1; gmmParams.Flags.Info.RenderCompressed = 1; // Allocate 1x1 surface for(uint32_t i = 0; i < TEST_BPP_MAX; i++) { gmmParams.Flags.Gpu.UnifiedAuxSurface = 1; //Turn off for separate aux creation gmmParams.Flags.Gpu.CCS = 1; //Turn off for separate aux creation TEST_BPP bpp = static_cast(i); gmmParams.Format = SetResourceFormat(bpp); gmmParams.BaseWidth64 = 0x1; gmmParams.BaseHeight = 1; gmmParams.Flags.Info.AllowVirtualPadding = (bpp != TEST_BPP_8); //OCL uses 8bpp buffers. doc doesn't comment if Linear buffer compr allowed or not on bpp!=8. GMM_RESOURCE_INFO *ResourceInfo; ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); uint32_t AlignedWidth = GMM_ULT_ALIGN(gmmParams.BaseWidth64, MinPitch); uint32_t PitchInBytes = AlignedWidth * GetBppValue(bpp); uint32_t AlignedSize = GMM_ULT_ALIGN(PitchInBytes, PAGE_SIZE); VerifyResourceHAlign(ResourceInfo, 0); VerifyResourceVAlign(ResourceInfo, 0); // N/A for buffer VerifyResourcePitch(ResourceInfo, 0); // N/A for buffer VerifyResourcePitchInTiles(ResourceInfo, 0); // N/A for linear VerifyResourceSize(ResourceInfo, AlignedSize); VerifyResourceQPitch(ResourceInfo, 0); // N/A for non-arrayed //test main surface base alignment is 64KB EXPECT_EQ(GMM_KBYTE(64), ResourceInfo->GetBaseAlignment()); EXPECT_EQ(0, ResourceInfo->GetUnifiedAuxSurfaceOffset(GMM_AUX_CCS) % PAGE_SIZE); ASSERT_LE(GMM_ULT_ALIGN(ResourceInfo->GetSizeMainSurface() / (GMM_KBYTE(16) / GMM_BYTES(64)), GMM_KBYTE(4)), ResourceInfo->GetSizeAuxSurface(GMM_AUX_CCS)); { //separate Aux gmmParams.Flags.Gpu.UnifiedAuxSurface = 0; GMM_RESOURCE_INFO *AuxResourceInfo; AuxResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); EXPECT_EQ(ResourceInfo->GetAuxHAlign(), AuxResourceInfo->GetHAlign()); EXPECT_EQ(ResourceInfo->GetAuxVAlign(), AuxResourceInfo->GetVAlign()); EXPECT_EQ(ResourceInfo->GetUnifiedAuxPitch(), AuxResourceInfo->GetRenderPitch()); EXPECT_EQ(ResourceInfo->GetSizeAuxSurface(GMM_AUX_CCS), AuxResourceInfo->GetSizeSurface()); pGmmULTClientContext->DestroyResInfoObject(AuxResourceInfo); } pGmmULTClientContext->DestroyResInfoObject(ResourceInfo); } // Allocate more than 1 page for(uint32_t i = 0; i < TEST_BPP_MAX; i++) { TEST_BPP bpp = static_cast(i); gmmParams.Format = SetResourceFormat(bpp); gmmParams.BaseWidth64 = 0x1001; gmmParams.BaseHeight = 1; gmmParams.Flags.Info.AllowVirtualPadding = (bpp != TEST_BPP_8); //OCL uses 8bpp buffers. document doesn't comment if Linear buffer compr allowed or not on bpp!=8. gmmParams.Flags.Gpu.UnifiedAuxSurface = 1; //Turn off for separate aux creation gmmParams.Flags.Gpu.CCS = 1; GMM_RESOURCE_INFO *ResourceInfo; ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); uint32_t AlignedWidth = GMM_ULT_ALIGN(gmmParams.BaseWidth64, MinPitch); uint32_t PitchInBytes = AlignedWidth * GetBppValue(bpp); uint32_t AlignedSize = GMM_ULT_ALIGN(PitchInBytes, PAGE_SIZE); VerifyResourceHAlign(ResourceInfo, MinPitch); VerifyResourceVAlign(ResourceInfo, 0); // N/A for buffer VerifyResourcePitch(ResourceInfo, 0); // N/A for buffer VerifyResourcePitchInTiles(ResourceInfo, 0); // N/A for linear VerifyResourceSize(ResourceInfo, AlignedSize); VerifyResourceQPitch(ResourceInfo, 0); // N/A for non-arrayed //test main surface base alignment is 64KB EXPECT_EQ(GMM_KBYTE(64), ResourceInfo->GetBaseAlignment()); EXPECT_EQ(0, ResourceInfo->GetUnifiedAuxSurfaceOffset(GMM_AUX_CCS) % PAGE_SIZE); ASSERT_LE(GMM_ULT_ALIGN(ResourceInfo->GetSizeMainSurface() / (GMM_KBYTE(16) / GMM_BYTES(64)), GMM_KBYTE(4)), ResourceInfo->GetSizeAuxSurface(GMM_AUX_CCS)); { //separate Aux gmmParams.Flags.Gpu.UnifiedAuxSurface = 0; GMM_RESOURCE_INFO *AuxResourceInfo; AuxResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); EXPECT_EQ(ResourceInfo->GetAuxHAlign(), AuxResourceInfo->GetHAlign()); EXPECT_EQ(ResourceInfo->GetAuxVAlign(), AuxResourceInfo->GetVAlign()); EXPECT_EQ(ResourceInfo->GetUnifiedAuxPitch(), AuxResourceInfo->GetRenderPitch()); EXPECT_EQ(ResourceInfo->GetSizeAuxSurface(GMM_AUX_CCS), AuxResourceInfo->GetSizeSurface()); pGmmULTClientContext->DestroyResInfoObject(AuxResourceInfo); } pGmmULTClientContext->DestroyResInfoObject(ResourceInfo); } } ///TODO Add MSAA/Depth Compressed Resource tests TEST_F(CTestGen12Resource, TestLosslessMSAACompressedResource) { } TEST_F(CTestGen12Resource, TestDepthHiZNotCompressedResource) { const uint32_t HAlign = 8; //HiZ alignment (16x4 ie general alignment), [Depth 16bit: 8x8; ow 8x4] uint32_t VAlign = 4; const uint32_t AllocTileSize[1][2] = {128, 32}; //HiZ is TileY GMM_RESCREATE_PARAMS gmmParams = {}; gmmParams.NoGfxMemory = 1; gmmParams.Flags.Info.TiledY = 1; //Not supported for Depth buffer, but HiZ output is TileY gmmParams.Flags.Gpu.Depth = 1; //GPU Flags= Depth + HiZ gmmParams.Flags.Gpu.HiZ = 1; gmmParams.Flags.Gpu.CCS = 0; gmmParams.Flags.Info.RenderCompressed = 0; gmmParams.Flags.Gpu.UnifiedAuxSurface = 1; for(uint32_t k = 0; k <= 1; k++) { gmmParams.Flags.Gpu.IndirectClearColor = k; // Allocate 1x1 surface so that it occupies 1 Tile in X dimension for(uint32_t j = TEST_BPP_8; j <= TEST_BPP_128; j++) //Depth bpp doesn't matter, Depth px dimensions decide HiZ size in HW { { VAlign = (j == TEST_BPP_16) ? 8 : 4; } gmmParams.Format = SetResourceFormat(static_cast(j)); //Only 16,24,32 supported; But driver creates the resource even for other bpps without failing for(uint32_t i = RESOURCE_2D; i <= RESOURCE_CUBE; i++) //3D doesn't support HiZ { gmmParams.Type = static_cast(i); gmmParams.BaseWidth64 = 0x1; gmmParams.BaseHeight = 0x1; //0x24; //not 1 tile //gmmParams.MaxLod = 6; --add expectedheight calc- mip0+max{mip1, sum{mip2,...n}} gmmParams.Depth = 0x1; if(i == RESOURCE_1D || i == RESOURCE_3D) // SKL+ 1D and 3D do not support HiZ { gmmParams.Flags.Gpu.HiZ = 0; } else { gmmParams.Flags.Gpu.HiZ = 1; } GMM_RESOURCE_INFO *ResourceInfo = NULL; ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); //EXPECT_NE(NULL, ResourceInfo); VerifyResourceHAlign(ResourceInfo, HAlign); VerifyResourceVAlign(ResourceInfo, VAlign); uint32_t ExpectedPitch = AllocTileSize[0][0]; VerifyResourcePitch(ResourceInfo, ExpectedPitch); VerifyResourcePitchInTiles(ResourceInfo, 1); // 1 tileY wide uint32_t ExpectedHeight = GMM_ULT_ALIGN(gmmParams.BaseHeight, VAlign); if(gmmParams.ArraySize > 1 || gmmParams.Type == RESOURCE_CUBE) { uint32_t ExpectedQPitch = GMM_ULT_ALIGN(gmmParams.BaseHeight, VAlign); ExpectedHeight *= (gmmParams.Type == RESOURCE_CUBE) ? 6 : 1; VerifyResourceQPitch(ResourceInfo, ExpectedQPitch); // Each face should be VAlign rows apart within a tile, } VerifyResourceSize(ResourceInfo, GFX_ALIGN(ExpectedPitch * ExpectedHeight, 1 * PAGE_SIZE)); //1 Tile should be enough if(gmmParams.Flags.Gpu.IndirectClearColor) { VerifyResourceAuxCCSize(ResourceInfo, PAGE_SIZE); } else { VerifyResourceAuxCCSize(ResourceInfo, 0); } pGmmULTClientContext->DestroyResInfoObject(ResourceInfo); } // Allocate 2 tiles in X dimension. (muti-tiles Tiles in Y dimension for cube/array) for(uint32_t i = RESOURCE_2D; i <= RESOURCE_CUBE; i++) { gmmParams.Type = static_cast(i); gmmParams.BaseWidth64 = AllocTileSize[0][0] + 0x1; gmmParams.BaseHeight = (gmmParams.Type == RESOURCE_1D) ? 0x1 : (gmmParams.Type == RESOURCE_CUBE) ? gmmParams.BaseWidth64 : VAlign / 2; gmmParams.ArraySize = (gmmParams.Type != RESOURCE_3D) ? VAlign : 1; gmmParams.Depth = 0x1; if(i == RESOURCE_1D || i == RESOURCE_3D) { gmmParams.Flags.Gpu.HiZ = 0; } else { gmmParams.Flags.Gpu.HiZ = 1; } GMM_RESOURCE_INFO *ResourceInfo; ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); VerifyResourceHAlign(ResourceInfo, HAlign); VerifyResourceVAlign(ResourceInfo, VAlign); uint32_t ExpectedPitch = GFX_ALIGN(gmmParams.BaseWidth * (int)pow(2, j), AllocTileSize[0][0]); VerifyResourcePitch(ResourceInfo, ExpectedPitch); VerifyResourcePitchInTiles(ResourceInfo, ExpectedPitch / AllocTileSize[0][0]); uint32_t ExpectedQPitch = 0; if(gmmParams.ArraySize > 1 || gmmParams.Type == RESOURCE_CUBE) { ExpectedQPitch = GMM_ULT_ALIGN(gmmParams.BaseHeight, VAlign); VerifyResourceQPitch(ResourceInfo, ExpectedQPitch); // Each face should be VAlign rows apart within a tile. } VerifyResourceSize(ResourceInfo, // PitchInBytes * Rows where Rows = (__GMM_MAX_CUBE_FACE x QPitch) /2 (Stencil height = halved due to interleaving), then aligned to tile boundary ((gmmParams.Type == RESOURCE_CUBE) ? ExpectedPitch * GMM_ULT_ALIGN(ExpectedQPitch * gmmParams.ArraySize * __GMM_MAX_CUBE_FACE, AllocTileSize[0][1]) : //cube ((gmmParams.ArraySize > 1) ? ExpectedPitch * GMM_ULT_ALIGN(ExpectedQPitch * gmmParams.ArraySize, AllocTileSize[0][1]) : //array ExpectedPitch * GMM_ULT_ALIGN(gmmParams.BaseHeight, AllocTileSize[0][1])))); if(gmmParams.Flags.Gpu.IndirectClearColor) { VerifyResourceAuxCCSize(ResourceInfo, PAGE_SIZE); } else { VerifyResourceAuxCCSize(ResourceInfo, 0); } pGmmULTClientContext->DestroyResInfoObject(ResourceInfo); } // Allocate 2 tiles in X, 3 tiles in Y dimension (non-arrayed) Multi-tiles for 3D for(uint32_t i = RESOURCE_2D; i <= RESOURCE_3D; i++) { gmmParams.Type = static_cast(i); gmmParams.BaseWidth64 = AllocTileSize[0][0] + 0x1; gmmParams.BaseHeight = 2 * AllocTileSize[0][1] + 0x1; //Half-Depth Height or QPitch (lod!=0), aligned to 8 required by HW gmmParams.Depth = (gmmParams.Type == RESOURCE_2D) ? 0x1 : VAlign + 1; gmmParams.ArraySize = 1; if(i == RESOURCE_1D || i == RESOURCE_3D) { gmmParams.Flags.Gpu.HiZ = 0; } else { gmmParams.Flags.Gpu.HiZ = 1; } GMM_RESOURCE_INFO *ResourceInfo; ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); VerifyResourceHAlign(ResourceInfo, HAlign); VerifyResourceVAlign(ResourceInfo, VAlign); uint32_t ExpectedPitch = GFX_ALIGN(gmmParams.BaseWidth * (int)pow(2, j), AllocTileSize[0][0]); VerifyResourcePitch(ResourceInfo, ExpectedPitch); VerifyResourcePitchInTiles(ResourceInfo, ExpectedPitch / AllocTileSize[0][0]); // 2 tile wide uint32_t TwoDQPitch, ExpectedQPitch = 0; if(gmmParams.Type == RESOURCE_3D) { TwoDQPitch = GMM_ULT_ALIGN(gmmParams.BaseHeight, VAlign); ExpectedQPitch = GFX_ALIGN(TwoDQPitch, AllocTileSize[0][1]); //Depth slices arranged as 2D-arrayed slices. VerifyResourceQPitch(ResourceInfo, ExpectedQPitch); } else { //HiZ for 3D not supported. Driver still allocates like IVB/HSW. VerifyResourceSize(ResourceInfo, ExpectedPitch * GMM_ULT_ALIGN(gmmParams.BaseHeight, AllocTileSize[0][1])); } pGmmULTClientContext->DestroyResInfoObject(ResourceInfo); } } } } ///TODO Add MSAA/Depth Compressed Resource tests TEST_F(CTestGen12Resource, DISABLED_TestDepthCompressedResource) { const uint32_t HAlign = 8; //HiZ alignment (16x4 ie general alignment), [Depth 16bit: 8x8; ow 8x4] uint32_t VAlign = 4; // 8; Need to debug why driver uses VAlign/2 //const uint32_t DepthTileSize[1][2] = { 64, 64 }; //Depth/Stencil buffer should be TileY/Ys/Yf only (16,24,32 bpp only) no 3D or MSAA const uint32_t AllocTileSize[1][2] = {128, 32}; //HiZ is TileY GMM_RESCREATE_PARAMS gmmParams = {}; gmmParams.NoGfxMemory = 1; gmmParams.Flags.Info.TiledY = 1; //Not supported for Depth buffer, but HiZ output is TileY gmmParams.Flags.Gpu.Depth = 1; //GPU Flags= Depth/SeparateStencil + HiZ gmmParams.Flags.Gpu.HiZ = 1; gmmParams.Flags.Gpu.IndirectClearColor = 1; gmmParams.Flags.Gpu.CCS = 1; gmmParams.Flags.Info.RenderCompressed = 1; gmmParams.Flags.Gpu.UnifiedAuxSurface = 1; // Allocate 1x1 surface so that it occupies 1 Tile in X dimension for(uint32_t j = TEST_BPP_8; j <= TEST_BPP_128; j++) //Depth bpp doesn't matter, Depth px dimensions decide HiZ size in HW { { VAlign = (j == TEST_BPP_16) ? 8 : 4; } gmmParams.Format = SetResourceFormat(static_cast(j)); //Only 16,24,32 supported; But driver creates the resource even for other bpps without failing for(uint32_t i = RESOURCE_2D; i <= RESOURCE_CUBE; i++) //3D doesn't support HiZ - test driver returns proper? { gmmParams.Type = static_cast(i); gmmParams.BaseWidth64 = 0x1; gmmParams.BaseHeight = 0x1; //0x24; //not 1 tile //gmmParams.MaxLod = 6; --add expectedheight calc- mip0+max{mip1, sum{mip2,...n}} gmmParams.Depth = 0x1; if(i == RESOURCE_1D || i == RESOURCE_3D) { gmmParams.Flags.Gpu.HiZ = 0; } GMM_RESOURCE_INFO *ResourceInfo = NULL; ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); //EXPECT_NE(NULL, ResourceInfo); VerifyResourceHAlign(ResourceInfo, HAlign); VerifyResourceVAlign(ResourceInfo, VAlign); uint32_t ExpectedPitch = AllocTileSize[0][0] * 4; VerifyResourcePitch(ResourceInfo, ExpectedPitch); VerifyResourcePitchInTiles(ResourceInfo, 4); // 1 tileY wide uint32_t ExpectedHeight = GMM_ULT_ALIGN(gmmParams.BaseHeight, VAlign); if(gmmParams.ArraySize > 1 || gmmParams.Type == RESOURCE_CUBE) { uint32_t ExpectedQPitch = GMM_ULT_ALIGN(gmmParams.BaseHeight, VAlign); //Apply formula as per specification ExpectedQPitch = GMM_ULT_ALIGN(ExpectedQPitch / 2, VAlign); ExpectedHeight *= (gmmParams.Type == RESOURCE_CUBE) ? 6 : 1; VerifyResourceQPitch(ResourceInfo, ExpectedQPitch); // Each face should be VAlign rows apart within a tile, Turn on verification after clarity } VerifyResourceSize(ResourceInfo, GFX_ALIGN(ExpectedPitch * ExpectedHeight, 4 * PAGE_SIZE)); //1 Tile should be enough pGmmULTClientContext->DestroyResInfoObject(ResourceInfo); } // Allocate 2 tiles in X dimension. (muti-tiles Tiles in Y dimension for cube/array) for(uint32_t i = RESOURCE_2D; i <= RESOURCE_CUBE; i++) { gmmParams.Type = static_cast(i); gmmParams.BaseWidth64 = AllocTileSize[0][0] + 0x1; gmmParams.BaseHeight = (gmmParams.Type == RESOURCE_1D) ? 0x1 : (gmmParams.Type == RESOURCE_CUBE) ? gmmParams.BaseWidth64 : VAlign / 2; gmmParams.ArraySize = (gmmParams.Type != RESOURCE_3D) ? VAlign : 1; // Gen8 doesn't support 3D-arrays (so HiZ not supported) [test 3d arrays once -- HiZ would fail but ResCreate doesn't?] gmmParams.Depth = 0x1; GMM_RESOURCE_INFO *ResourceInfo; ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); VerifyResourceHAlign(ResourceInfo, HAlign); VerifyResourceVAlign(ResourceInfo, VAlign); uint32_t ExpectedPitch = GFX_ALIGN(gmmParams.BaseWidth * (int)pow(2, j), AllocTileSize[0][0] * 4); VerifyResourcePitch(ResourceInfo, ExpectedPitch); VerifyResourcePitchInTiles(ResourceInfo, 4); // 2 tileY wide uint32_t ExpectedQPitch = 0; if(gmmParams.ArraySize > 1 || gmmParams.Type == RESOURCE_CUBE) { ExpectedQPitch = GMM_ULT_ALIGN(gmmParams.BaseHeight, VAlign); //ExpectedQPitch = GMM_ULT_ALIGN(ExpectedQPitch / 2, VAlign); VerifyResourceQPitch(ResourceInfo, ExpectedQPitch); // Each face should be VAlign rows apart within a tile. Turn on verification after clarity } VerifyResourceSize(ResourceInfo, // PitchInBytes * Rows where Rows = (__GMM_MAX_CUBE_FACE x QPitch) /2 (Stencil height = halved due to interleaving), then aligned to tile boundary ((gmmParams.Type == RESOURCE_CUBE) ? ExpectedPitch * GMM_ULT_ALIGN(ExpectedQPitch * gmmParams.ArraySize * __GMM_MAX_CUBE_FACE, AllocTileSize[0][1]) : //cube ((gmmParams.ArraySize > 1) ? ExpectedPitch * GMM_ULT_ALIGN(ExpectedQPitch * gmmParams.ArraySize, AllocTileSize[0][1]) : //array 4 * GMM_KBYTE(4)))); pGmmULTClientContext->DestroyResInfoObject(ResourceInfo); } // Allocate 2 tiles in X/Y dimension (non-arrayed) Multi-tiles for 3D for(uint32_t i = RESOURCE_2D; i <= RESOURCE_3D; i++) { gmmParams.Type = static_cast(i); gmmParams.BaseWidth64 = AllocTileSize[0][0] + 0x1; gmmParams.BaseHeight = 2 * AllocTileSize[0][1] + 0x1; //Half-Depth Height or QPitch (lod!=0), aligned to 8 required by HW gmmParams.Depth = (gmmParams.Type == RESOURCE_2D) ? 0x1 : VAlign + 1; gmmParams.ArraySize = 1; GMM_RESOURCE_INFO *ResourceInfo; ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); VerifyResourceHAlign(ResourceInfo, HAlign); VerifyResourceVAlign(ResourceInfo, VAlign); uint32_t ExpectedPitch = AllocTileSize[0][0] * 4; VerifyResourcePitch(ResourceInfo, ExpectedPitch); VerifyResourcePitchInTiles(ResourceInfo, 4); // 2 tile wide uint32_t TwoDQPitch, ExpectedQPitch = 0; if(gmmParams.Type == RESOURCE_3D) { TwoDQPitch = GMM_ULT_ALIGN(gmmParams.BaseHeight, VAlign); ExpectedQPitch = gmmParams.Depth * GMM_ULT_ALIGN(TwoDQPitch / 2, VAlign); //Depth slices arranged as 2D-arrayed slices. } else { //HiZ for 3D not supported. Driver still allocates like IVB/HSW. (should Qpitch or only overall buffer height be Valigned ?) VerifyResourceSize(ResourceInfo, ((gmmParams.Type == RESOURCE_3D) ? ExpectedPitch * GMM_ULT_ALIGN(ExpectedQPitch, AllocTileSize[0][1]) : 2 * 2 * GMM_KBYTE(4))); } pGmmULTClientContext->DestroyResInfoObject(ResourceInfo); } } } TEST_F(CTestGen12Resource, TestStencilCompressedResource) { const uint32_t HAlign = {16}; const uint32_t VAlign = {8}; const uint32_t TileSize[2] = {128, 32}; GMM_RESCREATE_PARAMS gmmParams = {}; gmmParams.Type = RESOURCE_2D; gmmParams.NoGfxMemory = 1; gmmParams.Flags.Info.TiledY = 1; //gmmParams.ArraySize = 4; gmmParams.Flags.Gpu.SeparateStencil = 1; gmmParams.Flags.Info.RenderCompressed = 1; // Turn on .MC or .RC flag - mandatory to tell compression-type, for Yf its also used to pad surf // to 4x1 tile (reqd by HW for perf reasons) // If unifiedAuxSurf reqd (mandatory for displayable or cross-adapter shared), turn on .CCS/.MMC and .UnifiedAuxSurface too //Allocate 1x1 surface { gmmParams.Flags.Gpu.UnifiedAuxSurface = 1; //Turn off for separate aux creation gmmParams.Flags.Gpu.CCS = 1; //Turn off for separate aux creation gmmParams.Flags.Gpu.IndirectClearColor = 1; TEST_BPP bpp = static_cast(TEST_BPP_8); GMM_TILE_MODE TileMode = LEGACY_TILE_Y; gmmParams.Format = SetResourceFormat(bpp); gmmParams.BaseWidth64 = 0x1; gmmParams.BaseHeight = 0x1; GMM_RESOURCE_INFO *ResourceInfo; ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); VerifyResourceHAlign(ResourceInfo, HAlign); VerifyResourceVAlign(ResourceInfo, VAlign); VerifyResourcePitch(ResourceInfo, 4 * TileSize[0]); // As wide as 4 Tile VerifyResourcePitchInTiles(ResourceInfo, 4); // 4 Tile wide VerifyResourceSize(ResourceInfo, 4 * GMM_KBYTE(4)); // 4 Tile Big VerifyResourceQPitch(ResourceInfo, 0); // Not Tested //test main surface base alignment is 64KB //For Yf test main surface pitch is 4-tileYF aligned EXPECT_EQ(GMM_KBYTE(64), ResourceInfo->GetBaseAlignment()); EXPECT_EQ(0, ResourceInfo->GetRenderPitchTiles() % 4); // Check on YF only EXPECT_EQ(0, ResourceInfo->GetUnifiedAuxSurfaceOffset(GMM_AUX_CCS) % PAGE_SIZE); EXPECT_EQ(GMM_KBYTE(4), ResourceInfo->GetSizeAuxSurface(GMM_AUX_CCS)); { //separate Aux gmmParams.Flags.Gpu.UnifiedAuxSurface = 0; GMM_RESOURCE_INFO *AuxResourceInfo; AuxResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); EXPECT_EQ(ResourceInfo->GetAuxHAlign(), AuxResourceInfo->GetHAlign()); EXPECT_EQ(ResourceInfo->GetAuxVAlign(), AuxResourceInfo->GetVAlign()); EXPECT_EQ(ResourceInfo->GetUnifiedAuxPitch(), AuxResourceInfo->GetRenderPitch()); EXPECT_EQ(ResourceInfo->GetSizeAuxSurface(GMM_AUX_CCS), AuxResourceInfo->GetSizeSurface()); pGmmULTClientContext->DestroyResInfoObject(AuxResourceInfo); } pGmmULTClientContext->DestroyResInfoObject(ResourceInfo); } // Allocate surface that requires multi tiles in two dimension // Allocate 2 tiles in X dimension { gmmParams.Flags.Gpu.UnifiedAuxSurface = 1; //Turn off for separate aux creation gmmParams.Flags.Gpu.CCS = 1; //Turn off for separate aux creation TEST_BPP bpp = static_cast(TEST_BPP_8); GMM_TILE_MODE TileMode = LEGACY_TILE_Y; gmmParams.Format = SetResourceFormat(bpp); gmmParams.BaseWidth64 = (TileSize[0] / GetBppValue(bpp)) + 1; // 1 pixel larger than 1 tile width gmmParams.BaseHeight = 0x1; gmmParams.Depth = 0x1; GMM_RESOURCE_INFO *ResourceInfo; ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); VerifyResourceHAlign(ResourceInfo, HAlign); VerifyResourceVAlign(ResourceInfo, VAlign); VerifyResourcePitch(ResourceInfo, TileSize[0] * 4); // As wide as 2 tile, but 4-tile pitch alignment VerifyResourcePitchInTiles(ResourceInfo, 4); // 2 tile wide, but 4-tile pitch alignment VerifyResourceSize(ResourceInfo, GMM_KBYTE(4) * 4); // 2 tile big, but 4-tile pitch alignment VerifyResourceQPitch(ResourceInfo, 0); // Not tested //test main surface base alignment is 64KB //For Y test main surface pitch is 4-tileY aligned EXPECT_EQ(GMM_KBYTE(64), ResourceInfo->GetBaseAlignment()); EXPECT_EQ(0, ResourceInfo->GetRenderPitchTiles() % 4); EXPECT_EQ(0, ResourceInfo->GetUnifiedAuxSurfaceOffset(GMM_AUX_CCS) % PAGE_SIZE); EXPECT_EQ(GMM_KBYTE(4), ResourceInfo->GetSizeAuxSurface(GMM_AUX_CCS)); { //separate Aux gmmParams.Flags.Gpu.UnifiedAuxSurface = 0; GMM_RESOURCE_INFO *AuxResourceInfo; AuxResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); EXPECT_EQ(ResourceInfo->GetAuxHAlign(), AuxResourceInfo->GetHAlign()); EXPECT_EQ(ResourceInfo->GetAuxVAlign(), AuxResourceInfo->GetVAlign()); EXPECT_EQ(ResourceInfo->GetUnifiedAuxPitch(), AuxResourceInfo->GetRenderPitch()); EXPECT_EQ(ResourceInfo->GetSizeAuxSurface(GMM_AUX_CCS), AuxResourceInfo->GetSizeSurface()); pGmmULTClientContext->DestroyResInfoObject(AuxResourceInfo); } pGmmULTClientContext->DestroyResInfoObject(ResourceInfo); } // Allocate surface that requires multi tiles in two dimension // Allocate 2 tiles in X/Y dimension { gmmParams.Flags.Gpu.UnifiedAuxSurface = 1; //Turn off for separate aux creation gmmParams.Flags.Gpu.CCS = 1; //Turn off for separate aux creation gmmParams.Flags.Gpu.IndirectClearColor = 1; TEST_BPP bpp = static_cast(TEST_BPP_8); GMM_TILE_MODE TileMode = LEGACY_TILE_Y; gmmParams.Format = SetResourceFormat(bpp); gmmParams.BaseWidth64 = (TileSize[0] / GetBppValue(bpp)) + 1; // 1 pixel larger than 1 tile width gmmParams.BaseHeight = TileSize[1] + 1; // 1 row larger than 1 tile height gmmParams.Depth = 0x1; GMM_RESOURCE_INFO *ResourceInfo; ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); VerifyResourceHAlign(ResourceInfo, HAlign); VerifyResourceVAlign(ResourceInfo, VAlign); VerifyResourcePitch(ResourceInfo, TileSize[0] * 4); // As wide as 2 tile, but 4-tile pitch alignment VerifyResourcePitchInTiles(ResourceInfo, 4); // 2 tile wide, but 4-tile pitch alignment VerifyResourceSize(ResourceInfo, GMM_KBYTE(4) * 4 * 2); // 4 tile wide; and 2-tile high VerifyResourceQPitch(ResourceInfo, 0); // Not tested //test main surface base alignment is 64KB //For Y test main surface pitch is 4-tileY aligned EXPECT_EQ(GMM_KBYTE(64), ResourceInfo->GetBaseAlignment()); EXPECT_EQ(0, ResourceInfo->GetRenderPitchTiles() % 4); EXPECT_EQ(0, ResourceInfo->GetUnifiedAuxSurfaceOffset(GMM_AUX_CCS) % PAGE_SIZE); EXPECT_EQ(GMM_KBYTE(4), ResourceInfo->GetSizeAuxSurface(GMM_AUX_CCS)); { //separate Aux gmmParams.Flags.Gpu.UnifiedAuxSurface = 0; GMM_RESOURCE_INFO *AuxResourceInfo; AuxResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); EXPECT_EQ(ResourceInfo->GetAuxHAlign(), AuxResourceInfo->GetHAlign()); EXPECT_EQ(ResourceInfo->GetAuxVAlign(), AuxResourceInfo->GetVAlign()); EXPECT_EQ(ResourceInfo->GetUnifiedAuxPitch(), AuxResourceInfo->GetRenderPitch()); EXPECT_EQ(ResourceInfo->GetSizeAuxSurface(GMM_AUX_CCS), AuxResourceInfo->GetSizeSurface()); pGmmULTClientContext->DestroyResInfoObject(AuxResourceInfo); } pGmmULTClientContext->DestroyResInfoObject(ResourceInfo); } } /// @brief ULT for 2D TileYf Compressed Resource TEST_F(CTestGen12Resource, Test2DTileYfAMFSResource) { const uint32_t HAlign[TEST_BPP_MAX] = {64, 64, 32, 32, 16}; const uint32_t VAlign[TEST_BPP_MAX] = {64, 32, 32, 16, 16}; const uint32_t TileSize[TEST_BPP_MAX][2] = {{64, 64}, {128, 32}, {128, 32}, {256, 16}, {256, 16}}; GMM_RESCREATE_PARAMS gmmParams = {}; gmmParams.Type = RESOURCE_2D; gmmParams.NoGfxMemory = 1; gmmParams.Flags.Info.TiledY = 1; gmmParams.Flags.Info.TiledYf = 1; gmmParams.Flags.Gpu.Texture = 1; gmmParams.Flags.Gpu.ProceduralTexture = 1; // If unifiedAuxSurf reqd (mandatory for displayable or cross-adapter shared), turn on .CCS/.MMC and .UnifiedAuxSurface too //Allocate 1x1 surface for(uint32_t i = 0; i < TEST_BPP_MAX; i++) { gmmParams.Flags.Gpu.UnifiedAuxSurface = 1; //Turn off for separate aux creation gmmParams.Flags.Gpu.CCS = 1; //Turn off for separate aux creation //gmmParams.Flags.Gpu.MMC = 0; //Turn on to check unifiedaux creation TEST_BPP bpp = static_cast(i); GMM_TILE_MODE TileMode = DEFINE_TILE(YF_2D, bpp); gmmParams.Format = SetResourceFormat(bpp); gmmParams.BaseWidth64 = 0x1; gmmParams.BaseHeight = 0x1; GMM_RESOURCE_INFO *ResourceInfo; ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); VerifyResourceHAlign(ResourceInfo, HAlign[i]); VerifyResourceVAlign(ResourceInfo, VAlign[i]); VerifyResourcePitch(ResourceInfo, TileSize[i][0]); // As wide as 1 Tile VerifyResourcePitchInTiles(ResourceInfo, 1); // 1 Tile wide //VerifyResourceSize(ResourceInfo, GMM_KBYTE(4)); // 1 Tile Big, old behaviour consuming bytes for main-surface (paired Texture dimensions) only used to obtain GPUVA for indirect (Auxtable mapped) CCS access by sampler. VerifyResourceSize(ResourceInfo, 0); // New behaviour, optimized SFT size, sampler doesn't access CCS via main.. kernels refer the CCS-via its GPUVA (w/o main). VerifyResourceQPitch(ResourceInfo, 0); // Not Tested //test main surface base alignment is 4KB, since AMFS PT isn't compressed //but uses same linear CCS as compression EXPECT_EQ(GMM_KBYTE(4), ResourceInfo->GetBaseAlignment()); EXPECT_EQ(0, ResourceInfo->GetUnifiedAuxSurfaceOffset(GMM_AUX_CCS) % PAGE_SIZE); EXPECT_EQ(GMM_KBYTE(4), ResourceInfo->GetSizeAuxSurface(GMM_AUX_CCS)); { //separate Aux gmmParams.Flags.Gpu.UnifiedAuxSurface = 0; GMM_RESOURCE_INFO *AuxResourceInfo; AuxResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); EXPECT_EQ(ResourceInfo->GetAuxHAlign(), AuxResourceInfo->GetHAlign()); EXPECT_EQ(ResourceInfo->GetAuxVAlign(), AuxResourceInfo->GetVAlign()); EXPECT_EQ(ResourceInfo->GetUnifiedAuxPitch(), AuxResourceInfo->GetRenderPitch()); EXPECT_EQ(ResourceInfo->GetSizeAuxSurface(GMM_AUX_CCS), AuxResourceInfo->GetSizeSurface()); EXPECT_EQ(0, AuxResourceInfo->GmmGetTileMode()); pGmmULTClientContext->DestroyResInfoObject(AuxResourceInfo); } pGmmULTClientContext->DestroyResInfoObject(ResourceInfo); } // Allocate surface that requires multi tiles in two dimension // Allocate 2 tiles in X dimension for(uint32_t i = 0; i < TEST_BPP_MAX; i++) { gmmParams.Flags.Gpu.UnifiedAuxSurface = 1; //Turn off for separate aux creation gmmParams.Flags.Gpu.CCS = 1; //Turn off for separate aux creation TEST_BPP bpp = static_cast(i); GMM_TILE_MODE TileMode = DEFINE_TILE(YF_2D, bpp); gmmParams.Format = SetResourceFormat(bpp); gmmParams.BaseWidth64 = (TileSize[i][0] / GetBppValue(bpp)) + 1; // 1 pixel larger than 1 tile width gmmParams.BaseHeight = 0x1; gmmParams.Depth = 0x1; GMM_RESOURCE_INFO *ResourceInfo; ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); VerifyResourceHAlign(ResourceInfo, HAlign[i]); VerifyResourceVAlign(ResourceInfo, VAlign[i]); VerifyResourcePitch(ResourceInfo, TileSize[i][0] * 2); // As wide as 2 tile VerifyResourcePitchInTiles(ResourceInfo, 2); // 2 tile wide //VerifyResourceSize(ResourceInfo, GMM_KBYTE(4) * 2); // 2 tile big, old behaviour consuming bytes for main-surface (paired Texture dimensions) only used to obtain GPUVA for indirect (Auxtable mapped) CCS access by sampler. VerifyResourceSize(ResourceInfo, 0); // New behaviour, optimized SFT size, sampler doesn't access CCS via main.. kernels refer the CCS-via its GPUVA (w/o main). VerifyResourceQPitch(ResourceInfo, 0); // Not tested //test main surface base alignment is 4KB EXPECT_EQ(GMM_KBYTE(4), ResourceInfo->GetBaseAlignment()); EXPECT_EQ(0, ResourceInfo->GetUnifiedAuxSurfaceOffset(GMM_AUX_CCS) % PAGE_SIZE); EXPECT_EQ(GMM_KBYTE(4), ResourceInfo->GetSizeAuxSurface(GMM_AUX_CCS)); { //separate Aux gmmParams.Flags.Gpu.UnifiedAuxSurface = 0; GMM_RESOURCE_INFO *AuxResourceInfo; AuxResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); EXPECT_EQ(ResourceInfo->GetAuxHAlign(), AuxResourceInfo->GetHAlign()); EXPECT_EQ(ResourceInfo->GetAuxVAlign(), AuxResourceInfo->GetVAlign()); EXPECT_EQ(ResourceInfo->GetUnifiedAuxPitch(), AuxResourceInfo->GetRenderPitch()); EXPECT_EQ(ResourceInfo->GetSizeAuxSurface(GMM_AUX_CCS), AuxResourceInfo->GetSizeSurface()); EXPECT_EQ(0, AuxResourceInfo->GmmGetTileMode()); pGmmULTClientContext->DestroyResInfoObject(AuxResourceInfo); } pGmmULTClientContext->DestroyResInfoObject(ResourceInfo); } // Allocate surface that requires multi tiles in two dimension // Allocate 2 tiles in X/Y dimension for(uint32_t i = 0; i < TEST_BPP_MAX; i++) { gmmParams.Flags.Gpu.UnifiedAuxSurface = 1; //Turn off for separate aux creation gmmParams.Flags.Gpu.CCS = 1; //Turn off for separate aux creation TEST_BPP bpp = static_cast(i); GMM_TILE_MODE TileMode = DEFINE_TILE(YF_2D, bpp); gmmParams.Format = SetResourceFormat(bpp); gmmParams.BaseWidth64 = (TileSize[i][0] / GetBppValue(bpp)) + 1; // 1 pixel larger than 1 tile width gmmParams.BaseHeight = TileSize[i][1] + 1; // 1 row larger than 1 tile height gmmParams.Depth = 0x1; GMM_RESOURCE_INFO *ResourceInfo; ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); VerifyResourceHAlign(ResourceInfo, HAlign[i]); VerifyResourceVAlign(ResourceInfo, VAlign[i]); VerifyResourcePitch(ResourceInfo, TileSize[i][0] * 2); // As wide as 2 tile VerifyResourcePitchInTiles(ResourceInfo, 2); // 2 tile wide //VerifyResourceSize(ResourceInfo, GMM_KBYTE(4) * 2 * 2); // 2 tile wide; and 2-tile high, old behaviour consuming bytes for main-surface (paired Texture dimensions) only used to obtain GPUVA for indirect (Auxtable mapped) CCS access by sampler. VerifyResourceSize(ResourceInfo, 0); // New behaviour, optimized SFT size, sampler doesn't access CCS via main.. kernels refer the CCS-via its GPUVA (w/o main). VerifyResourceQPitch(ResourceInfo, 0); // Not tested //test main surface base alignment is 4KB EXPECT_EQ(GMM_KBYTE(4), ResourceInfo->GetBaseAlignment()); EXPECT_EQ(0, ResourceInfo->GetUnifiedAuxSurfaceOffset(GMM_AUX_CCS) % PAGE_SIZE); EXPECT_EQ(GMM_KBYTE(4), ResourceInfo->GetSizeAuxSurface(GMM_AUX_CCS)); { //separate Aux gmmParams.Flags.Gpu.UnifiedAuxSurface = 0; GMM_RESOURCE_INFO *AuxResourceInfo; AuxResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); EXPECT_EQ(ResourceInfo->GetAuxHAlign(), AuxResourceInfo->GetHAlign()); EXPECT_EQ(ResourceInfo->GetAuxVAlign(), AuxResourceInfo->GetVAlign()); EXPECT_EQ(ResourceInfo->GetUnifiedAuxPitch(), AuxResourceInfo->GetRenderPitch()); EXPECT_EQ(ResourceInfo->GetSizeAuxSurface(GMM_AUX_CCS), AuxResourceInfo->GetSizeSurface()); EXPECT_EQ(0, AuxResourceInfo->GmmGetTileMode()); pGmmULTClientContext->DestroyResInfoObject(AuxResourceInfo); } pGmmULTClientContext->DestroyResInfoObject(ResourceInfo); } } /// @brief ULT for MSAA Resource - TODO adddepth MSAA, MCS surf param verificaton, compression case TEST_F(CTestGen12Resource, TestColorMSAA) { //Tile dimensions in Bytes const uint32_t MCSTileSize[1][2] = {128, 32}; //MCS is TileY const uint32_t TestDimensions[4][2] = { //Input dimensions in #Tiles {15, 20}, //16 Tiles x 20 {0, 0}, //1x1x1 {1, 0}, //2 Tilesx1 {1, 1}, //2 Tiles x 2 }; uint32_t TestArraySize[2] = {1, 5}; uint32_t MinPitch = 32; uint32_t HAlign, VAlign, TileDimX, TileDimY, MCSHAlign, MCSVAlign, TileSize; uint32_t ExpectedMCSBpp; std::vector> List; //TEST_TILE_TYPE, TEST_BPP, TEST_RESOURCE_TYPE, Depth or RT, TestDimension index, ArraySize auto Size = BuildInputIterator(List, 4, 2, false); // Size of arrays TestDimensions, TestArraySize for(auto element : List) { GMM_RESCREATE_PARAMS gmmParams = {}; gmmParams.Flags.Info = {0}; TEST_TILE_TYPE Tiling = (TEST_TILE_TYPE)std::get<0>(element); TEST_BPP Bpp = (TEST_BPP)std::get<1>(element); TEST_RESOURCE_TYPE ResType = (TEST_RESOURCE_TYPE)std::get<2>(element); bool IsRT = std::get<3>(element); // True for RT, False for Depth int TestDimIdx = std::get<4>(element); //index into TestDimensions array int ArrayIdx = std::get<5>(element); //index into TestArraySize TileSize = (Tiling == TEST_TILEYS) ? GMM_KBYTE(64) : GMM_KBYTE(4); //Discard un-supported Tiling/Res_type/bpp for this test if(ResType != TEST_RESOURCE_2D || //No 1D/3D/Cube. Supported 2D mip-maps/array (!IsRT && (Tiling == TEST_TILEX || // doesn't support TileX for Depth !(Bpp == TEST_BPP_16 || Bpp == TEST_BPP_32)))) //depth supported on 16bit, 32bit formats only continue; if(!IsRT) continue; //comment depth msaa for now (requires change in h/v align) SetTileFlag(gmmParams, Tiling); SetResType(gmmParams, ResType); SetResGpuFlags(gmmParams, IsRT); SetResArraySize(gmmParams, TestArraySize[ArrayIdx]); gmmParams.NoGfxMemory = 1; gmmParams.Format = SetResourceFormat(Bpp); for(uint32_t k = MSAA_2x; k <= MSAA_16x; k++) { GetAlignmentAndTileDimensionsForMSAA(Bpp, IsRT, Tiling, (TEST_MSAA)k, TileDimX, TileDimY, HAlign, VAlign, ExpectedMCSBpp, MCSHAlign, MCSVAlign); //gmmParams.BaseWidth64 = TestDimensions[TestDimIdx][0] * TileDimX + 0x1; //gmmParams.BaseHeight = TestDimensions[TestDimIdx][1] * TileDimY + 0x1; gmmParams.BaseWidth64 = 4; gmmParams.BaseHeight = 4; gmmParams.Depth = 0x1; gmmParams.MSAA.NumSamples = static_cast(pow((double)2, k)); gmmParams.Flags.Gpu.MCS = 0; //MSS surface GMM_RESOURCE_INFO *MSSResourceInfo; MSSResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); if(MSSResourceInfo) { VerifyResourceHAlign(MSSResourceInfo, HAlign); VerifyResourceVAlign(MSSResourceInfo, VAlign); if(IsRT) //Arrayed MSS { uint32_t ExpectedPitch = 0, ExpectedQPitch = 0; ExpectedPitch = GMM_ULT_ALIGN(GMM_ULT_ALIGN(gmmParams.BaseWidth64, HAlign) * (int)pow(2.0, Bpp), TileDimX); // Aligned width * bpp, aligned to TileWidth ExpectedPitch = GFX_MAX(ExpectedPitch, MinPitch); VerifyResourcePitch(MSSResourceInfo, ExpectedPitch); if(Tiling != TEST_LINEAR) VerifyResourcePitchInTiles(MSSResourceInfo, ExpectedPitch / TileDimX); ExpectedQPitch = GMM_ULT_ALIGN(gmmParams.BaseHeight, VAlign); if(gmmParams.ArraySize > 1) //Gen9: Qpitch is distance between array slices (not sample slices) { VerifyResourceQPitch(MSSResourceInfo, ExpectedQPitch); } uint32_t ExpectedHeight = GMM_ULT_ALIGN(ExpectedQPitch * gmmParams.MSAA.NumSamples * gmmParams.ArraySize, TileDimY); //Align Height =ExpectedPitch * NumSamples * ExpectedQPitch, to Tile-Height VerifyResourceSize(MSSResourceInfo, GMM_ULT_ALIGN(ExpectedPitch * ExpectedHeight, TileSize)); } } pGmmULTClientContext->DestroyResInfoObject(MSSResourceInfo); } //NumSamples = k } //Iterate through all Input types //Mip-mapped, MSAA case: } gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/ULT/GmmGen12ResourceULT.h000066400000000000000000000043421466655022700243050ustar00rootroot00000000000000/*============================================================================== Copyright(c) 2019 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ============================================================================*/ #pragma once #include "GmmGen10ResourceULT.h" #include "../GmmLib/inc/Internal/Common/Platform/GmmGen12Platform.h" class CTestGen12Resource : public CTestGen10Resource { public: static void SetUpTestCase(); static void TearDownTestCase(); }; #define DEFINE_TILE(xxx, bpp) \ (bpp == TEST_BPP_8) ? TILE_##xxx##_8bpe : \ (bpp == TEST_BPP_16) ? TILE_##xxx##_16bpe : \ (bpp == TEST_BPP_32) ? TILE_##xxx##_32bpe : \ (bpp == TEST_BPP_64) ? TILE_##xxx##_64bpe : \ TILE_##xxx##_128bpe gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/ULT/GmmGen12dGPUCachePolicyULT.cpp000066400000000000000000000225571466655022700257640ustar00rootroot00000000000000/*============================================================================== Copyright(c) 2020 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ============================================================================*/ #include "GmmGen12dGPUCachePolicyULT.h" using namespace std; ///////////////////////////////////////////////////////////////////////////////////// /// Sets up common environment for Cache Policy fixture tests. this is called once per /// test case before executing all tests under resource fixture test case. /// It also calls SetupTestCase from CommonULT to initialize global context and others. /// ///////////////////////////////////////////////////////////////////////////////////// void CTestGen12dGPUCachePolicy::SetUpTestCase() { } ///////////////////////////////////////////////////////////////////////////////////// /// cleans up once all the tests finish execution. It also calls TearDownTestCase /// from CommonULT to destroy global context and others. /// ///////////////////////////////////////////////////////////////////////////////////// void CTestGen12dGPUCachePolicy::TearDownTestCase() { } void CTestGen12dGPUCachePolicy::SetUpGen12dGPUVariant(PRODUCT_FAMILY platform) { printf("%s\n", __FUNCTION__); GfxPlatform.eProductFamily = platform; GfxPlatform.eRenderCoreFamily = IGFX_XE_HPG_CORE; pGfxAdapterInfo = (ADAPTER_INFO *)malloc(sizeof(ADAPTER_INFO)); if(pGfxAdapterInfo) { memset(pGfxAdapterInfo, 0, sizeof(ADAPTER_INFO)); pGfxAdapterInfo->SkuTable.FtrLinearCCS = 1; //legacy y =>0 - test both pGfxAdapterInfo->SkuTable.FtrStandardMipTailFormat = 1; pGfxAdapterInfo->SkuTable.FtrTileY = 0; pGfxAdapterInfo->SkuTable.FtrLocalMemory = 1; CommonULT::SetUpTestCase(); } } void CTestGen12dGPUCachePolicy::TearDownGen12dGPUVariant() { printf("%s\n", __FUNCTION__); CommonULT::TearDownTestCase(); } TEST_F(CTestGen12dGPUCachePolicy, TestGen12dGPU_DG1CachePolicy) { SetUpGen12dGPUVariant(IGFX_DG1); CheckL3Gen12dGPUCachePolicy(); TearDownGen12dGPUVariant(); } TEST_F(CTestGen12dGPUCachePolicy, TestGen12dGPU_XE_HP_SDVCachePolicy) { SetUpGen12dGPUVariant(IGFX_XE_HP_SDV); CheckL3Gen12dGPUCachePolicy(); TearDownGen12dGPUVariant(); } void CTestGen12dGPUCachePolicy::CheckSpecialMocs(uint32_t Usage, uint32_t AssignedMocsIdx, GMM_CACHE_POLICY_ELEMENT ClientRequest) { if(Usage == GMM_RESOURCE_USAGE_CCS) //60 { EXPECT_EQ(AssignedMocsIdx, 60) << "Usage# " << Usage << ": Incorrect Index for CCS"; EXPECT_EQ(0, ClientRequest.L3) << "Usage# " << Usage << ": Incorrect L3 cacheability for CCS"; EXPECT_EQ(0, ClientRequest.UcLookup) << "Usage# " << Usage << ": Incorrect L3 LookUp cacheability for CCS"; } else if(Usage == GMM_RESOURCE_USAGE_CCS_MEDIA_WRITABLE) // 61 { EXPECT_EQ(AssignedMocsIdx, 61) << "Usage# " << Usage << ": Incorrect Index for CCS"; EXPECT_EQ(0, ClientRequest.L3) << "Usage# " << Usage << ": Incorrect L3 cacheability for CCS"; EXPECT_EQ(0, ClientRequest.UcLookup) << "Usage# " << Usage << ": Incorrect L3 LookUp cacheability for CCS"; } else if(Usage == GMM_RESOURCE_USAGE_MOCS_62) //62 { EXPECT_EQ(AssignedMocsIdx, 62) << "Usage# " << Usage << ": Incorrect Index for MOCS_62"; EXPECT_EQ(0, ClientRequest.L3) << "Usage# " << Usage << ": Incorrect L3 cacheability for MOCS#62"; } } void CTestGen12dGPUCachePolicy::CheckMocsIdxHDCL1(uint32_t Usage, uint32_t AssignedMocsIdx, GMM_CACHE_POLICY_ELEMENT ClientRequest) { #define GMM_GEN12_MAX_NUMBER_MOCS_INDEXES (60) // On TGL last four (#60-#63) are reserved by h/w, few? are sw configurable though (#60) // Check of assigned Index setting is appropriate for HDCL1 setting if(ClientRequest.HDCL1) { EXPECT_GE(AssignedMocsIdx, GMM_GEN10_HDCL1_MOCS_INDEX_START) << "Usage# " << Usage << ": Index must be greater than " << GMM_GEN10_HDCL1_MOCS_INDEX_START - 1 << " for HDCL1 setting. AssignedMocs: " << AssignedMocsIdx; EXPECT_LT(AssignedMocsIdx, GMM_GEN12_MAX_NUMBER_MOCS_INDEXES) << "Usage# " << Usage << ": Index must be less than " << GMM_GEN12_MAX_NUMBER_MOCS_INDEXES << "for HDCL1 setting"; } else if(AssignedMocsIdx < GMM_GEN12_MAX_NUMBER_MOCS_INDEXES) { EXPECT_LT(AssignedMocsIdx, GMM_GEN10_HDCL1_MOCS_INDEX_START) << "Usage# " << Usage << ": Incorrect Index for HDCL1 setting"; } } void CTestGen12dGPUCachePolicy::CheckL3Gen12dGPUCachePolicy() { const uint32_t L3_WB_CACHEABLE = 0x3; const uint32_t L3_UNCACHEABLE = 0x1; // Check Usage MOCS index against MOCS settings for(uint32_t Usage = GMM_RESOURCE_USAGE_UNKNOWN; Usage < GMM_RESOURCE_USAGE_MAX; Usage++) { GMM_CACHE_POLICY_ELEMENT ClientRequest = pGmmULTClientContext->GetCachePolicyElement((GMM_RESOURCE_USAGE_TYPE)Usage); uint32_t AssignedMocsIdx = ClientRequest.MemoryObjectOverride.Gen12.Index; GMM_CACHE_POLICY_TBL_ELEMENT Mocs = pGmmULTClientContext->GetCachePolicyTlbElement(AssignedMocsIdx); uint32_t StartMocsIdx = 1; //printf("Usage: %d --> Index: [%d]\n", Usage, AssignedMocsIdx); if(GfxPlatform.eProductFamily == IGFX_DG2) { StartMocsIdx = 0; } if(StartMocsIdx == 1) { EXPECT_NE(0, AssignedMocsIdx) << "Usage# " << Usage << ": Misprogramming MOCS - Index 0 is reserved for Error"; } EXPECT_EQ(0, Mocs.L3.ESC) << "Usage# " << Usage << ": ESC is non-zero"; EXPECT_EQ(0, Mocs.L3.SCC) << "Usage# " << Usage << ": SCC is non-zero"; EXPECT_EQ(0, Mocs.L3.Reserved) << "Usage# " << Usage << ": Reserved field is non-zero"; // Check if Mocs Index is not greater than GMM_MAX_NUMBER_MOCS_INDEXES EXPECT_GT(GMM_MAX_NUMBER_MOCS_INDEXES, AssignedMocsIdx) << "Usage# " << Usage << ": MOCS Index greater than MAX allowed (63)"; if(GfxPlatform.eProductFamily <= IGFX_XE_HP_SDV) { CheckMocsIdxHDCL1(Usage, AssignedMocsIdx, ClientRequest); } if(GfxPlatform.eProductFamily < IGFX_DG2) { CheckSpecialMocs(Usage, AssignedMocsIdx, ClientRequest); } if(ClientRequest.L3) { EXPECT_EQ(L3_WB_CACHEABLE, Mocs.L3.Cacheability) << "Usage# " << Usage << ": Incorrect L3 cachebility setting"; } else { EXPECT_EQ(L3_UNCACHEABLE, Mocs.L3.Cacheability) << "Usage# " << Usage << ": Incorrect L3 cachebility setting"; } } } void CTestXe_HP_CachePolicy::SetUpPlatformVariant(PRODUCT_FAMILY platform) { printf("%s\n", __FUNCTION__); CTestGen12dGPUCachePolicy::SetUpGen12dGPUVariant(platform); } void CTestXe_HP_CachePolicy::TearDownPlatformVariant() { printf("%s\n", __FUNCTION__); CTestGen12dGPUCachePolicy::TearDownGen12dGPUVariant(); } void CTestXe_HP_CachePolicy::CheckL3CachePolicy() { printf("%s\n", __FUNCTION__); CTestGen12dGPUCachePolicy::CheckL3Gen12dGPUCachePolicy(); } void CTestXe_HP_CachePolicy::SetUpTestCase() { } void CTestXe_HP_CachePolicy::TearDownTestCase() { } TEST_F(CTestXe_HP_CachePolicy, Test_DG2_CachePolicy) { SetUpPlatformVariant(IGFX_DG2); CheckL3CachePolicy(); TearDownPlatformVariant(); } TEST_F(CTestXe_HP_CachePolicy, Test_PVC_CachePolicy) { SetUpPlatformVariant(IGFX_PVC); CheckL3CachePolicy(); CheckPAT(); TearDownPlatformVariant(); } void CTestXe_HP_CachePolicy::CheckPAT() { // Check Usage PAT index against PAT settings for(unsigned long Usage = GMM_RESOURCE_USAGE_UNKNOWN; Usage < GMM_RESOURCE_USAGE_MAX; Usage++) { GMM_CACHE_POLICY_ELEMENT ClientRequest = pGmmULTClientContext->GetCachePolicyElement((GMM_RESOURCE_USAGE_TYPE)Usage); if(ClientRequest.Initialized == false) // undefined resource in platform { continue; } unsigned long PATIndex = pGmmULTClientContext->CachePolicyGetPATIndex(NULL, (GMM_RESOURCE_USAGE_TYPE)Usage, NULL, false); //printf("Xe HPG: Usage: %d --> PAT Index: [%d]\n", Usage, PATIndex); EXPECT_NE(PATIndex, GMM_PAT_ERROR) << "Usage# " << Usage << ": No matching PAT Index"; } } gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/ULT/GmmGen12dGPUCachePolicyULT.h000066400000000000000000000044661466655022700254300ustar00rootroot00000000000000/*============================================================================== Copyright(c) 2020 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ============================================================================*/ #pragma once #include "GmmCachePolicyULT.h" class CTestGen12dGPUCachePolicy : public CTestCachePolicy { protected: virtual void SetUpGen12dGPUVariant(PRODUCT_FAMILY); virtual void TearDownGen12dGPUVariant(); virtual void CheckL3Gen12dGPUCachePolicy(); virtual void CheckSpecialMocs(uint32_t Usage, uint32_t AssignedMocsIdx, GMM_CACHE_POLICY_ELEMENT ClientRequest); virtual void CheckMocsIdxHDCL1(uint32_t Usage, uint32_t AssignedMocsIdx, GMM_CACHE_POLICY_ELEMENT ClientRequest); public: static void SetUpTestCase(); static void TearDownTestCase(); }; class CTestXe_HP_CachePolicy : public CTestGen12dGPUCachePolicy { protected: virtual void SetUpPlatformVariant(PRODUCT_FAMILY); virtual void TearDownPlatformVariant(); virtual void CheckL3CachePolicy(); virtual void CheckPAT(); public: static void SetUpTestCase(); static void TearDownTestCase(); }; #pragma once gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/ULT/GmmGen12dGPUResourceULT.cpp000066400000000000000000004727621466655022700253770ustar00rootroot00000000000000/*============================================================================== Copyright(c) 2020 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ============================================================================*/ #include "GmmGen12dGPUResourceULT.h" using namespace std; ///////////////////////////////////////////////////////////////////////////////////// /// Sets up common environment for Resource fixture tests. this is called once per /// test case before executing all tests under resource fixture test case. // It also calls SetupTestCase from CommonULT to initialize global context and others. /// /// @see CTestGen12dGPUResource::SetUpTestCase() /// ///////////////////////////////////////////////////////////////////////////////////// void CTestGen12dGPUResource::SetUpTestCase() { printf("%s\n", __FUNCTION__); GfxPlatform.eProductFamily = IGFX_XE_HP_SDV; GfxPlatform.eRenderCoreFamily = IGFX_XE_HP_CORE; pGfxAdapterInfo = (ADAPTER_INFO *)malloc(sizeof(ADAPTER_INFO)); if(pGfxAdapterInfo) { memset(pGfxAdapterInfo, 0, sizeof(ADAPTER_INFO)); pGfxAdapterInfo->SkuTable.FtrLinearCCS = 1; //legacy y =>0 - test both pGfxAdapterInfo->SkuTable.FtrStandardMipTailFormat = 1; pGfxAdapterInfo->SkuTable.FtrTileY = 1; pGfxAdapterInfo->SkuTable.FtrTile64Optimization = 1; CommonULT::SetUpTestCase(); } } ///////////////////////////////////////////////////////////////////////////////////// /// cleans up once all the tests finish execution. It also calls TearDownTestCase /// from CommonULT to destroy global context and others. /// /// @see CTestGen12dGPUResource::TearDownTestCase() ///////////////////////////////////////////////////////////////////////////////////// void CTestGen12dGPUResource::TearDownTestCase() { printf("%s\n", __FUNCTION__); CommonULT::TearDownTestCase(); } TEST_F(CTestGen12dGPUResource, DISABLED_Test1DLinearResource) { // Horizontal pixel alignment const uint32_t HAlign[] = {128, 64, 32, 16, 8}; //128Bytes/(bpp>>3) GMM_RESCREATE_PARAMS gmmParams = {}; gmmParams.Type = RESOURCE_1D; gmmParams.NoGfxMemory = 1; gmmParams.Flags.Info.Linear = 1; gmmParams.Flags.Gpu.Texture = 1; // Allocate 1x1 surface for(uint32_t i = 0; i < TEST_BPP_MAX; i++) { TEST_BPP bpp = static_cast(i); gmmParams.Format = SetResourceFormat(bpp); gmmParams.BaseWidth64 = 0x1; gmmParams.BaseHeight = 1; GMM_RESOURCE_INFO *ResourceInfo; ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); uint32_t AlignedWidth = GMM_ULT_ALIGN(gmmParams.BaseWidth64, HAlign[i]); uint32_t PitchInBytes = AlignedWidth * GetBppValue(bpp); uint32_t AlignedSize = GMM_ULT_ALIGN(PitchInBytes, PAGE_SIZE); VerifyResourceHAlign(ResourceInfo, HAlign[i]); VerifyResourceVAlign(ResourceInfo, 0); // N/A for 1D VerifyResourcePitch(ResourceInfo, 0); // N/A for 1D VerifyResourcePitchInTiles(ResourceInfo, 0); // N/A for linear VerifyResourceSize(ResourceInfo, AlignedSize); VerifyResourceQPitch(ResourceInfo, 0); // N/A for non-arrayed pGmmULTClientContext->DestroyResInfoObject(ResourceInfo); } // Allocate more than 1 page for(uint32_t i = 0; i < TEST_BPP_MAX; i++) { TEST_BPP bpp = static_cast(i); gmmParams.Format = SetResourceFormat(bpp); gmmParams.BaseWidth64 = 0x1001; gmmParams.BaseHeight = 1; GMM_RESOURCE_INFO *ResourceInfo; ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); uint32_t AlignedWidth = GMM_ULT_ALIGN(gmmParams.BaseWidth64, HAlign[i]); uint32_t PitchInBytes = AlignedWidth * GetBppValue(bpp); uint32_t AlignedSize = GMM_ULT_ALIGN(PitchInBytes, PAGE_SIZE); VerifyResourceHAlign(ResourceInfo, HAlign[i]); VerifyResourceVAlign(ResourceInfo, 0); // N/A for 1D VerifyResourcePitch(ResourceInfo, 0); // N/A for 1D VerifyResourcePitchInTiles(ResourceInfo, 0); // N/A for linear VerifyResourceSize(ResourceInfo, AlignedSize); VerifyResourceQPitch(ResourceInfo, 0); // N/A for non-arrayed pGmmULTClientContext->DestroyResInfoObject(ResourceInfo); } } /// @brief ULT for 1D Linear Resource Arrays TEST_F(CTestGen12dGPUResource, DISABLED_Test1DLinearResourceArrays) { // Horizontal pixel alignment const uint32_t HAlign[] = {128, 64, 32, 16, 8}; //128Bytes/(bpp>>3) GMM_RESCREATE_PARAMS gmmParams = {}; gmmParams.Type = RESOURCE_1D; gmmParams.NoGfxMemory = 1; gmmParams.Flags.Info.Linear = 1; gmmParams.Flags.Gpu.Texture = 1; gmmParams.ArraySize = 4; // Allocate more than 1 page for(uint32_t i = 0; i < TEST_BPP_MAX; i++) { TEST_BPP bpp = static_cast(i); gmmParams.Format = SetResourceFormat(bpp); gmmParams.BaseWidth64 = 0x1001; gmmParams.BaseHeight = 1; GMM_RESOURCE_INFO *ResourceInfo; ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); uint32_t AlignedWidth = GMM_ULT_ALIGN(gmmParams.BaseWidth64, HAlign[i]); uint32_t PitchInBytes = AlignedWidth * GetBppValue(bpp); uint32_t AlignedSize = GMM_ULT_ALIGN(PitchInBytes * gmmParams.ArraySize, PAGE_SIZE); VerifyResourceHAlign(ResourceInfo, HAlign[i]); VerifyResourceVAlign(ResourceInfo, 0); // N/A for 1D VerifyResourcePitch(ResourceInfo, 0); // N/A for 1D VerifyResourcePitchInTiles(ResourceInfo, 0); // N/A for linear VerifyResourceSize(ResourceInfo, AlignedSize); VerifyResourceQPitch(ResourceInfo, AlignedWidth); pGmmULTClientContext->DestroyResInfoObject(ResourceInfo); } } /// @brief ULT for 1D Mipped Linear Resource TEST_F(CTestGen12dGPUResource, DISABLED_Test1DLinearResourceMips) { // Horizontal pixel alignment const uint32_t HAlign[] = {128, 64, 32, 16, 8}; //128Bytes/(bpp>>3) GMM_RESCREATE_PARAMS gmmParams = {}; gmmParams.Type = RESOURCE_1D; gmmParams.NoGfxMemory = 1; gmmParams.Flags.Info.Linear = 1; gmmParams.Flags.Gpu.Texture = 1; gmmParams.MaxLod = 5; // Allocate 256x1 surface for(uint32_t i = 0; i < TEST_BPP_MAX; i++) { TEST_BPP bpp = static_cast(i); gmmParams.Format = SetResourceFormat(bpp); gmmParams.BaseWidth64 = 0x100; gmmParams.BaseHeight = 0x1; GMM_RESOURCE_INFO *ResourceInfo; ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); uint32_t AlignedWidth = GMM_ULT_ALIGN(gmmParams.BaseWidth64, HAlign[i]); for(int mip = 1; mip <= gmmParams.MaxLod; mip++) { // Since 1D doesn't have a height, mips are just based on width AlignedWidth += GMM_ULT_ALIGN(gmmParams.BaseWidth64 >> mip, HAlign[i]); } uint32_t PitchInBytes = AlignedWidth * GetBppValue(bpp); uint32_t AlignedSize = GMM_ULT_ALIGN(PitchInBytes, PAGE_SIZE); VerifyResourceHAlign(ResourceInfo, HAlign[i]); VerifyResourceVAlign(ResourceInfo, 0); // N/A for 1D VerifyResourcePitch(ResourceInfo, 0); // N/A for 1D VerifyResourcePitchInTiles(ResourceInfo, 0); // N/A for linear VerifyResourceSize(ResourceInfo, AlignedSize); VerifyResourceQPitch(ResourceInfo, 0); // N/A for non-arrayed // Mip0 should be at offset 0. X/Y/Z Offset should be 0 for linear. GMM_REQ_OFFSET_INFO OffsetInfo = {}; OffsetInfo.ReqRender = 1; OffsetInfo.MipLevel = 0; //Mip 0 ResourceInfo->GetOffset(OffsetInfo); EXPECT_EQ(0, OffsetInfo.Render.Offset64); EXPECT_EQ(0, OffsetInfo.Render.XOffset); EXPECT_EQ(0, OffsetInfo.Render.YOffset); EXPECT_EQ(0, OffsetInfo.Render.ZOffset); // All mips should be right after one another linearly uint32_t StartOfMip = 0; for(int mip = 1; mip <= gmmParams.MaxLod; mip++) { OffsetInfo = {}; OffsetInfo.ReqRender = 1; OffsetInfo.MipLevel = mip; ResourceInfo->GetOffset(OffsetInfo); StartOfMip += GMM_ULT_ALIGN(gmmParams.BaseWidth64 >> (mip - 1), HAlign[i]) * GetBppValue(bpp); EXPECT_EQ(StartOfMip, OffsetInfo.Render.Offset64); EXPECT_EQ(0, OffsetInfo.Render.XOffset); EXPECT_EQ(0, OffsetInfo.Render.YOffset); EXPECT_EQ(0, OffsetInfo.Render.ZOffset); } pGmmULTClientContext->DestroyResInfoObject(ResourceInfo); } } /// @brief ULT for 1D Mipped TileYS Resource TEST_F(CTestGen12dGPUResource, DISABLED_Test1DTileTiledResourceMips) { const uint32_t TileSize[TEST_BPP_MAX] = {65536, 32768, 16384, 8192, 4096}; const uint32_t Mts[TEST_BPP_MAX] = {16384, 8192, 4096, 2048, 1024}; GMM_RESCREATE_PARAMS gmmParams = {}; gmmParams.Type = RESOURCE_1D; gmmParams.NoGfxMemory = 1; gmmParams.Flags.Gpu.TiledResource = 1; gmmParams.Flags.Gpu.Texture = 1; gmmParams.MaxLod = 5; // Allocate all mips in 1 tile or multiple tiles, depending on the bpp for(uint32_t i = 0; i < TEST_BPP_MAX; i++) { TEST_BPP bpp = static_cast(i); gmmParams.Format = SetResourceFormat(bpp); gmmParams.BaseWidth64 = 16 * 1024; // 16K is the max width you can specify gmmParams.BaseHeight = 0x1; GMM_RESOURCE_INFO *ResourceInfo; ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); uint32_t MaxMip; uint32_t MipTailStart = gmmParams.MaxLod; for(MaxMip = 0; MaxMip <= gmmParams.MaxLod; MaxMip++) { if((gmmParams.BaseWidth64 >> MaxMip) <= Mts[i]) { MipTailStart = MaxMip; break; } } uint32_t AlignedWidth = 0; for(int mip = 0; mip <= MaxMip; mip++) { // Since 1D doesn't have a height, mips are just based on width AlignedWidth += GMM_ULT_ALIGN(gmmParams.BaseWidth64 >> mip, TileSize[i]); ; } uint32_t PitchInBytes = AlignedWidth * GetBppValue(bpp); uint32_t AlignedSize = GMM_ULT_ALIGN(PitchInBytes, PAGE_SIZE); VerifyResourceHAlign(ResourceInfo, TileSize[i]); VerifyResourceVAlign(ResourceInfo, 0); // N/A for 1D VerifyResourcePitch(ResourceInfo, 0); // N/A for 1D VerifyResourcePitchInTiles(ResourceInfo, 0); // N/A for linear VerifyResourceSize(ResourceInfo, AlignedSize); VerifyResourceQPitch(ResourceInfo, 0); // N/A for non-arrayed // All mips should be right after one another linearly, until the miptail uint32_t StartOfMip = 0; int mip; for(mip = 0; mip < MaxMip; mip++) { GMM_REQ_OFFSET_INFO OffsetInfo = {}; OffsetInfo.ReqRender = 1; OffsetInfo.MipLevel = mip; ResourceInfo->GetOffset(OffsetInfo); StartOfMip += (mip == 0 ? 0 : GMM_ULT_ALIGN(gmmParams.BaseWidth64 >> (mip - 1), TileSize[i]) * GetBppValue(bpp)); EXPECT_EQ(StartOfMip, OffsetInfo.Render.Offset64); EXPECT_EQ(0, OffsetInfo.Render.XOffset); EXPECT_EQ(0, OffsetInfo.Render.YOffset); EXPECT_EQ(0, OffsetInfo.Render.ZOffset); } uint32_t MipTailOffsets[GMM_ULT_MAX_MIPMAP] = {32768, 16384, 8192, 4096, 2048, 1536, 1280, 1024, 768, 512, 256, 0, 64, 128, 196}; // Check for offset inside miptails. EXPECT_EQ(MipTailStart, ResourceInfo->GetPackedMipTailStartLod()); StartOfMip += GMM_ULT_ALIGN(gmmParams.BaseWidth64 >> (mip - 1), TileSize[i]) * GetBppValue(bpp); // Start of MipTail for(int slot = 0; mip <= gmmParams.MaxLod; mip++, slot++) { GMM_REQ_OFFSET_INFO OffsetInfo = {}; OffsetInfo.ReqRender = 1; OffsetInfo.MipLevel = mip; ResourceInfo->GetOffset(OffsetInfo); EXPECT_EQ(StartOfMip, OffsetInfo.Render.Offset64); // Start of Miptail EXPECT_EQ(MipTailOffsets[slot], OffsetInfo.Render.XOffset); // Offset within miptail EXPECT_EQ(0, OffsetInfo.Render.YOffset); EXPECT_EQ(0, OffsetInfo.Render.ZOffset); } pGmmULTClientContext->DestroyResInfoObject(ResourceInfo); } } /// @brief ULT for 2D Tile64 Resource Optimization TEST_F(CTestGen12dGPUResource, DISABLED_TestTile64ResourceOptimization) { const uint32_t TileSize[TEST_BPP_MAX][2] = {{256, 256}, {512, 128}, {512, 128}, {1024, 64}, {1024, 64}}; GMM_RESCREATE_PARAMS gmmParams = {}; gmmParams.Type = RESOURCE_2D; gmmParams.Format = GMM_FORMAT_R8G8B8A8_UNORM; gmmParams.NoGfxMemory = 1; gmmParams.Flags.Gpu.Texture = 1; // TiledResource set 0 - allow to enter in Tile64 optimization logic gmmParams.Flags.Gpu.TiledResource = 0; gmmParams.ArraySize = 6; gmmParams.BaseWidth64 = 1; gmmParams.BaseHeight = 1; // set any valid Usage gmmParams.Usage = GMM_RESOURCE_USAGE_RENDER_TARGET; GMM_RESOURCE_INFO *ResourceInfo; ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); // Check if Tile4 info flag VerifyResourceTile4(ResourceInfo, true); pGmmULTClientContext->DestroyResInfoObject(ResourceInfo); gmmParams.Type = RESOURCE_2D; gmmParams.BaseWidth64 = 128; gmmParams.BaseHeight = 128; gmmParams.NoGfxMemory = 1; gmmParams.Flags.Gpu.Texture = 1; // TiledResource set 0 - allow to enter in Tile64 optimization logic gmmParams.Flags.Gpu.TiledResource = 0; gmmParams.ArraySize = 960; gmmParams.Flags.Info.Tile4 = 0; gmmParams.Flags.Info.Tile64 = 0; gmmParams.Format = GMM_FORMAT_BC6H; ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); // Check if Tile4 info flag VerifyResourceTile4(ResourceInfo, true); pGmmULTClientContext->DestroyResInfoObject(ResourceInfo); // Allocate surface that requires multi tiles in two dimension // Allocate 2 tiles in X dimension for(uint32_t i = 0; i < TEST_BPP_MAX; i++) { TEST_BPP bpp = static_cast(i); gmmParams.Format = SetResourceFormat(bpp); gmmParams.BaseWidth64 = (TileSize[i][0] / GetBppValue(bpp)) + 1; // 1 pixel larger than 1 tile width gmmParams.BaseHeight = 0x1; gmmParams.Depth = 0x1; // TiledResource set 0 - allow to enter in Tile64 optimization logic gmmParams.Flags.Gpu.TiledResource = 0; gmmParams.Flags.Info.Tile4 = 0; gmmParams.Flags.Info.Tile64 = 0; GMM_RESOURCE_INFO *ResourceInfo; ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); // Check if Tile4 is set or not VerifyResourceTile4(ResourceInfo, true); pGmmULTClientContext->DestroyResInfoObject(ResourceInfo); } // Allocate 2 tiles in X/Y dimension for(uint32_t i = 0; i < TEST_BPP_MAX; i++) { TEST_BPP bpp = static_cast(i); gmmParams.Format = GMM_FORMAT_R8G8B8A8_UNORM; //SetResourceFormat(bpp); gmmParams.BaseWidth64 = (TileSize[i][0] / GetBppValue(bpp)) + 1; // 1 pixel larger than 1 tile width gmmParams.BaseHeight = TileSize[i][1] + 1; // 1 row larger than 1 tile height gmmParams.Depth = 0x1; gmmParams.Flags.Info.Tile4 = 0; gmmParams.Flags.Info.Tile64 = 0; GMM_RESOURCE_INFO *ResourceInfo; ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); // Check if Tile4 is set or not VerifyResourceTile4(ResourceInfo, true); pGmmULTClientContext->DestroyResInfoObject(ResourceInfo); } } /// @brief ULT for 2D Tile64 Resource with Mips TEST_F(CTestGen12dGPUResource, DISABLED_Test2DTile64MippedResourceOptimization) { const uint32_t HAlign[TEST_BPP_MAX] = {256, 256, 128, 128, 64}; const uint32_t VAlign[TEST_BPP_MAX] = {256, 128, 128, 64, 64}; const uint32_t TileSize[TEST_BPP_MAX][2] = {{256, 256}, {512, 128}, {512, 128}, {1024, 64}, {1024, 64}}; const uint32_t MtsWidth[TEST_BPP_MAX] = {128, 128, 64, 64, 32}; const uint32_t MtsHeight[TEST_BPP_MAX] = {256, 128, 128, 64, 64}; GMM_RESCREATE_PARAMS gmmParams = {}; gmmParams.Type = RESOURCE_2D; gmmParams.NoGfxMemory = 1; // TiledResource set 0 - allow to enter in Tile64 optimization logic gmmParams.Flags.Gpu.TiledResource = 0; gmmParams.Flags.Gpu.Texture = 1; gmmParams.MaxLod = 5; gmmParams.ArraySize = 4; // set any valid Usage gmmParams.Usage = GMM_RESOURCE_USAGE_RENDER_TARGET; for(uint32_t i = 0; i < TEST_BPP_MAX; i++) { uint32_t AlignedWidth = 0; uint32_t AlignedHeight = 0; uint32_t ExpectedPitch = 0; uint32_t MipTailStartLod = 0; // Valigned Mip Heights uint32_t Mip0Height = 0; uint32_t Mip1Height = 0; uint32_t Mip2Height = 0; uint32_t Mip3Height = 0; uint32_t Mip2Higher = 0; // Sum of aligned heights of Mip2 and above uint32_t MipTailHeight = 0; // Haligned Mip Widths uint32_t Mip0Width = 0; uint32_t Mip1Width = 0; uint32_t Mip2Width = 0; TEST_BPP bpp = static_cast(i); gmmParams.Format = SetResourceFormat(bpp); gmmParams.BaseWidth64 = 0x120; gmmParams.BaseHeight = 0x120; // TiledResource set 0 - allow to enter in Tile64 optimization logic gmmParams.Flags.Gpu.TiledResource = 0; gmmParams.Flags.Info.Tile4 = 0; gmmParams.Flags.Info.Tile64 = 0; GMM_RESOURCE_INFO *ResourceInfo; ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); VerifyResourceTile4(ResourceInfo, true); // find the miptail start level { uint32_t MipWidth = gmmParams.BaseWidth64; uint32_t MipHeight = gmmParams.BaseHeight; while(!(MipWidth <= MtsWidth[i] && MipHeight <= MtsHeight[i])) { MipTailStartLod++; MipWidth = (uint32_t)(GMM_ULT_MAX(1, gmmParams.BaseWidth64 >> MipTailStartLod)); MipHeight = GMM_ULT_MAX(1, gmmParams.BaseHeight >> MipTailStartLod); } } // Mip resource Aligned Width calculation Mip0Width = GMM_ULT_ALIGN(gmmParams.BaseWidth64, HAlign[i]); Mip1Width = GMM_ULT_ALIGN(gmmParams.BaseWidth64 >> 1, HAlign[i]); Mip2Width = GMM_ULT_ALIGN(gmmParams.BaseWidth64 >> 2, HAlign[i]); AlignedWidth = GMM_ULT_MAX(Mip0Width, Mip1Width + Mip2Width); Mip0Height = GMM_ULT_ALIGN(gmmParams.BaseHeight, VAlign[i]); if(MipTailStartLod == 2) { //EXPECT_EQ(2, ResourceInfo->GetPackedMipTailStartLod()); // Block height...Mip0Height + Max(Mip1Height, Sum of Mip2Height..MipnHeight) Mip1Height = GMM_ULT_ALIGN(gmmParams.BaseHeight >> 1, VAlign[i]); Mip2Height = Mip2Higher = GMM_ULT_ALIGN(gmmParams.BaseHeight >> 2, VAlign[i]); } else if(MipTailStartLod == 3) { //EXPECT_EQ(3, ResourceInfo->GetPackedMipTailStartLod()); // Block height...Mip0Height + Max(Mip1Height, Sum of Mip2Height..MipnHeight) Mip1Height = GMM_ULT_ALIGN(gmmParams.BaseHeight >> 1, VAlign[i]); Mip2Height = GMM_ULT_ALIGN(gmmParams.BaseHeight >> 2, VAlign[i]); // Miptail started lod MipTailHeight = VAlign[i]; Mip2Higher = Mip2Height + MipTailHeight; } else if(MipTailStartLod == 4) { //EXPECT_EQ(4, ResourceInfo->GetPackedMipTailStartLod()); // Block height...Mip0Height + Max(Mip1Height, Sum of Mip2Height..MipnHeight) Mip1Height = GMM_ULT_ALIGN(gmmParams.BaseHeight >> 1, VAlign[i]); Mip2Height = GMM_ULT_ALIGN(gmmParams.BaseHeight >> 2, VAlign[i]); Mip3Height = GMM_ULT_ALIGN(gmmParams.BaseHeight >> 3, VAlign[i]); // Miptail started lod MipTailHeight = VAlign[i]; Mip2Higher = Mip2Height + Mip3Height + MipTailHeight; } uint32_t MaxHeight = GMM_ULT_MAX(Mip1Height, Mip2Higher); AlignedHeight = Mip0Height + MaxHeight; AlignedHeight = GMM_ULT_ALIGN(AlignedHeight, VAlign[i]); ExpectedPitch = AlignedWidth * GetBppValue(bpp); ExpectedPitch = GMM_ULT_ALIGN(ExpectedPitch, GMM_BYTES(32)); //VerifyResourcePitch(ResourceInfo, ExpectedPitch); //VerifyResourcePitchInTiles(ResourceInfo, static_cast(ExpectedPitch / TileSize[i][0])); //VerifyResourceSize(ResourceInfo, GMM_ULT_ALIGN(ExpectedPitch * AlignedHeight * gmmParams.ArraySize, PAGE_SIZE)); //VerifyResourceQPitch(ResourceInfo, AlignedHeight); // Mip 0 offsets, offset is 0,0 GMM_REQ_OFFSET_INFO ReqInfo = {0}; ReqInfo.MipLevel = 0; ReqInfo.ReqRender = 1; ResourceInfo->GetOffset(ReqInfo); uint32_t Mip0Size = ExpectedPitch * Mip0Height; //EXPECT_EQ(0, ReqInfo.Render.Offset64); //EXPECT_EQ(0, ReqInfo.Render.XOffset); //EXPECT_EQ(0, ReqInfo.Render.YOffset); // Mip 1 offsets ReqInfo = {0}; ReqInfo.MipLevel = 1; ReqInfo.ReqRender = 1; ResourceInfo->GetOffset(ReqInfo); uint32_t Mip1Offset = Mip0Size; //EXPECT_EQ(Mip1Offset, ReqInfo.Render.Offset64); //EXPECT_EQ(0, ReqInfo.Render.XOffset); //EXPECT_EQ(0, ReqInfo.Render.YOffset); // Mip 2 offset ReqInfo = {0}; ReqInfo.MipLevel = 2; ReqInfo.ReqRender = 1; ResourceInfo->GetOffset(ReqInfo); uint32_t Mip2Offset = Mip1Width * GetBppValue(bpp) + Mip0Height * ExpectedPitch; uint32_t Mip2X = GFX_ALIGN_FLOOR(uint32_t(Mip2Offset % ExpectedPitch), TileSize[i][0]); uint32_t Mip2Y = GFX_ALIGN_FLOOR(uint32_t(Mip2Offset / ExpectedPitch), TileSize[i][1]); uint32_t Mip2RenderAlignedOffset = Mip2Y * ExpectedPitch + (Mip2X / TileSize[i][0]) * (TileSize[i][0] * TileSize[i][1]); //EXPECT_EQ(Mip2RenderAlignedOffset, ReqInfo.Render.Offset64); switch(bpp) { case TEST_BPP_8: //EXPECT_EQ(128, ReqInfo.Render.XOffset); //EXPECT_EQ(0, ReqInfo.Render.YOffset); break; case TEST_BPP_16: //EXPECT_EQ(256, ReqInfo.Render.XOffset); //EXPECT_EQ(0, ReqInfo.Render.YOffset); break; case TEST_BPP_32: //EXPECT_EQ(0, ReqInfo.Render.XOffset); //EXPECT_EQ(0, ReqInfo.Render.YOffset); break; case TEST_BPP_64: //EXPECT_EQ(0, ReqInfo.Render.XOffset); //EXPECT_EQ(0, ReqInfo.Render.YOffset); break; case TEST_BPP_128: //EXPECT_EQ(0, ReqInfo.Render.XOffset); //EXPECT_EQ(0, ReqInfo.Render.YOffset); break; default: break; } // Mip 3 offset ReqInfo = {0}; ReqInfo.MipLevel = 3; ReqInfo.ReqRender = 1; ResourceInfo->GetOffset(ReqInfo); uint32_t Mip3Offset = 0; switch(bpp) { case TEST_BPP_8: Mip3Offset = Mip1Width * GetBppValue(bpp) + Mip0Height * ExpectedPitch; //EXPECT_EQ(0, ReqInfo.Render.XOffset); //EXPECT_EQ(128, ReqInfo.Render.YOffset); break; case TEST_BPP_16: Mip3Offset = Mip1Width * GetBppValue(bpp) + Mip0Height * ExpectedPitch; //EXPECT_EQ(0, ReqInfo.Render.XOffset); //EXPECT_EQ(64, ReqInfo.Render.YOffset); break; case TEST_BPP_32: Mip3Offset = Mip1Width * GetBppValue(bpp) + (Mip0Height + Mip2Height) * ExpectedPitch; //EXPECT_EQ(256, ReqInfo.Render.XOffset); //EXPECT_EQ(0, ReqInfo.Render.YOffset); break; case TEST_BPP_64: Mip3Offset = Mip1Width * GetBppValue(bpp) + (Mip0Height + Mip2Height) * ExpectedPitch; //EXPECT_EQ(512, ReqInfo.Render.XOffset); //EXPECT_EQ(0, ReqInfo.Render.YOffset); break; case TEST_BPP_128: Mip3Offset = Mip1Width * GetBppValue(bpp) + (Mip0Height + Mip2Height) * ExpectedPitch; //EXPECT_EQ(0, ReqInfo.Render.XOffset); //EXPECT_EQ(0, ReqInfo.Render.YOffset); break; default: break; } uint32_t Mip3X = GFX_ALIGN_FLOOR(uint32_t(Mip3Offset % ExpectedPitch), TileSize[i][0]); uint32_t Mip3Y = GFX_ALIGN_FLOOR(uint32_t(Mip3Offset / ExpectedPitch), TileSize[i][1]); uint32_t Mip3RenderAlignedOffset = Mip3Y * ExpectedPitch + (Mip3X / TileSize[i][0]) * (TileSize[i][0] * TileSize[i][1]); //EXPECT_EQ(Mip3RenderAlignedOffset, ReqInfo.Render.Offset64); // Mip 4 offset ReqInfo = {0}; ReqInfo.MipLevel = 4; ReqInfo.ReqRender = 1; ResourceInfo->GetOffset(ReqInfo); uint32_t Mip4Offset = 0; switch(bpp) { case TEST_BPP_8: Mip4Offset = Mip1Width * GetBppValue(bpp) + Mip0Height * ExpectedPitch; //EXPECT_EQ(64, ReqInfo.Render.XOffset); //EXPECT_EQ(0, ReqInfo.Render.YOffset); break; case TEST_BPP_16: Mip4Offset = Mip1Width * GetBppValue(bpp) + Mip0Height * ExpectedPitch; //EXPECT_EQ(128, ReqInfo.Render.XOffset); //EXPECT_EQ(0, ReqInfo.Render.YOffset); break; case TEST_BPP_32: Mip4Offset = Mip1Width * GetBppValue(bpp) + (Mip0Height + Mip2Height) * ExpectedPitch; //EXPECT_EQ(0, ReqInfo.Render.XOffset); //EXPECT_EQ(64, ReqInfo.Render.YOffset); break; case TEST_BPP_64: Mip4Offset = Mip1Width * GetBppValue(bpp) + (Mip0Height + Mip2Height) * ExpectedPitch; //EXPECT_EQ(0, ReqInfo.Render.XOffset); //EXPECT_EQ(32, ReqInfo.Render.YOffset); break; case TEST_BPP_128: Mip4Offset = Mip1Width * GetBppValue(bpp) + (Mip0Height + Mip2Height + Mip3Height) * ExpectedPitch; //EXPECT_EQ(512, ReqInfo.Render.XOffset); //EXPECT_EQ(0, ReqInfo.Render.YOffset); break; default: break; } uint32_t Mip4X = GFX_ALIGN_FLOOR(uint32_t(Mip4Offset % ExpectedPitch), TileSize[i][0]); uint32_t Mip4Y = GFX_ALIGN_FLOOR(uint32_t(Mip4Offset / ExpectedPitch), TileSize[i][1]); uint32_t Mip4RenderAlignedOffset = Mip4Y * ExpectedPitch + (Mip4X / TileSize[i][0]) * (TileSize[i][0] * TileSize[i][1]); //EXPECT_EQ(Mip4RenderAlignedOffset, ReqInfo.Render.Offset64); // Mip 5 offset ReqInfo = {0}; ReqInfo.MipLevel = 4; ReqInfo.ReqRender = 1; ResourceInfo->GetOffset(ReqInfo); uint32_t Mip5Offset = 0; switch(bpp) { case TEST_BPP_8: Mip5Offset = Mip1Width * GetBppValue(bpp) + Mip0Height * ExpectedPitch; //EXPECT_EQ(64, ReqInfo.Render.XOffset); //EXPECT_EQ(0, ReqInfo.Render.YOffset); break; case TEST_BPP_16: Mip5Offset = Mip1Width * GetBppValue(bpp) + Mip0Height * ExpectedPitch; //EXPECT_EQ(128, ReqInfo.Render.XOffset); //EXPECT_EQ(0, ReqInfo.Render.YOffset); break; case TEST_BPP_32: Mip5Offset = Mip1Width * GetBppValue(bpp) + (Mip0Height + Mip2Height) * ExpectedPitch; //EXPECT_EQ(0, ReqInfo.Render.XOffset); //EXPECT_EQ(64, ReqInfo.Render.YOffset); break; case TEST_BPP_64: Mip5Offset = Mip1Width * GetBppValue(bpp) + (Mip0Height + Mip2Height) * ExpectedPitch; //EXPECT_EQ(0, ReqInfo.Render.XOffset); //EXPECT_EQ(32, ReqInfo.Render.YOffset); break; case TEST_BPP_128: Mip5Offset = Mip1Width * GetBppValue(bpp) + (Mip0Height + Mip2Height + Mip3Height) * ExpectedPitch; //EXPECT_EQ(512, ReqInfo.Render.XOffset); //EXPECT_EQ(0, ReqInfo.Render.YOffset); break; default: break; } uint32_t Mip5X = GFX_ALIGN_FLOOR(uint32_t(Mip4Offset % ExpectedPitch), TileSize[i][0]); uint32_t Mip5Y = GFX_ALIGN_FLOOR(uint32_t(Mip4Offset / ExpectedPitch), TileSize[i][1]); uint32_t Mip5RenderAlignedOffset = Mip5Y * ExpectedPitch + (Mip5X / TileSize[i][0]) * (TileSize[i][0] * TileSize[i][1]); //EXPECT_EQ(Mip5RenderAlignedOffset, ReqInfo.Render.Offset64); pGmmULTClientContext->DestroyResInfoObject(ResourceInfo); } } /// @brief ULT for 3D Tile64 Resource Optimization TEST_F(CTestGen12dGPUResource, DISABLED_Test3DTile64ResourceOptimization) { const uint32_t TileSize[TEST_BPP_MAX][2] = {{256, 256}, {512, 128}, {512, 128}, {1024, 64}, {1024, 64}}; GMM_RESCREATE_PARAMS gmmParams = {}; gmmParams.Type = RESOURCE_3D; gmmParams.Format = GMM_FORMAT_R8G8B8A8_UNORM; gmmParams.NoGfxMemory = 1; gmmParams.Flags.Gpu.Texture = 1; // TiledResource set 0 - allow to enter in Tile64 optimization logic gmmParams.Flags.Gpu.TiledResource = 0; gmmParams.ArraySize = 6; gmmParams.BaseWidth64 = 1; gmmParams.BaseHeight = 1; gmmParams.Depth = 1; GMM_RESOURCE_INFO *ResourceInfo; ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); // Check if Tile4 info flag VerifyResourceTile4(ResourceInfo, true); pGmmULTClientContext->DestroyResInfoObject(ResourceInfo); gmmParams.Type = RESOURCE_3D; gmmParams.BaseWidth64 = 128; gmmParams.BaseHeight = 128; gmmParams.NoGfxMemory = 1; gmmParams.Flags.Gpu.Texture = 1; gmmParams.Depth = 1; // TiledResource set 0 - allow to enter in Tile64 optimization logic gmmParams.Flags.Gpu.TiledResource = 0; gmmParams.ArraySize = 960; gmmParams.Flags.Info.Tile4 = 0; gmmParams.Flags.Info.Tile64 = 0; gmmParams.Format = GMM_FORMAT_BC6H; ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); // Check if Tile4 info flag VerifyResourceTile4(ResourceInfo, true); pGmmULTClientContext->DestroyResInfoObject(ResourceInfo); // Allocate surface that requires multi tiles in two dimension // Allocate 2 tiles in X dimension for(uint32_t i = 0; i < TEST_BPP_MAX; i++) { TEST_BPP bpp = static_cast(i); gmmParams.Type = RESOURCE_3D; gmmParams.Format = SetResourceFormat(bpp); gmmParams.BaseWidth64 = (TileSize[i][0] / GetBppValue(bpp)) + 1; // 1 pixel larger than 1 tile width gmmParams.BaseHeight = 0x1; gmmParams.Depth = 0x1; // TiledResource set 0 - allow to enter in Tile64 optimization logic gmmParams.Flags.Gpu.TiledResource = 0; gmmParams.Flags.Info.Tile4 = 0; gmmParams.Flags.Info.Tile64 = 0; GMM_RESOURCE_INFO *ResourceInfo; ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); // Check if Tile4 is set or not VerifyResourceTile4(ResourceInfo, true); pGmmULTClientContext->DestroyResInfoObject(ResourceInfo); } // Allocate 2 tiles in X/Y dimension for(uint32_t i = 0; i < TEST_BPP_MAX; i++) { TEST_BPP bpp = static_cast(i); gmmParams.Type = RESOURCE_3D; gmmParams.Format = GMM_FORMAT_R8G8B8A8_UNORM; //SetResourceFormat(bpp); gmmParams.BaseWidth64 = (TileSize[i][0] / GetBppValue(bpp)) + 1; // 1 pixel larger than 1 tile width gmmParams.BaseHeight = TileSize[i][1] + 1; // 1 row larger than 1 tile height gmmParams.Depth = 0x1; gmmParams.Flags.Info.Tile4 = 0; gmmParams.Flags.Info.Tile64 = 0; GMM_RESOURCE_INFO *ResourceInfo; ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); // Check if Tile4 is set or not VerifyResourceTile4(ResourceInfo, true); pGmmULTClientContext->DestroyResInfoObject(ResourceInfo); } } /// @brief ULT for 2D TileYf Compressed Resource TEST_F(CTestGen12dGPUResource, DISABLED_Test2DTileYfCompressedResource) { const uint32_t HAlign[TEST_BPP_MAX] = {64, 64, 32, 32, 16}; const uint32_t VAlign[TEST_BPP_MAX] = {64, 32, 32, 16, 16}; const uint32_t TileSize[TEST_BPP_MAX][2] = {{64, 64}, {128, 32}, {128, 32}, {256, 16}, {256, 16}}; GMM_RESCREATE_PARAMS gmmParams = {}; gmmParams.Type = RESOURCE_2D; gmmParams.NoGfxMemory = 1; gmmParams.Flags.Info.TiledY = 1; gmmParams.Flags.Info.TiledYf = 1; gmmParams.Flags.Gpu.Texture = 1; gmmParams.Flags.Info.RenderCompressed = 1; // Turn on .MC or .RC flag - mandatory to tell compression-type, for Yf its also used to pad surf // to 4x1 tile (reqd by HW ) // If unifiedAuxSurf reqd (mandatory for displayable or cross-adapter shared), turn on .CCS/.MMC and .UnifiedAuxSurface too //Allocate 1x1 surface for(uint32_t i = 0; i < TEST_BPP_MAX; i++) { gmmParams.Flags.Gpu.UnifiedAuxSurface = 1; //Turn off for separate aux creation gmmParams.Flags.Gpu.CCS = 1; //Turn off for separate aux creation TEST_BPP bpp = static_cast(i); GMM_TILE_MODE TileMode = DEFINE_TILE(YF_2D, bpp); gmmParams.Format = SetResourceFormat(bpp); gmmParams.BaseWidth64 = 0x1; gmmParams.BaseHeight = 0x1; GMM_RESOURCE_INFO *ResourceInfo; ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); VerifyResourceHAlign(ResourceInfo, HAlign[i]); VerifyResourceVAlign(ResourceInfo, VAlign[i]); VerifyResourcePitch(ResourceInfo, 4 * TileSize[i][0]); // As wide as 4 Tile VerifyResourcePitchInTiles(ResourceInfo, 4); // 4 Tile wide VerifyResourceSize(ResourceInfo, 4 * GMM_KBYTE(4)); // 4 Tile Big VerifyResourceQPitch(ResourceInfo, 0); //test main surface base alignment is 16KB //For Yf/Y test main surface pitch is 4-tileYF/Y aligned EXPECT_EQ(GMM_KBYTE(64), ResourceInfo->GetBaseAlignment()); EXPECT_EQ(0, ResourceInfo->GetRenderPitchTiles() % 4); if(const_cast(pGfxAdapterInfo->SkuTable).FtrLinearCCS) { EXPECT_EQ(0, ResourceInfo->GetUnifiedAuxSurfaceOffset(GMM_AUX_CCS) % PAGE_SIZE); EXPECT_GE(ResourceInfo->GetSizeAuxSurface(GMM_AUX_CCS), ResourceInfo->GetSizeMainSurface() >> 8); } EXPECT_EQ(GMM_KBYTE(4), ResourceInfo->GetSizeAuxSurface(GMM_AUX_CCS)); pGmmULTClientContext->DestroyResInfoObject(ResourceInfo); } // Allocate surface that requires multi tiles in two dimension // Allocate 2 tiles in X dimension for(uint32_t i = 0; i < TEST_BPP_MAX; i++) { gmmParams.Flags.Gpu.UnifiedAuxSurface = 1; //Turn off for separate aux creation gmmParams.Flags.Gpu.CCS = 1; //Turn off for separate aux creation TEST_BPP bpp = static_cast(i); GMM_TILE_MODE TileMode = DEFINE_TILE(YF_2D, bpp); gmmParams.Format = SetResourceFormat(bpp); gmmParams.BaseWidth64 = (TileSize[i][0] / GetBppValue(bpp)) + 1; // 1 pixel larger than 1 tile width gmmParams.BaseHeight = 0x1; gmmParams.Depth = 0x1; GMM_RESOURCE_INFO *ResourceInfo; ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); VerifyResourceHAlign(ResourceInfo, HAlign[i]); VerifyResourceVAlign(ResourceInfo, VAlign[i]); VerifyResourcePitch(ResourceInfo, TileSize[i][0] * 4); // As wide as 2 tile, but 4-tile pitch alignment VerifyResourcePitchInTiles(ResourceInfo, 4); // 2 tile wide, but 4-tile pitch alignment VerifyResourceSize(ResourceInfo, GMM_KBYTE(4) * 4); // 2 tile big, but 4-tile pitch alignment VerifyResourceQPitch(ResourceInfo, 0); //test main surface base alignment is 16KB //For Yf/Y test main surface pitch is 4-tileYF/Y aligned EXPECT_EQ(GMM_KBYTE(64), ResourceInfo->GetBaseAlignment()); EXPECT_EQ(0, ResourceInfo->GetRenderPitchTiles() % 4); if(const_cast(pGfxAdapterInfo->SkuTable).FtrLinearCCS) { EXPECT_EQ(0, ResourceInfo->GetUnifiedAuxSurfaceOffset(GMM_AUX_CCS) % PAGE_SIZE); EXPECT_GE(ResourceInfo->GetSizeAuxSurface(GMM_AUX_CCS), ResourceInfo->GetSizeMainSurface() >> 8); } EXPECT_EQ(GMM_KBYTE(4), ResourceInfo->GetSizeAuxSurface(GMM_AUX_CCS)); pGmmULTClientContext->DestroyResInfoObject(ResourceInfo); } // Allocate surface that requires multi tiles in two dimension // Allocate 2 tiles in X/Y dimension for(uint32_t i = 0; i < TEST_BPP_MAX; i++) { gmmParams.Flags.Gpu.UnifiedAuxSurface = 1; //Turn off for separate aux creation gmmParams.Flags.Gpu.CCS = 1; //Turn off for separate aux creation TEST_BPP bpp = static_cast(i); GMM_TILE_MODE TileMode = DEFINE_TILE(YF_2D, bpp); gmmParams.Format = SetResourceFormat(bpp); gmmParams.BaseWidth64 = (TileSize[i][0] / GetBppValue(bpp)) + 1; // 1 pixel larger than 1 tile width gmmParams.BaseHeight = TileSize[i][1] + 1; // 1 row larger than 1 tile height gmmParams.Depth = 0x1; GMM_RESOURCE_INFO *ResourceInfo; ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); VerifyResourceHAlign(ResourceInfo, HAlign[i]); VerifyResourceVAlign(ResourceInfo, VAlign[i]); VerifyResourcePitch(ResourceInfo, TileSize[i][0] * 4); // As wide as 2 tile, but 4-tile pitch alignment VerifyResourcePitchInTiles(ResourceInfo, 4); // 2 tile wide, but 4-tile pitch alignment VerifyResourceSize(ResourceInfo, GMM_KBYTE(4) * 4 * 2); // 4 tile wide; and 2-tile high VerifyResourceQPitch(ResourceInfo, 0); // Not tested //test main surface base alignment is 16KB //For Yf/Y test main surface pitch is 4-tileYF/Y aligned EXPECT_EQ(GMM_KBYTE(64), ResourceInfo->GetBaseAlignment()); EXPECT_EQ(0, ResourceInfo->GetRenderPitchTiles() % 4); if(const_cast(pGfxAdapterInfo->SkuTable).FtrLinearCCS) { EXPECT_EQ(0, ResourceInfo->GetUnifiedAuxSurfaceOffset(GMM_AUX_CCS) % PAGE_SIZE); EXPECT_GE(ResourceInfo->GetSizeAuxSurface(GMM_AUX_CCS), ResourceInfo->GetSizeMainSurface() >> 8); } EXPECT_EQ(GMM_KBYTE(4), ResourceInfo->GetSizeAuxSurface(GMM_AUX_CCS)); pGmmULTClientContext->DestroyResInfoObject(ResourceInfo); } } /// @brief ULT for 2D TileY Compressed Resource TEST_F(CTestGen12dGPUResource, DISABLED_Test2DTileYCompressedResource) { const uint32_t HAlign = {16}; const uint32_t VAlign = {4}; const uint32_t TileSize[2] = {128, 32}; GMM_RESCREATE_PARAMS gmmParams = {}; gmmParams.Type = RESOURCE_2D; gmmParams.NoGfxMemory = 1; gmmParams.Flags.Info.TiledY = 1; gmmParams.Flags.Gpu.Texture = 1; gmmParams.Flags.Info.RenderCompressed = 1; // Turn on .MC or .RC flag - mandatory to tell compression-type, for Yf/Y its also used to pad surf // to 4x1 tile (reqd by HW for perf reasons) // If unifiedAuxSurf reqd (mandatory for displayable or cross-adapter shared), turn on .CCS/.MMC and .UnifiedAuxSurface too //Allocate 1x1 surface for(uint32_t i = 0; i < TEST_BPP_MAX; i++) { gmmParams.Flags.Gpu.UnifiedAuxSurface = 1; //Turn off for separate aux creation gmmParams.Flags.Gpu.CCS = 1; //Turn off for separate aux creation TEST_BPP bpp = static_cast(i); GMM_TILE_MODE TileMode = LEGACY_TILE_Y; gmmParams.Format = SetResourceFormat(bpp); gmmParams.BaseWidth64 = 0x1; gmmParams.BaseHeight = 0x1; GMM_RESOURCE_INFO *ResourceInfo; ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); VerifyResourceHAlign(ResourceInfo, HAlign); VerifyResourceVAlign(ResourceInfo, VAlign); VerifyResourcePitch(ResourceInfo, 4 * TileSize[0]); // As wide as 4 Tile VerifyResourcePitchInTiles(ResourceInfo, 4); // 4 Tile wide VerifyResourceSize(ResourceInfo, 4 * GMM_KBYTE(4)); // 4 Tile Big VerifyResourceQPitch(ResourceInfo, 0); //test main surface base alignment is 16KB //For Yf/Y test main surface pitch is 4-tileYF/Y aligned EXPECT_EQ(GMM_KBYTE(64), ResourceInfo->GetBaseAlignment()); EXPECT_EQ(0, ResourceInfo->GetRenderPitchTiles() % 4); if(const_cast(pGfxAdapterInfo->SkuTable).FtrLinearCCS) { EXPECT_EQ(0, ResourceInfo->GetUnifiedAuxSurfaceOffset(GMM_AUX_CCS) % PAGE_SIZE); EXPECT_GE(ResourceInfo->GetSizeAuxSurface(GMM_AUX_CCS), ResourceInfo->GetSizeMainSurface() >> 8); } EXPECT_EQ(GMM_KBYTE(4), ResourceInfo->GetSizeAuxSurface(GMM_AUX_CCS)); pGmmULTClientContext->DestroyResInfoObject(ResourceInfo); } // Allocate surface that requires multi tiles in two dimension // Allocate 2 tiles in X dimension for(uint32_t i = 0; i < TEST_BPP_MAX; i++) { gmmParams.Flags.Gpu.UnifiedAuxSurface = 1; //Turn off for separate aux creation gmmParams.Flags.Gpu.CCS = 1; //Turn off for separate aux creation TEST_BPP bpp = static_cast(i); GMM_TILE_MODE TileMode = LEGACY_TILE_Y; gmmParams.Format = SetResourceFormat(bpp); gmmParams.BaseWidth64 = (TileSize[0] / GetBppValue(bpp)) + 1; // 1 pixel larger than 1 tile width gmmParams.BaseHeight = 0x1; gmmParams.Depth = 0x1; GMM_RESOURCE_INFO *ResourceInfo; ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); VerifyResourceHAlign(ResourceInfo, HAlign); VerifyResourceVAlign(ResourceInfo, VAlign); VerifyResourcePitch(ResourceInfo, TileSize[0] * 4); // As wide as 2 tile, but 4-tile pitch alignment VerifyResourcePitchInTiles(ResourceInfo, 4); // 2 tile wide, but 4-tile pitch alignment VerifyResourceSize(ResourceInfo, GMM_KBYTE(4) * 4); // 2 tile big, but 4-tile pitch alignment VerifyResourceQPitch(ResourceInfo, 0); //test main surface base alignment is 16KB //For Yf test main surface pitch is 4-tileYF aligned EXPECT_EQ(GMM_KBYTE(64), ResourceInfo->GetBaseAlignment()); EXPECT_EQ(0, ResourceInfo->GetRenderPitchTiles() % 4); // Check on YF only if(const_cast(pGfxAdapterInfo->SkuTable).FtrLinearCCS) { EXPECT_EQ(0, ResourceInfo->GetUnifiedAuxSurfaceOffset(GMM_AUX_CCS) % PAGE_SIZE); EXPECT_GE(ResourceInfo->GetSizeAuxSurface(GMM_AUX_CCS), ResourceInfo->GetSizeMainSurface() >> 8); } EXPECT_EQ(GMM_KBYTE(4), ResourceInfo->GetSizeAuxSurface(GMM_AUX_CCS)); pGmmULTClientContext->DestroyResInfoObject(ResourceInfo); } // Allocate surface that requires multi tiles in two dimension // Allocate 2 tiles in X/Y dimension for(uint32_t i = 0; i < TEST_BPP_MAX; i++) { gmmParams.Flags.Gpu.UnifiedAuxSurface = 1; //Turn off for separate aux creation gmmParams.Flags.Gpu.CCS = 1; //Turn off for separate aux creation TEST_BPP bpp = static_cast(i); GMM_TILE_MODE TileMode = LEGACY_TILE_Y; gmmParams.Format = SetResourceFormat(bpp); gmmParams.BaseWidth64 = (TileSize[0] / GetBppValue(bpp)) + 1; // 1 pixel larger than 1 tile width gmmParams.BaseHeight = TileSize[1] + 1; // 1 row larger than 1 tile height gmmParams.Depth = 0x1; GMM_RESOURCE_INFO *ResourceInfo; ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); VerifyResourceHAlign(ResourceInfo, HAlign); VerifyResourceVAlign(ResourceInfo, VAlign); VerifyResourcePitch(ResourceInfo, TileSize[0] * 4); // As wide as 2 tile, but 4-tile pitch alignment VerifyResourcePitchInTiles(ResourceInfo, 4); // 2 tile wide, but 4-tile pitch alignment VerifyResourceSize(ResourceInfo, GMM_KBYTE(4) * 4 * 2); // 4 tile wide; and 2-tile high VerifyResourceQPitch(ResourceInfo, 0); //test main surface base alignment is 16KB //For Yf/Y test main surface pitch is 4-tileYF/Y aligned EXPECT_EQ(GMM_KBYTE(64), ResourceInfo->GetBaseAlignment()); EXPECT_EQ(0, ResourceInfo->GetRenderPitchTiles() % 4); // Check on YF only if(const_cast(pGfxAdapterInfo->SkuTable).FtrLinearCCS) { EXPECT_EQ(0, ResourceInfo->GetUnifiedAuxSurfaceOffset(GMM_AUX_CCS) % PAGE_SIZE); EXPECT_GE(ResourceInfo->GetSizeAuxSurface(GMM_AUX_CCS), ResourceInfo->GetSizeMainSurface() >> 8); } EXPECT_EQ(GMM_KBYTE(4), ResourceInfo->GetSizeAuxSurface(GMM_AUX_CCS)); pGmmULTClientContext->DestroyResInfoObject(ResourceInfo); } } /// @brief ULT for 2D TileY lossless Compressed lossy Resource TEST_F(CTestGen12dGPUResource, DISABLED_Test2DTileYLossyCompressedResource) { const uint32_t HAlign = {4}; const uint32_t VAlign = {4}; const uint32_t TileSize[2] = {128, 32}; GMM_RESCREATE_PARAMS gmmParams = {}; gmmParams.Type = RESOURCE_2D; gmmParams.NoGfxMemory = 1; gmmParams.Flags.Info.TiledY = 1; gmmParams.Flags.Gpu.Texture = 1; gmmParams.Flags.Info.RenderCompressed = 1; // Turn on .MC or .RC flag - mandatory to tell compression-type, for Yf its also used to pad surf // to 4x1 tile (reqd by HW for perf reasons) // If unifiedAuxSurf reqd (mandatory for displayable or cross-adapter shared), turn on .CCS/.MMC and .UnifiedAuxSurface too //Allocate 1x1 surface for(uint32_t i = 0; i < TEST_BPP_MAX; i++) { gmmParams.Flags.Gpu.UnifiedAuxSurface = 1; //Turn off for separate aux creation gmmParams.Flags.Gpu.CCS = 1; //Turn off for separate aux creation TEST_BPP bpp = static_cast(i); GMM_TILE_MODE TileMode = LEGACY_TILE_Y; gmmParams.Format = GMM_FORMAT_ETC2_RGB8; gmmParams.BaseWidth64 = 0x80; gmmParams.BaseHeight = 0x20; GMM_RESOURCE_INFO *ResourceInfo; ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); VerifyResourceHAlign(ResourceInfo, HAlign); VerifyResourceVAlign(ResourceInfo, VAlign); VerifyResourcePitch(ResourceInfo, 4 * TileSize[0]); // As wide as 4 Tile VerifyResourcePitchInTiles(ResourceInfo, 4); // 4 Tile wide VerifyResourceSize(ResourceInfo, 4 * GMM_KBYTE(4)); // 4 Tile Big VerifyResourceQPitch(ResourceInfo, 0); //test main surface base alignment is 16KB //For Yf/Y test main surface pitch is 4-tileYF/Y aligned EXPECT_EQ(GMM_KBYTE(64), ResourceInfo->GetBaseAlignment()); EXPECT_EQ(0, ResourceInfo->GetRenderPitchTiles() % 4); if(const_cast(pGfxAdapterInfo->SkuTable).FtrLinearCCS) { EXPECT_EQ(0, ResourceInfo->GetUnifiedAuxSurfaceOffset(GMM_AUX_CCS) % PAGE_SIZE); EXPECT_GE(ResourceInfo->GetSizeAuxSurface(GMM_AUX_CCS), ResourceInfo->GetSizeMainSurface() >> 8); } EXPECT_EQ(GMM_KBYTE(4), ResourceInfo->GetSizeAuxSurface(GMM_AUX_CCS)); { //separate Aux gmmParams.Flags.Gpu.UnifiedAuxSurface = 0; GMM_RESOURCE_INFO *AuxResourceInfo; AuxResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); EXPECT_EQ(ResourceInfo->GetAuxHAlign(), AuxResourceInfo->GetHAlign()); EXPECT_EQ(ResourceInfo->GetAuxVAlign(), AuxResourceInfo->GetVAlign()); EXPECT_EQ(ResourceInfo->GetUnifiedAuxPitch(), AuxResourceInfo->GetRenderPitch()); EXPECT_EQ(ResourceInfo->GetSizeAuxSurface(GMM_AUX_CCS), AuxResourceInfo->GetSizeSurface()); pGmmULTClientContext->DestroyResInfoObject(AuxResourceInfo); } pGmmULTClientContext->DestroyResInfoObject(ResourceInfo); } // Allocate surface that requires multi tiles in two dimension // Allocate 2 tiles in X dimension for(uint32_t i = 0; i < TEST_BPP_MAX; i++) { gmmParams.Flags.Gpu.UnifiedAuxSurface = 1; //Turn off for separate aux creation gmmParams.Flags.Gpu.CCS = 1; //Turn off for separate aux creation TEST_BPP bpp = static_cast(i); GMM_TILE_MODE TileMode = LEGACY_TILE_Y; gmmParams.Format = GMM_FORMAT_ETC2_RGB8; gmmParams.BaseWidth64 = (TileSize[0] / GetBppValue(bpp)) + 1; // 1 pixel larger than 1 tile width gmmParams.BaseHeight = 0x1; gmmParams.Depth = 0x1; GMM_RESOURCE_INFO *ResourceInfo; ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); VerifyResourceHAlign(ResourceInfo, HAlign); VerifyResourceVAlign(ResourceInfo, VAlign); VerifyResourcePitch(ResourceInfo, TileSize[0] * 4); // As wide as 2 tile, but 4-tile pitch alignment VerifyResourcePitchInTiles(ResourceInfo, 4); // 2 tile wide, but 4-tile pitch alignment VerifyResourceSize(ResourceInfo, GMM_KBYTE(4) * 4); // 2 tile big, but 4-tile pitch alignment VerifyResourceQPitch(ResourceInfo, 0); //test main surface base alignment is 16KB //For Yf/Y test main surface pitch is 4-tileYF/Y aligned EXPECT_EQ(GMM_KBYTE(64), ResourceInfo->GetBaseAlignment()); EXPECT_EQ(0, ResourceInfo->GetRenderPitchTiles() % 4); if(const_cast(pGfxAdapterInfo->SkuTable).FtrLinearCCS) { EXPECT_EQ(0, ResourceInfo->GetUnifiedAuxSurfaceOffset(GMM_AUX_CCS) % PAGE_SIZE); EXPECT_GE(ResourceInfo->GetSizeAuxSurface(GMM_AUX_CCS), ResourceInfo->GetSizeMainSurface() >> 8); } EXPECT_EQ(GMM_KBYTE(4), ResourceInfo->GetSizeAuxSurface(GMM_AUX_CCS)); { //separate Aux gmmParams.Flags.Gpu.UnifiedAuxSurface = 0; GMM_RESOURCE_INFO *AuxResourceInfo; AuxResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); EXPECT_EQ(ResourceInfo->GetAuxHAlign(), AuxResourceInfo->GetHAlign()); EXPECT_EQ(ResourceInfo->GetAuxVAlign(), AuxResourceInfo->GetVAlign()); EXPECT_EQ(ResourceInfo->GetUnifiedAuxPitch(), AuxResourceInfo->GetRenderPitch()); EXPECT_EQ(ResourceInfo->GetSizeAuxSurface(GMM_AUX_CCS), AuxResourceInfo->GetSizeSurface()); pGmmULTClientContext->DestroyResInfoObject(AuxResourceInfo); } pGmmULTClientContext->DestroyResInfoObject(ResourceInfo); } // Allocate surface that requires multi tiles in two dimension // Allocate 2 tiles in X/Y dimension for(uint32_t i = 0; i < TEST_BPP_MAX; i++) { gmmParams.Flags.Gpu.UnifiedAuxSurface = 1; //Turn off for separate aux creation gmmParams.Flags.Gpu.CCS = 1; //Turn off for separate aux creation TEST_BPP bpp = static_cast(i); GMM_TILE_MODE TileMode = LEGACY_TILE_Y; gmmParams.Format = GMM_FORMAT_ETC2_RGB8; gmmParams.BaseWidth64 = (TileSize[0] / GetBppValue(bpp)) + 1; // 1 pixel larger than 1 tile width gmmParams.BaseHeight = TileSize[1] + 1; // 1 row larger than 1 tile height gmmParams.Depth = 0x1; GMM_RESOURCE_INFO *ResourceInfo; ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); VerifyResourceHAlign(ResourceInfo, HAlign); VerifyResourceVAlign(ResourceInfo, VAlign); VerifyResourcePitch(ResourceInfo, TileSize[0] * 4); // As wide as 2 tile, but 4-tile pitch alignment VerifyResourcePitchInTiles(ResourceInfo, 4); // 2 tile wide, but 4-tile pitch alignment VerifyResourceSize(ResourceInfo, GMM_KBYTE(4) * 4); // 4 tile wide; max compressed height = 0x24/4 = 9, so fits in 1 tile-height VerifyResourceQPitch(ResourceInfo, 0); //test main surface base alignment is 16KB //For Yf/Y test main surface pitch is 4-tileYF/Y aligned EXPECT_EQ(GMM_KBYTE(64), ResourceInfo->GetBaseAlignment()); EXPECT_EQ(0, ResourceInfo->GetRenderPitchTiles() % 4); if(const_cast(pGfxAdapterInfo->SkuTable).FtrLinearCCS) { EXPECT_EQ(0, ResourceInfo->GetUnifiedAuxSurfaceOffset(GMM_AUX_CCS) % PAGE_SIZE); EXPECT_GE(ResourceInfo->GetSizeAuxSurface(GMM_AUX_CCS), ResourceInfo->GetSizeMainSurface() >> 8); } EXPECT_EQ(GMM_KBYTE(4), ResourceInfo->GetSizeAuxSurface(GMM_AUX_CCS)); { //separate Aux gmmParams.Flags.Gpu.UnifiedAuxSurface = 0; GMM_RESOURCE_INFO *AuxResourceInfo; AuxResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); EXPECT_EQ(ResourceInfo->GetAuxHAlign(), AuxResourceInfo->GetHAlign()); EXPECT_EQ(ResourceInfo->GetAuxVAlign(), AuxResourceInfo->GetVAlign()); EXPECT_EQ(ResourceInfo->GetUnifiedAuxPitch(), AuxResourceInfo->GetRenderPitch()); EXPECT_EQ(ResourceInfo->GetSizeAuxSurface(GMM_AUX_CCS), AuxResourceInfo->GetSizeSurface()); pGmmULTClientContext->DestroyResInfoObject(AuxResourceInfo); } pGmmULTClientContext->DestroyResInfoObject(ResourceInfo); } } //Y416(64bpp -how is 10/12/16bit depth given?) //Y410(32bpp), Y216(64bpp), YCRCB_NORMAL(16bpp), YCRCB_SWAPUV(16bpp), //YCRCB_SWAPUVY(16bpp), YCRCB_SWAPY(16bpp) /// @brief ULT for Planar Compressed Resource TEST_F(CTestGen12dGPUResource, DISABLED_TestPlanarYfCompressedResource) { const uint32_t TileSize[TEST_BPP_MAX][2] = { {64, 64}, {128, 32}, {128, 32}, {256, 16}, {256, 16}}; // TileYf GMM_RESCREATE_PARAMS gmmParams = {}; gmmParams.Type = RESOURCE_2D; gmmParams.NoGfxMemory = 1; gmmParams.Flags.Gpu.Texture = 1; //gmmParams.Flags.Gpu.MMC = 1; gmmParams.Flags.Gpu.CCS = 1; gmmParams.Flags.Info.MediaCompressed = 1; gmmParams.BaseWidth64 = 0x100; gmmParams.BaseHeight = 0x50; gmmParams.Depth = 0x1; SetTileFlag(gmmParams, TEST_TILEYF); // TileYF only //UV-Packed formats GMM_RESOURCE_FORMAT Format[4] = {GMM_FORMAT_NV12, GMM_FORMAT_NV21, GMM_FORMAT_P010, GMM_FORMAT_P016}; for(auto fmt : Format) { gmmParams.Format = fmt; // 8bpp (NV12, NV21), 16bpp (P016,P010) TEST_BPP Ybpp, UVbpp; //Yf/Ys could be accessed on CPU/app where UV plane bpp is double switch(pGmmULTClientContext->GetPlatformInfo().FormatTable[fmt].Element.BitsPer) { case 8: Ybpp = TEST_BPP_8; UVbpp = TEST_BPP_16; break; case 16: Ybpp = TEST_BPP_16; UVbpp = TEST_BPP_32; break; default: return; } gmmParams.Flags.Gpu.UnifiedAuxSurface = 1; /*Aux is TileY (later Linear), not redescribing, its bytes are allocated using one bpp*/ GMM_TILE_MODE TileMode = DEFINE_TILE(YF_2D, Ybpp); GMM_RESOURCE_INFO *ResourceInfo; ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); //Redescribed Pitch isn't modified unless Y, UV pitch differ //But, original Pitch is padded to have even Tile, hence use Ybpp ExpectedPitch //to verify Pitch, but redescribed size uint32_t ExpectedPitch = GMM_ULT_ALIGN(gmmParams.BaseWidth64 * (int)pow(2.0, Ybpp), TileSize[Ybpp][0] * 4); uint32_t RedescribedPitch = GMM_ULT_ALIGN(gmmParams.BaseWidth64 / 2 * (int)pow(2.0, UVbpp), TileSize[UVbpp][0] * 4); //ExpectedPitch = GMM_ULT_ALIGN(ExpectedPitch, 2 * TileSize[Ybpp][0]); //pad to even tile if(ExpectedPitch != RedescribedPitch) { ExpectedPitch = RedescribedPitch; } VerifyResourcePitch(ResourceInfo, ExpectedPitch); VerifyResourcePitchInTiles(ResourceInfo, ExpectedPitch / TileSize[Ybpp][0]); int YSizeInTiles = (GMM_ULT_ALIGN(gmmParams.BaseHeight, TileSize[Ybpp][1]) / TileSize[Ybpp][1]) * RedescribedPitch / TileSize[Ybpp][0]; int UVSizeInTiles = (GMM_ULT_ALIGN(gmmParams.BaseHeight / 2, TileSize[UVbpp][1]) / TileSize[UVbpp][1]) * RedescribedPitch / TileSize[UVbpp][0]; VerifyResourceSize(ResourceInfo, GMM_KBYTE(4) * (YSizeInTiles + UVSizeInTiles)); VerifyResourceHAlign(ResourceInfo, TileSize[UVbpp][0] / pow(2.0, UVbpp)); // For Yf/Ys planar redescription causes UV width, Y height alignment VerifyResourceVAlign(ResourceInfo, TileSize[Ybpp][1]); VerifyResourceQPitch(ResourceInfo, 0); // N/A for non-mipped surface //test main surface base alignment is 16KB //For Yf test main surface pitch is 4-tileYF aligned EXPECT_EQ(GMM_KBYTE(64), ResourceInfo->GetBaseAlignment()); EXPECT_EQ(0, ResourceInfo->GetRenderPitchTiles() % 4); // Check on YF only if(const_cast(pGfxAdapterInfo->SkuTable).FtrLinearCCS) { EXPECT_EQ(0, ResourceInfo->GetUnifiedAuxSurfaceOffset(GMM_AUX_CCS) % PAGE_SIZE); EXPECT_GE(ResourceInfo->GetSizeAuxSurface(GMM_AUX_CCS), ResourceInfo->GetSizeMainSurface() >> 8); } EXPECT_EQ(GMM_KBYTE(4) * 2, ResourceInfo->GetSizeAuxSurface(GMM_AUX_CCS)); // Y and UV Aux are on separate tiles { //separate Aux gmmParams.Flags.Gpu.UnifiedAuxSurface = 0; GMM_RESOURCE_INFO *AuxResourceInfo; AuxResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); EXPECT_EQ(GMM_KBYTE(4) * 2, AuxResourceInfo->GetSizeSurface()); pGmmULTClientContext->DestroyResInfoObject(AuxResourceInfo); } pGmmULTClientContext->DestroyResInfoObject(ResourceInfo); } } /// @brief ULT for Planar Y Compressed Resource TEST_F(CTestGen12dGPUResource, DISABLED_TestPlanarYCompressedResource) { const uint32_t TileSize[2] = {128, 32}; const uint32_t HAlign = 16; const uint32_t VAlign = 4; GMM_RESCREATE_PARAMS gmmParams = {}; gmmParams.Type = RESOURCE_2D; gmmParams.NoGfxMemory = 1; gmmParams.Flags.Gpu.Texture = 1; gmmParams.Flags.Gpu.RenderTarget = 1; gmmParams.Flags.Gpu.MMC = 1; gmmParams.Flags.Gpu.CCS = 1; gmmParams.Flags.Gpu.IndirectClearColor = 1; gmmParams.Flags.Info.MediaCompressed = 1; gmmParams.Flags.Info.NotLockable = 1; gmmParams.Flags.Info.Cacheable = 1; gmmParams.BaseWidth64 = 0xB2; gmmParams.BaseHeight = 0x92; gmmParams.Depth = 0x1; SetTileFlag(gmmParams, TEST_TILEY); // TileYF only GMM_RESOURCE_FORMAT Format[4] = {GMM_FORMAT_NV12, GMM_FORMAT_NV21, GMM_FORMAT_P010, GMM_FORMAT_P016}; for(auto fmt : Format) { gmmParams.Format = fmt; // 8bpp (NV12, NV21), 16bpp (P016, P010) TEST_BPP Ybpp, UVbpp; //Yf/Ys could be accessed on CPU/app where UV plane bpp is double switch(pGmmULTClientContext->GetPlatformInfo().FormatTable[fmt].Element.BitsPer) { case 8: Ybpp = TEST_BPP_8; UVbpp = TEST_BPP_16; break; case 16: Ybpp = TEST_BPP_16; UVbpp = TEST_BPP_32; break; default: return; } gmmParams.Flags.Gpu.UnifiedAuxSurface = 1; GMM_TILE_MODE TileMode = LEGACY_TILE_Y; GMM_RESOURCE_INFO *ResourceInfo; ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); //Redescribed Pitch isn't modified unless Y, UV pitch differ //But, original Pitch is padded to have even Tile, hence use Ybpp ExpectedPitch //to verify Pitch, but redescribed size uint32_t ExpectedPitch = GMM_ULT_ALIGN(gmmParams.BaseWidth64 * (int)pow(2.0, Ybpp), TileSize[0] * 4); uint32_t RedescribedPitch = GMM_ULT_ALIGN(gmmParams.BaseWidth64 / 2 * (int)pow(2.0, UVbpp), TileSize[0] * 4); //ExpectedPitch = GMM_ULT_ALIGN(ExpectedPitch, 2 * TileSize[Ybpp][0]); //pad to even tile if(ExpectedPitch != RedescribedPitch) { ExpectedPitch = RedescribedPitch; } VerifyResourcePitch(ResourceInfo, ExpectedPitch); VerifyResourcePitchInTiles(ResourceInfo, ExpectedPitch / TileSize[0]); int YSizeInTiles = (GMM_ULT_ALIGN(gmmParams.BaseHeight, TileSize[1]) / TileSize[1]) * RedescribedPitch / TileSize[0]; int UVSizeInTiles = (GMM_ULT_ALIGN(gmmParams.BaseHeight / 2, TileSize[1]) / TileSize[1]) * RedescribedPitch / TileSize[0]; VerifyResourceSize(ResourceInfo, GMM_KBYTE(4) * (YSizeInTiles + UVSizeInTiles)); //when main-surf planes are tile-aligned, make it verify-true VerifyResourceHAlign(ResourceInfo, HAlign); VerifyResourceVAlign(ResourceInfo, VAlign); VerifyResourceQPitch(ResourceInfo, 0); // N/A for non-mipped surface //test main surface base alignment is 16KB //For Yf test main surface pitch is 4-tileY aligned EXPECT_EQ(GMM_KBYTE(64), ResourceInfo->GetBaseAlignment()); EXPECT_EQ(0, ResourceInfo->GetRenderPitchTiles() % 4); if(const_cast(pGfxAdapterInfo->SkuTable).FtrLinearCCS) { EXPECT_EQ(0, ResourceInfo->GetUnifiedAuxSurfaceOffset(GMM_AUX_CCS) % PAGE_SIZE); EXPECT_EQ(0, ResourceInfo->GetUnifiedAuxSurfaceOffset(GMM_AUX_UV_CCS) % PAGE_SIZE); EXPECT_GE(ResourceInfo->GetSizeAuxSurface(GMM_AUX_CCS), ResourceInfo->GetSizeMainSurface() >> 8); } EXPECT_EQ(GMM_KBYTE(4) * 2, ResourceInfo->GetSizeAuxSurface(GMM_AUX_CCS)); // Y and UV Aux are on separate tiles pGmmULTClientContext->DestroyResInfoObject(ResourceInfo); } } /// @brief ULT for Planar Ys Compressed resource TEST_F(CTestGen12dGPUResource, TestPlanarTile64CompressedResource) { const uint32_t TileSize[TEST_BPP_MAX][2] = { {256, 256}, {512, 128}, {512, 128}, {1024, 64}, {1024, 64}}; // TileYS GMM_RESCREATE_PARAMS gmmParams = {}; gmmParams.Type = RESOURCE_2D; gmmParams.NoGfxMemory = 1; gmmParams.Flags.Gpu.Texture = 1; gmmParams.Flags.Gpu.MMC = 1; //gmmParams.Flags.Gpu.CCS = 1; gmmParams.Flags.Gpu.UnifiedAuxSurface = 1; gmmParams.Flags.Info.MediaCompressed = 1; gmmParams.BaseWidth64 = 0x64; gmmParams.BaseHeight = 0x64; gmmParams.Depth = 0x1; gmmParams.ArraySize = 2; GMM_RESOURCE_FORMAT Format[4] = {GMM_FORMAT_NV12, GMM_FORMAT_NV21, GMM_FORMAT_P010, GMM_FORMAT_P016}; for(auto fmt : Format) { gmmParams.Format = fmt; // 8bpp(NV12) , P016 (16bpp), P010 (16bpp), NV21(8bpp) TEST_BPP Ybpp, UVbpp; //could be accessed on CPU/app where UV plane bpp is double switch(pGmmULTClientContext->GetPlatformInfo().FormatTable[gmmParams.Format].Element.BitsPer) { case 8: Ybpp = TEST_BPP_8; UVbpp = TEST_BPP_16; break; case 16: Ybpp = TEST_BPP_16; UVbpp = TEST_BPP_32; break; default: return; } gmmParams.Flags.Gpu.UnifiedAuxSurface = 1; GMM_RESOURCE_INFO *ResourceInfo; ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); GMM_REQ_OFFSET_INFO OffsetInfo = {}; OffsetInfo.ReqLock = 1; OffsetInfo.ReqRender = 1; OffsetInfo.Plane = GMM_PLANE_Y; OffsetInfo.ArrayIndex = 1; OffsetInfo.ReqStdLayout = 0; ResourceInfo->GetOffset(OffsetInfo); // ToDo: add verification //{ //separate Aux // gmmParams.Flags.Gpu.UnifiedAuxSurface = 0; // GMM_RESOURCE_INFO *AuxResourceInfo; // AuxResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); // EXPECT_EQ(ResourceInfo->GetSizeAuxSurface(GMM_AUX_CCS), AuxResourceInfo->G // add verification //{ //separate Aux // gmmParams.Flags.Gpu.UnifiedAuxSurface = 0; // GMM_RESOURCE_INFO *AuxResourceInfo; // AuxResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); // EXPECT_EQ(ResourceInfo->GetSizeAuxSurface(GMM_AUX_CCS), AuxResourceInfo->GetSizeSurface()); // pGmmULTClientContext->DestroyResInfoObject(AuxResourceInfo); //} pGmmULTClientContext->DestroyResInfoObject(ResourceInfo); } } /// @brief ULT for 2D arrayed compressed Resource TEST_F(CTestGen12dGPUResource, TestArrayedCompressedResource) { //printf("%s\n", __FUNCTION__); //Test for 3D array } /// @brief ULT for mip-mapped compressed Resource TEST_F(CTestGen12dGPUResource, TestMipMapCompressedResource) { //printf("%s\n", __FUNCTION__); } /// @brief ULT for cube Compressed Resource TEST_F(CTestGen12dGPUResource, DISABLED_TestCubeCompressedResource) { //Tests 2D array const uint32_t HAlign[5][TEST_BPP_MAX] = {{0}, {0}, {0}, {256, 256, 128, 128, 64}, {64, 64, 32, 32, 16}}; const uint32_t VAlign[5][TEST_BPP_MAX] = {{0}, {0}, {0}, {256, 128, 128, 64, 64}, {64, 32, 32, 16, 16}}; const TEST_TILE_TYPE TileTypeSupported[2] = {TEST_TILEYS, TEST_TILEYF}; const uint32_t TileSize[5][TEST_BPP_MAX][2] = { {0}, {0}, {0}, {{256, 256}, {512, 128}, {512, 128}, {1024, 64}, {1024, 64}}, // TileYS {{64, 64}, {128, 32}, {128, 32}, {256, 16}, {256, 16}}}; //TileYf GMM_RESCREATE_PARAMS gmmParams = {}; gmmParams.Type = RESOURCE_CUBE; gmmParams.NoGfxMemory = 1; gmmParams.Flags.Gpu.Texture = 1; gmmParams.Flags.Info.RenderCompressed = 1; // Allocate 1x1 surface so that it occupies 1 Tile in X dimension for(auto Tiling : TileTypeSupported) { gmmParams.Flags.Info.TiledY = 1; gmmParams.Flags.Info.TiledYf = (Tiling == TEST_TILEYF); gmmParams.Flags.Info.TiledYs = (Tiling == TEST_TILEYS); for(uint32_t i = 0; i < TEST_BPP_MAX; i++) { gmmParams.Flags.Gpu.UnifiedAuxSurface = 1; gmmParams.Flags.Gpu.CCS = 1; TEST_BPP bpp = static_cast(i); GMM_TILE_MODE TileMode = (Tiling == TEST_TILEYF) ? DEFINE_TILE(YF_2D, bpp) : DEFINE_TILE(YS_2D, bpp); gmmParams.Format = SetResourceFormat(bpp); gmmParams.BaseWidth64 = 0x1; gmmParams.BaseHeight = 0x1; gmmParams.Depth = 0x1; GMM_RESOURCE_INFO *ResourceInfo; ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); VerifyResourceHAlign(ResourceInfo, HAlign[Tiling][i]); VerifyResourceVAlign(ResourceInfo, VAlign[Tiling][i]); uint32_t ExpectedPitch = 4 * TileSize[TEST_TILEYF][i][0]; VerifyResourcePitch(ResourceInfo, ExpectedPitch); // As wide as 4 tile-YF VerifyResourcePitchInTiles(ResourceInfo, (Tiling == TEST_TILEYF) ? 4 : 1); // 1 tile wide uint32_t ExpectedQPitch = VAlign[Tiling][i]; VerifyResourceQPitch(ResourceInfo, ExpectedQPitch); // Each face should be VAlign rows apart within a tile VerifyResourceSize(ResourceInfo, // PitchInBytes * Rows where Rows = __GMM_MAX_CUBE_FACE x QPitch, then aligned to tile boundary ExpectedPitch * __GMM_MAX_CUBE_FACE * ExpectedQPitch); //test main surface base alignment is 16KB //For Yf test main surface pitch is 4-tileYF aligned EXPECT_EQ(GMM_KBYTE(64), ResourceInfo->GetBaseAlignment()); EXPECT_EQ(0, ResourceInfo->GetRenderPitchTiles() % ((Tiling == TEST_TILEYF) ? 4 : 1)); if(const_cast(pGfxAdapterInfo->SkuTable).FtrLinearCCS) { EXPECT_EQ(0, ResourceInfo->GetUnifiedAuxSurfaceOffset(GMM_AUX_CCS) % PAGE_SIZE); EXPECT_GE(ResourceInfo->GetSizeAuxSurface(GMM_AUX_CCS), ResourceInfo->GetSizeMainSurface() >> 8); } EXPECT_EQ(GMM_KBYTE(4), ResourceInfo->GetSizeAuxSurface(GMM_AUX_CCS)); { //separate Aux gmmParams.Flags.Gpu.UnifiedAuxSurface = 0; GMM_RESOURCE_INFO *AuxResourceInfo; AuxResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); EXPECT_EQ(ResourceInfo->GetAuxHAlign(), AuxResourceInfo->GetHAlign()); EXPECT_EQ(ResourceInfo->GetAuxVAlign(), AuxResourceInfo->GetVAlign()); EXPECT_EQ(ResourceInfo->GetUnifiedAuxPitch(), AuxResourceInfo->GetRenderPitch()); EXPECT_EQ(ResourceInfo->GetSizeAuxSurface(GMM_AUX_CCS), AuxResourceInfo->GetSizeSurface()); pGmmULTClientContext->DestroyResInfoObject(AuxResourceInfo); } for(uint32_t CubeFaceIndex = 0; CubeFaceIndex < __GMM_MAX_CUBE_FACE; CubeFaceIndex++) { GMM_REQ_OFFSET_INFO OffsetInfo = {}; OffsetInfo.ReqRender = 1; OffsetInfo.CubeFace = static_cast(CubeFaceIndex); ResourceInfo->GetOffset(OffsetInfo); EXPECT_EQ((CubeFaceIndex * ExpectedQPitch) * ExpectedPitch, OffsetInfo.Render.Offset64); // Render offset is tile's base address on which cube face begins. EXPECT_EQ(0, OffsetInfo.Render.XOffset); // X Offset should be 0 as cube face starts on tile boundary EXPECT_EQ(0, OffsetInfo.Render.YOffset); // Y Offset should be 0 as cube face starts on tile boundary EXPECT_EQ(0, OffsetInfo.Render.ZOffset); // Z offset N/A should be 0 } pGmmULTClientContext->DestroyResInfoObject(ResourceInfo); } // Allocate 2 tiles in X dimension. // Width and Height must be equal for(uint32_t i = 0; i < TEST_BPP_MAX; i++) { gmmParams.Flags.Gpu.UnifiedAuxSurface = 1; gmmParams.Flags.Gpu.CCS = 1; TEST_BPP bpp = static_cast(i); GMM_TILE_MODE TileMode = (Tiling == TEST_TILEYF) ? DEFINE_TILE(YF_2D, bpp) : DEFINE_TILE(YS_2D, bpp); gmmParams.Format = SetResourceFormat(bpp); gmmParams.BaseWidth64 = (TileSize[Tiling][i][0] / GetBppValue(bpp)) + 1; // 1 pixel larger than 1 tile width gmmParams.BaseHeight = gmmParams.BaseWidth64; // Heigth must be equal to width. gmmParams.Depth = 0x1; GMM_RESOURCE_INFO *ResourceInfo; ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); VerifyResourceHAlign(ResourceInfo, HAlign[Tiling][i]); VerifyResourceVAlign(ResourceInfo, VAlign[Tiling][i]); uint32_t ExpectedPitch = TileSize[Tiling][i][0] * 2 * ((Tiling == TEST_TILEYF) ? 2 : 1); // As wide as 2 tile, padded to 4 tile-pitch VerifyResourcePitch(ResourceInfo, ExpectedPitch); VerifyResourcePitchInTiles(ResourceInfo, 2 * ((Tiling == TEST_TILEYF) ? 2 : 1)); // 2 tile wide uint32_t ExpectedQPitch = GMM_ULT_ALIGN(gmmParams.BaseHeight, VAlign[Tiling][i]); VerifyResourceQPitch(ResourceInfo, ExpectedQPitch); // Each face should be Valigned-BaseHeight rows apart VerifyResourceSize(ResourceInfo, // PitchInBytes * Rows where Rows = __GMM_MAX_CUBE_FACE x QPitch, then aligned to tile boundary ExpectedPitch * __GMM_MAX_CUBE_FACE * ExpectedQPitch); //test main surface base alignment is 16KB //For Yf test main surface pitch is 4-tileYF aligned EXPECT_EQ(GMM_KBYTE(64), ResourceInfo->GetBaseAlignment()); EXPECT_EQ(0, ResourceInfo->GetRenderPitchTiles() % ((Tiling == TEST_TILEYF) ? 4 : 1)); // Check on YF only if(const_cast(pGfxAdapterInfo->SkuTable).FtrLinearCCS) { EXPECT_EQ(0, ResourceInfo->GetUnifiedAuxSurfaceOffset(GMM_AUX_CCS) % PAGE_SIZE); EXPECT_GE(ResourceInfo->GetSizeAuxSurface(GMM_AUX_CCS), ResourceInfo->GetSizeMainSurface() >> 8); } { //separate Aux gmmParams.Flags.Gpu.UnifiedAuxSurface = 0; GMM_RESOURCE_INFO *AuxResourceInfo; AuxResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); EXPECT_EQ(ResourceInfo->GetAuxHAlign(), AuxResourceInfo->GetHAlign()); EXPECT_EQ(ResourceInfo->GetAuxVAlign(), AuxResourceInfo->GetVAlign()); EXPECT_EQ(ResourceInfo->GetUnifiedAuxPitch(), AuxResourceInfo->GetRenderPitch()); EXPECT_EQ(ResourceInfo->GetSizeAuxSurface(GMM_AUX_CCS), AuxResourceInfo->GetSizeSurface()); pGmmULTClientContext->DestroyResInfoObject(AuxResourceInfo); } for(uint32_t CubeFaceIndex = 0; CubeFaceIndex < __GMM_MAX_CUBE_FACE; CubeFaceIndex++) { GMM_REQ_OFFSET_INFO OffsetInfo = {}; OffsetInfo.ReqRender = 1; OffsetInfo.CubeFace = static_cast(CubeFaceIndex); ResourceInfo->GetOffset(OffsetInfo); EXPECT_EQ((CubeFaceIndex * ExpectedQPitch) * ExpectedPitch, OffsetInfo.Render.Offset64); // Render offset is tile's base address on which cube face begins. EXPECT_EQ(0, OffsetInfo.Render.XOffset); // X Offset should be 0 as cube face starts on tile boundary EXPECT_EQ(0, OffsetInfo.Render.YOffset); // Y Offset should be 0 as cube face starts on tile boundary EXPECT_EQ(0, OffsetInfo.Render.ZOffset); // Z offset N/A should be 0 } pGmmULTClientContext->DestroyResInfoObject(ResourceInfo); } } } /// @brief ULT for 3D TileYs Compressed Resource TEST_F(CTestGen12dGPUResource, DISABLED_Test3DTileYsCompressedResource) { if(!const_cast(pGfxAdapterInfo->SkuTable).FtrLinearCCS) { return; } // Horizontal/Vertical pixel alignment const uint32_t HAlign[TEST_BPP_MAX] = {64, 32, 32, 32, 16}; const uint32_t VAlign[TEST_BPP_MAX] = {32, 32, 32, 16, 16}; const uint32_t TileSize[TEST_BPP_MAX][3] = {{64, 32, 32}, {64, 32, 32}, {128, 32, 16}, {256, 16, 16}, {256, 16, 16}}; GMM_RESCREATE_PARAMS gmmParams = {}; gmmParams.Type = RESOURCE_3D; gmmParams.NoGfxMemory = 1; gmmParams.Flags.Info.TiledY = 1; gmmParams.Flags.Info.TiledYs = 1; gmmParams.Flags.Gpu.Texture = 1; gmmParams.Flags.Info.RenderCompressed = 1; // Turn on .MC or .RC flag - mandatory to tell compression-type, for Yf its also used to pad surf // to 4x1 tile (reqd by HW for perf reasons) // Allocate 1x1x1 surface for(uint32_t i = 0; i < TEST_BPP_MAX; i++) { // If unifiedAuxSurf reqd (mandatory for displayable or cross-device shared), turn on .CCS/.MMC and .UnifiedAuxSurface too gmmParams.Flags.Gpu.UnifiedAuxSurface = 1; //Turn off for separate aux creation gmmParams.Flags.Gpu.CCS = 1; //Turn off for separate aux creation TEST_BPP bpp = static_cast(i); GMM_TILE_MODE TileMode = DEFINE_TILE(YS_3D, bpp); gmmParams.Format = SetResourceFormat(bpp); gmmParams.BaseWidth64 = 0x1; gmmParams.BaseHeight = 0x1; gmmParams.Depth = 0x1; GMM_RESOURCE_INFO *ResourceInfo; ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); VerifyResourceHAlign(ResourceInfo, HAlign[i]); VerifyResourceVAlign(ResourceInfo, VAlign[i]); VerifyResourcePitch(ResourceInfo, TileSize[i][0]); // As wide as 1 tile VerifyResourcePitchInTiles(ResourceInfo, 1); // 1 tile wide VerifyResourceSize(ResourceInfo, GMM_KBYTE(64)); // 1 tile big VerifyResourceQPitch(ResourceInfo, 0); // Not tested //test main surface base alignment is 16KB //For Yf test main surface pitch is 4-tileYF aligned EXPECT_EQ(GMM_KBYTE(64), ResourceInfo->GetBaseAlignment()); if(const_cast(pGfxAdapterInfo->SkuTable).FtrLinearCCS) { EXPECT_EQ(0, ResourceInfo->GetUnifiedAuxSurfaceOffset(GMM_AUX_CCS) % PAGE_SIZE); EXPECT_GE(ResourceInfo->GetSizeAuxSurface(GMM_AUX_CCS), ResourceInfo->GetSizeMainSurface() >> 8); } EXPECT_EQ(GMM_KBYTE(4), ResourceInfo->GetSizeAuxSurface(GMM_AUX_CCS)); { //separate Aux gmmParams.Flags.Gpu.UnifiedAuxSurface = 0; GMM_RESOURCE_INFO *AuxResourceInfo; AuxResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); EXPECT_EQ(ResourceInfo->GetAuxHAlign(), AuxResourceInfo->GetHAlign()); EXPECT_EQ(ResourceInfo->GetAuxVAlign(), AuxResourceInfo->GetVAlign()); EXPECT_EQ(ResourceInfo->GetUnifiedAuxPitch(), AuxResourceInfo->GetRenderPitch()); EXPECT_EQ(ResourceInfo->GetSizeAuxSurface(GMM_AUX_CCS), AuxResourceInfo->GetSizeSurface()); pGmmULTClientContext->DestroyResInfoObject(AuxResourceInfo); } pGmmULTClientContext->DestroyResInfoObject(ResourceInfo); } // Allocate 2 tiles in X dimension for(uint32_t i = 0; i < TEST_BPP_MAX; i++) { // If unifiedAuxSurf reqd (mandatory for displayable or cross-device shared), turn on .CCS/.MMC and .UnifiedAuxSurface too gmmParams.Flags.Gpu.UnifiedAuxSurface = 1; //Turn off for separate aux creation gmmParams.Flags.Gpu.CCS = 1; //Turn off for separate aux creation TEST_BPP bpp = static_cast(i); GMM_TILE_MODE TileMode = DEFINE_TILE(YS_3D, bpp); gmmParams.Format = SetResourceFormat(bpp); gmmParams.BaseWidth64 = (TileSize[i][0] / GetBppValue(bpp)) + 1; // 1 pixel larger than 1 tile width gmmParams.BaseHeight = 0x1; gmmParams.Depth = 0x1; GMM_RESOURCE_INFO *ResourceInfo; ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); VerifyResourceHAlign(ResourceInfo, HAlign[i]); VerifyResourceVAlign(ResourceInfo, VAlign[i]); VerifyResourcePitch(ResourceInfo, TileSize[i][0] * 2); // As wide as 2 tile VerifyResourcePitchInTiles(ResourceInfo, 2); // 2 tile wide VerifyResourceSize(ResourceInfo, GMM_KBYTE(64) * 2); // 2 tile big VerifyResourceQPitch(ResourceInfo, 0); // Not tested //test main surface base alignment is 16KB //For Yf test main surface pitch is 4-tileYF aligned EXPECT_EQ(GMM_KBYTE(64), ResourceInfo->GetBaseAlignment()); if(const_cast(pGfxAdapterInfo->SkuTable).FtrLinearCCS) { EXPECT_EQ(0, ResourceInfo->GetUnifiedAuxSurfaceOffset(GMM_AUX_CCS) % PAGE_SIZE); EXPECT_GE(ResourceInfo->GetSizeAuxSurface(GMM_AUX_CCS), ResourceInfo->GetSizeMainSurface() >> 8); } EXPECT_EQ(GMM_KBYTE(4), ResourceInfo->GetSizeAuxSurface(GMM_AUX_CCS)); { //separate Aux gmmParams.Flags.Gpu.UnifiedAuxSurface = 0; GMM_RESOURCE_INFO *AuxResourceInfo; AuxResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); EXPECT_EQ(ResourceInfo->GetAuxHAlign(), AuxResourceInfo->GetHAlign()); EXPECT_EQ(ResourceInfo->GetAuxVAlign(), AuxResourceInfo->GetVAlign()); EXPECT_EQ(ResourceInfo->GetUnifiedAuxPitch(), AuxResourceInfo->GetRenderPitch()); EXPECT_EQ(ResourceInfo->GetSizeAuxSurface(GMM_AUX_CCS), AuxResourceInfo->GetSizeSurface()); pGmmULTClientContext->DestroyResInfoObject(AuxResourceInfo); } pGmmULTClientContext->DestroyResInfoObject(ResourceInfo); } // Allocate 2 tiles in X/Y dimension for(uint32_t i = 0; i < TEST_BPP_MAX; i++) { // If unifiedAuxSurf reqd (mandatory for displayable or cross-device shared), turn on .CCS/.MMC and .UnifiedAuxSurface too gmmParams.Flags.Gpu.UnifiedAuxSurface = 1; //Turn off for separate aux creation gmmParams.Flags.Gpu.CCS = 1; //Turn off for separate aux creation TEST_BPP bpp = static_cast(i); GMM_TILE_MODE TileMode = DEFINE_TILE(YS_3D, bpp); gmmParams.Format = SetResourceFormat(bpp); gmmParams.BaseWidth64 = (TileSize[i][0] / GetBppValue(bpp)) + 1; // 1 pixel larger than 1 tile width gmmParams.BaseHeight = TileSize[i][1] + 1; // 1 row larger than 1 tile height gmmParams.Depth = 0x1; GMM_RESOURCE_INFO *ResourceInfo; ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); VerifyResourceHAlign(ResourceInfo, HAlign[i]); VerifyResourceVAlign(ResourceInfo, VAlign[i]); VerifyResourcePitch(ResourceInfo, TileSize[i][0] * 2); // As wide as 2 tile VerifyResourcePitchInTiles(ResourceInfo, 2); // 2 tile wide VerifyResourceSize(ResourceInfo, GMM_KBYTE(64) * 4); // 4 tile big VerifyResourceQPitch(ResourceInfo, 0); //test main surface base alignment is 16KB //For Yf test main surface pitch is 4-tileYF aligned EXPECT_EQ(GMM_KBYTE(64), ResourceInfo->GetBaseAlignment()); if(const_cast(pGfxAdapterInfo->SkuTable).FtrLinearCCS) { EXPECT_EQ(0, ResourceInfo->GetUnifiedAuxSurfaceOffset(GMM_AUX_CCS) % PAGE_SIZE); EXPECT_GE(ResourceInfo->GetSizeAuxSurface(GMM_AUX_CCS), ResourceInfo->GetSizeMainSurface() >> 8); } EXPECT_EQ(GMM_KBYTE(4), ResourceInfo->GetSizeAuxSurface(GMM_AUX_CCS)); { //separate Aux gmmParams.Flags.Gpu.UnifiedAuxSurface = 0; GMM_RESOURCE_INFO *AuxResourceInfo; AuxResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); EXPECT_EQ(ResourceInfo->GetAuxHAlign(), AuxResourceInfo->GetHAlign()); EXPECT_EQ(ResourceInfo->GetAuxVAlign(), AuxResourceInfo->GetVAlign()); EXPECT_EQ(ResourceInfo->GetUnifiedAuxPitch(), AuxResourceInfo->GetRenderPitch()); EXPECT_EQ(ResourceInfo->GetSizeAuxSurface(GMM_AUX_CCS), AuxResourceInfo->GetSizeSurface()); pGmmULTClientContext->DestroyResInfoObject(AuxResourceInfo); } pGmmULTClientContext->DestroyResInfoObject(ResourceInfo); } // Allocate 2 tiles in X/Y/Z dimension for(uint32_t i = 0; i < TEST_BPP_MAX; i++) { // If unifiedAuxSurf reqd (mandatory for displayable or cross-device shared), turn on .CCS/.MMC and .UnifiedAuxSurface too gmmParams.Flags.Gpu.UnifiedAuxSurface = 1; //Turn off for separate aux creation gmmParams.Flags.Gpu.CCS = 1; //Turn off for separate aux creation TEST_BPP bpp = static_cast(i); GMM_TILE_MODE TileMode = DEFINE_TILE(YS_3D, bpp); gmmParams.Format = SetResourceFormat(bpp); gmmParams.BaseWidth64 = (TileSize[i][0] / GetBppValue(bpp)) + 1; // 1 pixel larger than 1 tile width gmmParams.BaseHeight = TileSize[i][1] + 1; // 1 row larger than 1 tile height gmmParams.Depth = TileSize[i][2] + 1; // 1 plane larger than 1 tile depth GMM_RESOURCE_INFO *ResourceInfo; ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); VerifyResourceHAlign(ResourceInfo, HAlign[i]); VerifyResourceVAlign(ResourceInfo, VAlign[i]); VerifyResourcePitch(ResourceInfo, TileSize[i][0] * 2); // As wide as 2 tile VerifyResourcePitchInTiles(ResourceInfo, 2); // 2 tile wide VerifyResourceSize(ResourceInfo, GMM_KBYTE(64) * 8); // 8 tile big VerifyResourceQPitch(ResourceInfo, 0); // Not tested //test main surface base alignment is 16KB //For Yf test main surface pitch is 4-tileYF aligned EXPECT_EQ(GMM_KBYTE(64), ResourceInfo->GetBaseAlignment()); if(const_cast(pGfxAdapterInfo->SkuTable).FtrLinearCCS) { EXPECT_EQ(0, ResourceInfo->GetUnifiedAuxSurfaceOffset(GMM_AUX_CCS) % PAGE_SIZE); EXPECT_GE(ResourceInfo->GetSizeAuxSurface(GMM_AUX_CCS), ResourceInfo->GetSizeMainSurface() >> 8); } EXPECT_EQ(GMM_KBYTE(4), ResourceInfo->GetSizeAuxSurface(GMM_AUX_CCS)); { //separate Aux gmmParams.Flags.Gpu.UnifiedAuxSurface = 0; GMM_RESOURCE_INFO *AuxResourceInfo; AuxResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); EXPECT_EQ(ResourceInfo->GetAuxHAlign(), AuxResourceInfo->GetHAlign()); EXPECT_EQ(ResourceInfo->GetAuxVAlign(), AuxResourceInfo->GetVAlign()); EXPECT_EQ(ResourceInfo->GetUnifiedAuxPitch(), AuxResourceInfo->GetRenderPitch()); EXPECT_EQ(ResourceInfo->GetSizeAuxSurface(GMM_AUX_CCS), AuxResourceInfo->GetSizeSurface()); pGmmULTClientContext->DestroyResInfoObject(AuxResourceInfo); } pGmmULTClientContext->DestroyResInfoObject(ResourceInfo); } } /// @brief ULT for 3D TileYf Compressed Resource TEST_F(CTestGen12dGPUResource, DISABLED_Test3DTileYfCompressedResource) { if(!const_cast(pGfxAdapterInfo->SkuTable).FtrLinearCCS) { return; } // Horizontal/Verticle pixel alignment const uint32_t HAlign[TEST_BPP_MAX] = {16, 8, 8, 8, 4}; const uint32_t VAlign[TEST_BPP_MAX] = {16, 16, 16, 8, 8}; const uint32_t TileSize[TEST_BPP_MAX][3] = {{16, 16, 16}, {16, 16, 16}, {32, 16, 8}, {64, 8, 8}, {64, 8, 8}}; GMM_RESCREATE_PARAMS gmmParams = {}; gmmParams.Type = RESOURCE_3D; gmmParams.NoGfxMemory = 1; gmmParams.Flags.Info.TiledY = 1; gmmParams.Flags.Info.TiledYf = 1; gmmParams.Flags.Gpu.Texture = 1; gmmParams.Flags.Info.RenderCompressed = 1; // Turn on .MC or .RC flag - mandatory to tell compression-type, for Yf its also used to pad surf // to 4x1 tile (reqd by HW for perf reasons) // Allocate 1x1x1 surface for(uint32_t i = 0; i < TEST_BPP_MAX; i++) { // If unifiedAuxSurf reqd (mandatory for displayable or cross-device shared), turn on .CCS/.MMC and .UnifiedAuxSurface too gmmParams.Flags.Gpu.UnifiedAuxSurface = 1; //Turn off for separate aux creation gmmParams.Flags.Gpu.CCS = 1; //Turn off for separate aux creation //gmmParams.Flags.Gpu.MMC = 0; //Turn on to check unifiedaux creation TEST_BPP bpp = static_cast(i); GMM_TILE_MODE TileMode = DEFINE_TILE(YF_3D, bpp); gmmParams.Format = SetResourceFormat(bpp); //gmmParams.BaseWidth64 = 0x30; //gmmParams.BaseHeight = 0x30; //gmmParams.Depth = 0x20; gmmParams.BaseWidth64 = 1; gmmParams.BaseHeight = 1; gmmParams.Depth = 1; const uint32_t PitchAlignment = 32; GMM_RESOURCE_INFO *ResourceInfo; ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); VerifyResourceHAlign(ResourceInfo, HAlign[i]); VerifyResourceVAlign(ResourceInfo, VAlign[i]); VerifyResourcePitch(ResourceInfo, GMM_ULT_ALIGN(gmmParams.BaseWidth64, TileSize[i][0] * 4)); VerifyResourcePitchInTiles(ResourceInfo, GMM_ULT_ALIGN(gmmParams.BaseWidth64, TileSize[i][0] * 4) / TileSize[i][0]); VerifyResourceSize(ResourceInfo, (GMM_ULT_ALIGN(gmmParams.BaseWidth64, TileSize[i][0] * 4) / TileSize[i][0]) * (GMM_ULT_ALIGN(gmmParams.BaseHeight, TileSize[i][1]) / TileSize[i][1]) * (GMM_ULT_ALIGN(gmmParams.Depth, TileSize[i][2]) / TileSize[i][2]) * GMM_KBYTE(4)); VerifyResourceQPitch(ResourceInfo, (GMM_ULT_ALIGN(gmmParams.BaseHeight, TileSize[i][1]))); //test main surface base alignment is 16KB //For Yf test main surface pitch is 4-tileYF aligned EXPECT_EQ(GMM_KBYTE(64), ResourceInfo->GetBaseAlignment()); EXPECT_EQ(0, ResourceInfo->GetRenderPitchTiles() % 4); // Check on YF only if(const_cast(pGfxAdapterInfo->SkuTable).FtrLinearCCS) { EXPECT_EQ(0, ResourceInfo->GetUnifiedAuxSurfaceOffset(GMM_AUX_CCS) % PAGE_SIZE); EXPECT_GE(ResourceInfo->GetSizeAuxSurface(GMM_AUX_CCS), ResourceInfo->GetSizeMainSurface() >> 8); } ASSERT_LE(GMM_ULT_ALIGN(ResourceInfo->GetSizeMainSurface() / (GMM_KBYTE(16) / GMM_BYTES(64)), GMM_KBYTE(4)), ResourceInfo->GetSizeAuxSurface(GMM_AUX_CCS)); { //separate Aux gmmParams.Flags.Gpu.UnifiedAuxSurface = 0; GMM_RESOURCE_INFO *AuxResourceInfo; AuxResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); EXPECT_EQ(ResourceInfo->GetAuxHAlign(), AuxResourceInfo->GetHAlign()); EXPECT_EQ(ResourceInfo->GetAuxVAlign(), AuxResourceInfo->GetVAlign()); EXPECT_EQ(ResourceInfo->GetUnifiedAuxPitch(), AuxResourceInfo->GetRenderPitch()); EXPECT_EQ(ResourceInfo->GetSizeAuxSurface(GMM_AUX_CCS), AuxResourceInfo->GetSizeSurface()); pGmmULTClientContext->DestroyResInfoObject(AuxResourceInfo); } pGmmULTClientContext->DestroyResInfoObject(ResourceInfo); } // Allocate 2 tiles in X dimension for(uint32_t i = 0; i < TEST_BPP_MAX; i++) { // If unifiedAuxSurf reqd (mandatory for displayable or cross-device shared), turn on .CCS/.MMC and .UnifiedAuxSurface too gmmParams.Flags.Gpu.UnifiedAuxSurface = 1; //Turn off for separate aux creation gmmParams.Flags.Gpu.CCS = 1; //Turn off for separate aux creation TEST_BPP bpp = static_cast(i); GMM_TILE_MODE TileMode = DEFINE_TILE(YF_3D, bpp); gmmParams.Format = SetResourceFormat(bpp); gmmParams.BaseWidth64 = (TileSize[i][0] / GetBppValue(bpp)) + 1; gmmParams.BaseHeight = 0x1; gmmParams.Depth = 0x1; const uint32_t PitchAlignment = 32; GMM_RESOURCE_INFO *ResourceInfo; ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); VerifyResourceHAlign(ResourceInfo, HAlign[i]); VerifyResourceVAlign(ResourceInfo, VAlign[i]); VerifyResourcePitch(ResourceInfo, GMM_ULT_ALIGN(TileSize[i][0] * 4, PitchAlignment)); VerifyResourcePitchInTiles(ResourceInfo, GMM_ULT_ALIGN(TileSize[i][0] * 4, PitchAlignment) / TileSize[i][0]); VerifyResourceSize(ResourceInfo, GMM_ULT_ALIGN(TileSize[i][0] * 4, PitchAlignment) / TileSize[i][0] * GMM_KBYTE(4)); VerifyResourceQPitch(ResourceInfo, TileSize[i][1]); //test main surface base alignment is 16KB //For Yf test main surface pitch is 4-tileYF aligned EXPECT_EQ(GMM_KBYTE(64), ResourceInfo->GetBaseAlignment()); EXPECT_EQ(0, ResourceInfo->GetRenderPitchTiles() % 4); // Check on YF only if(const_cast(pGfxAdapterInfo->SkuTable).FtrLinearCCS) { EXPECT_EQ(0, ResourceInfo->GetUnifiedAuxSurfaceOffset(GMM_AUX_CCS) % PAGE_SIZE); EXPECT_GE(ResourceInfo->GetSizeAuxSurface(GMM_AUX_CCS), ResourceInfo->GetSizeMainSurface() >> 8); } EXPECT_EQ(GMM_KBYTE(4), ResourceInfo->GetSizeAuxSurface(GMM_AUX_CCS)); ASSERT_LE(GMM_ULT_ALIGN(ResourceInfo->GetSizeMainSurface() / (GMM_KBYTE(16) / GMM_BYTES(64)), GMM_KBYTE(4)), ResourceInfo->GetSizeAuxSurface(GMM_AUX_CCS)); { //separate Aux gmmParams.Flags.Gpu.UnifiedAuxSurface = 0; GMM_RESOURCE_INFO *AuxResourceInfo; AuxResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); EXPECT_EQ(ResourceInfo->GetAuxHAlign(), AuxResourceInfo->GetHAlign()); EXPECT_EQ(ResourceInfo->GetAuxVAlign(), AuxResourceInfo->GetVAlign()); EXPECT_EQ(ResourceInfo->GetUnifiedAuxPitch(), AuxResourceInfo->GetRenderPitch()); EXPECT_EQ(ResourceInfo->GetSizeAuxSurface(GMM_AUX_CCS), AuxResourceInfo->GetSizeSurface()); pGmmULTClientContext->DestroyResInfoObject(AuxResourceInfo); } pGmmULTClientContext->DestroyResInfoObject(ResourceInfo); } // Allocate 2 tiles in X/Y dimension for(uint32_t i = 0; i < TEST_BPP_MAX; i++) { // If unifiedAuxSurf reqd (mandatory for displayable or cross-device shared), turn on .CCS/.MMC and .UnifiedAuxSurface too gmmParams.Flags.Gpu.UnifiedAuxSurface = 1; //Turn off for separate aux creation gmmParams.Flags.Gpu.CCS = 1; //Turn off for separate aux creation TEST_BPP bpp = static_cast(i); GMM_TILE_MODE TileMode = DEFINE_TILE(YF_3D, bpp); gmmParams.Format = SetResourceFormat(bpp); gmmParams.BaseWidth64 = (TileSize[i][0] / GetBppValue(bpp)) + 1; gmmParams.BaseHeight = TileSize[i][1] + 1; gmmParams.Depth = 0x1; const uint32_t PitchAlignment = 32; GMM_RESOURCE_INFO *ResourceInfo; ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); VerifyResourceHAlign(ResourceInfo, HAlign[i]); VerifyResourceVAlign(ResourceInfo, VAlign[i]); VerifyResourcePitch(ResourceInfo, GMM_ULT_ALIGN(TileSize[i][0] * 4, PitchAlignment)); VerifyResourcePitchInTiles(ResourceInfo, GMM_ULT_ALIGN(TileSize[i][0] * 4, PitchAlignment) / TileSize[i][0]); VerifyResourceSize(ResourceInfo, GMM_ULT_ALIGN(TileSize[i][0] * 4, PitchAlignment) / TileSize[i][0] * 2 * GMM_KBYTE(4)); VerifyResourceQPitch(ResourceInfo, TileSize[i][1] * 2); //test main surface base alignment is 16KB //For Yf test main surface pitch is 4-tileYF aligned EXPECT_EQ(GMM_KBYTE(64), ResourceInfo->GetBaseAlignment()); EXPECT_EQ(0, ResourceInfo->GetRenderPitchTiles() % 4); // Check on YF only if(const_cast(pGfxAdapterInfo->SkuTable).FtrLinearCCS) { EXPECT_EQ(0, ResourceInfo->GetUnifiedAuxSurfaceOffset(GMM_AUX_CCS) % PAGE_SIZE); EXPECT_GE(ResourceInfo->GetSizeAuxSurface(GMM_AUX_CCS), ResourceInfo->GetSizeMainSurface() >> 8); } EXPECT_EQ(GMM_KBYTE(4), ResourceInfo->GetSizeAuxSurface(GMM_AUX_CCS)); ASSERT_LE(GMM_ULT_ALIGN(ResourceInfo->GetSizeMainSurface() / (GMM_KBYTE(16) / GMM_BYTES(64)), GMM_KBYTE(4)), ResourceInfo->GetSizeAuxSurface(GMM_AUX_CCS)); { //separate Aux gmmParams.Flags.Gpu.UnifiedAuxSurface = 0; GMM_RESOURCE_INFO *AuxResourceInfo; AuxResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); EXPECT_EQ(ResourceInfo->GetAuxHAlign(), AuxResourceInfo->GetHAlign()); EXPECT_EQ(ResourceInfo->GetAuxVAlign(), AuxResourceInfo->GetVAlign()); EXPECT_EQ(ResourceInfo->GetUnifiedAuxPitch(), AuxResourceInfo->GetRenderPitch()); EXPECT_EQ(ResourceInfo->GetSizeAuxSurface(GMM_AUX_CCS), AuxResourceInfo->GetSizeSurface()); pGmmULTClientContext->DestroyResInfoObject(AuxResourceInfo); } pGmmULTClientContext->DestroyResInfoObject(ResourceInfo); } // Allocate 2 tiles in X/Y/Z dimension for(uint32_t i = 0; i < TEST_BPP_MAX; i++) { // If unifiedAuxSurf reqd (mandatory for displayable or cross-device shared), turn on .CCS/.MMC and .UnifiedAuxSurface too gmmParams.Flags.Gpu.UnifiedAuxSurface = 1; //Turn off for separate aux creation gmmParams.Flags.Gpu.CCS = 1; //Turn off for separate aux creation TEST_BPP bpp = static_cast(i); GMM_TILE_MODE TileMode = DEFINE_TILE(YF_3D, bpp); gmmParams.Format = SetResourceFormat(bpp); gmmParams.BaseWidth64 = (TileSize[i][0] / GetBppValue(bpp)) + 1; gmmParams.BaseHeight = TileSize[i][1] + 1; gmmParams.Depth = TileSize[i][2] + 1; const uint32_t PitchAlignment = 32; GMM_RESOURCE_INFO *ResourceInfo; ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); VerifyResourceHAlign(ResourceInfo, HAlign[i]); VerifyResourceVAlign(ResourceInfo, VAlign[i]); VerifyResourcePitch(ResourceInfo, GMM_ULT_ALIGN(TileSize[i][0] * 4, PitchAlignment)); VerifyResourcePitchInTiles(ResourceInfo, GMM_ULT_ALIGN(TileSize[i][0] * 4, PitchAlignment) / TileSize[i][0]); VerifyResourceSize(ResourceInfo, GMM_ULT_ALIGN(TileSize[i][0] * 4, PitchAlignment) / TileSize[i][0] * 2 * 2 * GMM_KBYTE(4)); VerifyResourceQPitch(ResourceInfo, TileSize[i][1] * 2); //test main surface base alignment is 16KB //For Yf test main surface pitch is 4-tileYF aligned EXPECT_EQ(GMM_KBYTE(64), ResourceInfo->GetBaseAlignment()); EXPECT_EQ(0, ResourceInfo->GetRenderPitchTiles() % 4); // Check on YF only if(const_cast(pGfxAdapterInfo->SkuTable).FtrLinearCCS) { EXPECT_EQ(0, ResourceInfo->GetUnifiedAuxSurfaceOffset(GMM_AUX_CCS) % PAGE_SIZE); EXPECT_GE(ResourceInfo->GetSizeAuxSurface(GMM_AUX_CCS), ResourceInfo->GetSizeMainSurface() >> 8); } EXPECT_EQ(GMM_KBYTE(4), ResourceInfo->GetSizeAuxSurface(GMM_AUX_CCS)); ASSERT_LE(GMM_ULT_ALIGN(ResourceInfo->GetSizeMainSurface() / (GMM_KBYTE(16) / GMM_BYTES(64)), GMM_KBYTE(4)), ResourceInfo->GetSizeAuxSurface(GMM_AUX_CCS)); { //separate Aux gmmParams.Flags.Gpu.UnifiedAuxSurface = 0; GMM_RESOURCE_INFO *AuxResourceInfo; AuxResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); EXPECT_EQ(ResourceInfo->GetAuxHAlign(), AuxResourceInfo->GetHAlign()); EXPECT_EQ(ResourceInfo->GetAuxVAlign(), AuxResourceInfo->GetVAlign()); EXPECT_EQ(ResourceInfo->GetUnifiedAuxPitch(), AuxResourceInfo->GetRenderPitch()); EXPECT_EQ(ResourceInfo->GetSizeAuxSurface(GMM_AUX_CCS), AuxResourceInfo->GetSizeSurface()); pGmmULTClientContext->DestroyResInfoObject(AuxResourceInfo); } pGmmULTClientContext->DestroyResInfoObject(ResourceInfo); } } /// @brief ULT for 3D TileY Compressed Resource TEST_F(CTestGen12dGPUResource, DISABLED_Test3DTileYCompressedResource) { if(!const_cast(pGfxAdapterInfo->SkuTable).FtrLinearCCS) { return; } // Horizontal/Verticle pixel alignment const uint32_t HAlign = {16}; const uint32_t VAlign = {4}; const uint32_t TileSize[3] = {128, 32, 1}; GMM_RESCREATE_PARAMS gmmParams = {}; gmmParams.Type = RESOURCE_3D; gmmParams.NoGfxMemory = 1; gmmParams.Flags.Info.TiledY = 1; gmmParams.Flags.Gpu.Texture = 1; gmmParams.Flags.Info.RenderCompressed = 1; // Turn on .MC or .RC flag - mandatory to tell compression-type, for Yf its also used to pad surf // to 4x1 tile (reqd by HW for perf reasons) // Allocate 1x1x1 surface for(uint32_t i = 0; i < TEST_BPP_MAX; i++) { // If unifiedAuxSurf reqd (mandatory for displayable or cross-device shared), turn on .CCS/.MMC and .UnifiedAuxSurface too gmmParams.Flags.Gpu.UnifiedAuxSurface = 1; //Turn off for separate aux creation gmmParams.Flags.Gpu.CCS = 1; //Turn off for separate aux creation TEST_BPP bpp = static_cast(i); GMM_TILE_MODE TileMode = LEGACY_TILE_Y; gmmParams.Format = SetResourceFormat(bpp); //gmmParams.BaseWidth64 = 0x30; //gmmParams.BaseHeight = 0x30; //gmmParams.Depth = 0x20; gmmParams.BaseWidth64 = 1; gmmParams.BaseHeight = 1; gmmParams.Depth = 1; const uint32_t PitchAlignment = 32; GMM_RESOURCE_INFO *ResourceInfo; ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); VerifyResourceHAlign(ResourceInfo, HAlign); VerifyResourceVAlign(ResourceInfo, VAlign); VerifyResourcePitch(ResourceInfo, GMM_ULT_ALIGN(gmmParams.BaseWidth64, TileSize[0] * 4)); VerifyResourcePitchInTiles(ResourceInfo, GMM_ULT_ALIGN(gmmParams.BaseWidth64, TileSize[0] * 4) / TileSize[0]); VerifyResourceSize(ResourceInfo, (GMM_ULT_ALIGN(gmmParams.BaseWidth64, TileSize[0] * 4) / TileSize[0]) * (GMM_ULT_ALIGN(gmmParams.BaseHeight, TileSize[1]) / TileSize[1]) * (GMM_ULT_ALIGN(gmmParams.Depth, TileSize[2]) / TileSize[2]) * GMM_KBYTE(4)); VerifyResourceQPitch(ResourceInfo, (GMM_ULT_ALIGN(gmmParams.BaseHeight, TileSize[1]))); //test main surface base alignment is 16KB //For Yf test main surface pitch is 4-tileYF aligned EXPECT_EQ(GMM_KBYTE(64), ResourceInfo->GetBaseAlignment()); EXPECT_EQ(0, ResourceInfo->GetRenderPitchTiles() % 4); // Check on YF only EXPECT_EQ(0, ResourceInfo->GetUnifiedAuxSurfaceOffset(GMM_AUX_CCS) % PAGE_SIZE); ASSERT_LE(GMM_ULT_ALIGN(ResourceInfo->GetSizeMainSurface() / (GMM_KBYTE(16) / GMM_BYTES(64)), GMM_KBYTE(4)), ResourceInfo->GetSizeAuxSurface(GMM_AUX_CCS)); { //separate Aux gmmParams.Flags.Gpu.UnifiedAuxSurface = 0; GMM_RESOURCE_INFO *AuxResourceInfo; AuxResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); EXPECT_EQ(ResourceInfo->GetAuxHAlign(), AuxResourceInfo->GetHAlign()); EXPECT_EQ(ResourceInfo->GetAuxVAlign(), AuxResourceInfo->GetVAlign()); EXPECT_EQ(ResourceInfo->GetUnifiedAuxPitch(), AuxResourceInfo->GetRenderPitch()); EXPECT_EQ(ResourceInfo->GetSizeAuxSurface(GMM_AUX_CCS), AuxResourceInfo->GetSizeSurface()); pGmmULTClientContext->DestroyResInfoObject(AuxResourceInfo); } pGmmULTClientContext->DestroyResInfoObject(ResourceInfo); } // Allocate 2 tiles in X dimension for(uint32_t i = 0; i < TEST_BPP_MAX; i++) { // If unifiedAuxSurf reqd (mandatory for displayable or cross-device shared), turn on .CCS/.MMC and .UnifiedAuxSurface too gmmParams.Flags.Gpu.UnifiedAuxSurface = 1; //Turn off for separate aux creation gmmParams.Flags.Gpu.CCS = 1; //Turn off for separate aux creation TEST_BPP bpp = static_cast(i); GMM_TILE_MODE TileMode = LEGACY_TILE_Y; gmmParams.Format = SetResourceFormat(bpp); gmmParams.BaseWidth64 = (TileSize[0] / GetBppValue(bpp)) + 1; gmmParams.BaseHeight = 0x1; gmmParams.Depth = 0x1; const uint32_t PitchAlignment = 32; GMM_RESOURCE_INFO *ResourceInfo; ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); VerifyResourceHAlign(ResourceInfo, HAlign); VerifyResourceVAlign(ResourceInfo, VAlign); VerifyResourcePitch(ResourceInfo, GMM_ULT_ALIGN(TileSize[0] * 4, PitchAlignment)); VerifyResourcePitchInTiles(ResourceInfo, GMM_ULT_ALIGN(TileSize[0] * 4, PitchAlignment) / TileSize[0]); VerifyResourceSize(ResourceInfo, GMM_ULT_ALIGN(TileSize[0] * 4, PitchAlignment) / TileSize[0] * GMM_KBYTE(4)); VerifyResourceQPitch(ResourceInfo, TileSize[1]); //test main surface base alignment is 16KB //For Yf test main surface pitch is 4-tileYF aligned EXPECT_EQ(GMM_KBYTE(64), ResourceInfo->GetBaseAlignment()); EXPECT_EQ(0, ResourceInfo->GetRenderPitchTiles() % 4); // Check on YF only EXPECT_EQ(GMM_KBYTE(4), ResourceInfo->GetSizeAuxSurface(GMM_AUX_CCS)); ASSERT_LE(GMM_ULT_ALIGN(ResourceInfo->GetSizeMainSurface() / (GMM_KBYTE(16) / GMM_BYTES(64)), GMM_KBYTE(4)), ResourceInfo->GetSizeAuxSurface(GMM_AUX_CCS)); { //separate Aux gmmParams.Flags.Gpu.UnifiedAuxSurface = 0; GMM_RESOURCE_INFO *AuxResourceInfo; AuxResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); EXPECT_EQ(ResourceInfo->GetAuxHAlign(), AuxResourceInfo->GetHAlign()); EXPECT_EQ(ResourceInfo->GetAuxVAlign(), AuxResourceInfo->GetVAlign()); EXPECT_EQ(ResourceInfo->GetUnifiedAuxPitch(), AuxResourceInfo->GetRenderPitch()); EXPECT_EQ(ResourceInfo->GetSizeAuxSurface(GMM_AUX_CCS), AuxResourceInfo->GetSizeSurface()); pGmmULTClientContext->DestroyResInfoObject(AuxResourceInfo); } pGmmULTClientContext->DestroyResInfoObject(ResourceInfo); } // Allocate 2 tiles in X/Y dimension for(uint32_t i = 0; i < TEST_BPP_MAX; i++) { // If unifiedAuxSurf reqd (mandatory for displayable or cross-device shared), turn on .CCS/.MMC and .UnifiedAuxSurface too gmmParams.Flags.Gpu.UnifiedAuxSurface = 1; //Turn off for separate aux creation gmmParams.Flags.Gpu.CCS = 1; //Turn off for separate aux creation TEST_BPP bpp = static_cast(i); GMM_TILE_MODE TileMode = LEGACY_TILE_Y; gmmParams.Format = SetResourceFormat(bpp); gmmParams.BaseWidth64 = (TileSize[0] / GetBppValue(bpp)) + 1; gmmParams.BaseHeight = TileSize[1] + 1; gmmParams.Depth = 0x1; const uint32_t PitchAlignment = 32; GMM_RESOURCE_INFO *ResourceInfo; ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); VerifyResourceHAlign(ResourceInfo, HAlign); VerifyResourceVAlign(ResourceInfo, VAlign); VerifyResourcePitch(ResourceInfo, GMM_ULT_ALIGN(TileSize[0] * 4, PitchAlignment)); VerifyResourcePitchInTiles(ResourceInfo, GMM_ULT_ALIGN(TileSize[0] * 4, PitchAlignment) / TileSize[0]); VerifyResourceSize(ResourceInfo, GMM_ULT_ALIGN(TileSize[0] * 4, PitchAlignment) / TileSize[0] * 2 * GMM_KBYTE(4)); VerifyResourceQPitch(ResourceInfo, TileSize[1] * 2); //test main surface base alignment is 16KB //For Yf test main surface pitch is 4-tileYF aligned EXPECT_EQ(GMM_KBYTE(64), ResourceInfo->GetBaseAlignment()); EXPECT_EQ(0, ResourceInfo->GetRenderPitchTiles() % 4); // Check on YF only EXPECT_EQ(0, ResourceInfo->GetUnifiedAuxSurfaceOffset(GMM_AUX_CCS) % PAGE_SIZE); EXPECT_EQ(GMM_KBYTE(4), ResourceInfo->GetSizeAuxSurface(GMM_AUX_CCS)); ASSERT_LE(GMM_ULT_ALIGN(ResourceInfo->GetSizeMainSurface() / (GMM_KBYTE(16) / GMM_BYTES(64)), GMM_KBYTE(4)), ResourceInfo->GetSizeAuxSurface(GMM_AUX_CCS)); { //separate Aux gmmParams.Flags.Gpu.UnifiedAuxSurface = 0; GMM_RESOURCE_INFO *AuxResourceInfo; AuxResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); EXPECT_EQ(ResourceInfo->GetAuxHAlign(), AuxResourceInfo->GetHAlign()); EXPECT_EQ(ResourceInfo->GetAuxVAlign(), AuxResourceInfo->GetVAlign()); EXPECT_EQ(ResourceInfo->GetUnifiedAuxPitch(), AuxResourceInfo->GetRenderPitch()); EXPECT_EQ(ResourceInfo->GetSizeAuxSurface(GMM_AUX_CCS), AuxResourceInfo->GetSizeSurface()); pGmmULTClientContext->DestroyResInfoObject(AuxResourceInfo); } pGmmULTClientContext->DestroyResInfoObject(ResourceInfo); } // Allocate 2 tiles in X/Y/Z dimension for(uint32_t i = 0; i < TEST_BPP_MAX; i++) { // If unifiedAuxSurf reqd (mandatory for displayable or cross-device shared), turn on .CCS/.MMC and .UnifiedAuxSurface too gmmParams.Flags.Gpu.UnifiedAuxSurface = 1; //Turn off for separate aux creation gmmParams.Flags.Gpu.CCS = 1; //Turn off for separate aux creation TEST_BPP bpp = static_cast(i); GMM_TILE_MODE TileMode = LEGACY_TILE_Y; gmmParams.Format = SetResourceFormat(bpp); gmmParams.BaseWidth64 = (TileSize[0] / GetBppValue(bpp)) + 1; gmmParams.BaseHeight = TileSize[1] + 1; gmmParams.Depth = TileSize[2] + 1; const uint32_t PitchAlignment = 32; GMM_RESOURCE_INFO *ResourceInfo; ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); VerifyResourceHAlign(ResourceInfo, HAlign); VerifyResourceVAlign(ResourceInfo, VAlign); VerifyResourcePitch(ResourceInfo, GMM_ULT_ALIGN(TileSize[0] * 4, PitchAlignment)); VerifyResourcePitchInTiles(ResourceInfo, GMM_ULT_ALIGN(TileSize[0] * 4, PitchAlignment) / TileSize[0]); VerifyResourceSize(ResourceInfo, GMM_ULT_ALIGN(TileSize[0] * 4, PitchAlignment) / TileSize[0] * 2 * 2 * GMM_KBYTE(4)); VerifyResourceQPitch(ResourceInfo, TileSize[1] * 2); //test main surface base alignment is 16KB //For Yf test main surface pitch is 4-tileYF aligned EXPECT_EQ(GMM_KBYTE(64), ResourceInfo->GetBaseAlignment()); EXPECT_EQ(0, ResourceInfo->GetRenderPitchTiles() % 4); // Check on YF only EXPECT_EQ(0, ResourceInfo->GetUnifiedAuxSurfaceOffset(GMM_AUX_CCS) % PAGE_SIZE); EXPECT_EQ(GMM_KBYTE(4), ResourceInfo->GetSizeAuxSurface(GMM_AUX_CCS)); ASSERT_LE(GMM_ULT_ALIGN(ResourceInfo->GetSizeMainSurface() / (GMM_KBYTE(16) / GMM_BYTES(64)), GMM_KBYTE(4)), ResourceInfo->GetSizeAuxSurface(GMM_AUX_CCS)); { //separate Aux gmmParams.Flags.Gpu.UnifiedAuxSurface = 0; GMM_RESOURCE_INFO *AuxResourceInfo; AuxResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); EXPECT_EQ(ResourceInfo->GetAuxHAlign(), AuxResourceInfo->GetHAlign()); EXPECT_EQ(ResourceInfo->GetAuxVAlign(), AuxResourceInfo->GetVAlign()); EXPECT_EQ(ResourceInfo->GetUnifiedAuxPitch(), AuxResourceInfo->GetRenderPitch()); EXPECT_EQ(ResourceInfo->GetSizeAuxSurface(GMM_AUX_CCS), AuxResourceInfo->GetSizeSurface()); pGmmULTClientContext->DestroyResInfoObject(AuxResourceInfo); } pGmmULTClientContext->DestroyResInfoObject(ResourceInfo); } } /// @brief ULT for 2D Yf mipped compressed resource TEST_F(CTestGen12dGPUResource, DISABLED_Test2DTileYfMippedCompressedResource) { if(!const_cast(pGfxAdapterInfo->SkuTable).FtrLinearCCS) { return; } const uint32_t HAlign[TEST_BPP_MAX] = {64, 64, 32, 32, 16}; const uint32_t VAlign[TEST_BPP_MAX] = {64, 32, 32, 16, 16}; const uint32_t TileSize[TEST_BPP_MAX][2] = {{64, 64}, {128, 32}, {128, 32}, {256, 16}, {256, 16}}; const uint32_t MtsWidth[TEST_BPP_MAX] = {32, 32, 16, 16, 8}; const uint32_t MtsHeight[TEST_BPP_MAX] = {64, 32, 32, 16, 16}; GMM_RESCREATE_PARAMS gmmParams = {}; gmmParams.Type = RESOURCE_2D; gmmParams.NoGfxMemory = 1; gmmParams.Flags.Info.TiledY = 1; gmmParams.Flags.Info.TiledYf = 1; gmmParams.Flags.Gpu.Texture = 1; gmmParams.Flags.Info.RenderCompressed = 1; // Turn on .MC or .RC flag - mandatory to tell compression-type, for Yf its also used to pad surf // to 4x1 tile (reqd by HW for perf reasons) gmmParams.MaxLod = 4; gmmParams.ArraySize = 4; for(uint32_t i = 0; i < TEST_BPP_MAX; i++) { uint32_t AlignedWidth = 0; uint32_t AlignedHeight = 0; uint32_t ExpectedPitch = 0; uint32_t MipTailStartLod = 0; // Valigned Mip Heights uint32_t Mip0Height = 0; uint32_t Mip1Height = 0; uint32_t Mip2Height = 0; uint32_t Mip3Height = 0; uint32_t Mip2Higher = 0; // Sum of aligned heights of Mip2 and above uint32_t MipTailHeight = 0; // Haligned Mip Widths uint32_t Mip0Width = 0; uint32_t Mip1Width = 0; uint32_t Mip2Width = 0; TEST_BPP bpp = static_cast(i); gmmParams.Format = SetResourceFormat(bpp); gmmParams.BaseWidth64 = 0x38; gmmParams.BaseHeight = 0x38; // If unifiedAuxSurf reqd (mandatory for displayable or cross-device shared), turn on .CCS/.MMC and .UnifiedAuxSurface too gmmParams.Flags.Gpu.UnifiedAuxSurface = 1; //Turn off for separate aux creation gmmParams.Flags.Gpu.CCS = 1; //Turn off for separate aux creation GMM_RESOURCE_INFO *ResourceInfo; ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); VerifyResourceHAlign(ResourceInfo, HAlign[i]); VerifyResourceVAlign(ResourceInfo, VAlign[i]); // find the miptail start level { uint32_t MipWidth = gmmParams.BaseWidth64; uint32_t MipHeight = gmmParams.BaseHeight; while(!(MipWidth <= MtsWidth[i] && MipHeight <= MtsHeight[i])) { MipTailStartLod++; MipWidth = (uint32_t)(GMM_ULT_MAX(1, gmmParams.BaseWidth64 >> MipTailStartLod)); MipHeight = GMM_ULT_MAX(1, gmmParams.BaseHeight >> MipTailStartLod); } } // Mip resource Aligned Width calculation Mip0Width = GMM_ULT_ALIGN(gmmParams.BaseWidth64, HAlign[i]); Mip0Height = GMM_ULT_ALIGN(gmmParams.BaseHeight, VAlign[i]); if(MipTailStartLod == 1) { EXPECT_EQ(1, ResourceInfo->GetPackedMipTailStartLod()); // Block height...Mip0Height + Max(Mip1Height, Sum of Mip2Height..MipnHeight) Mip1Height = GMM_ULT_ALIGN(gmmParams.BaseHeight >> 1, VAlign[i]); AlignedWidth = Mip0Width; } if(MipTailStartLod == 2) { EXPECT_EQ(2, ResourceInfo->GetPackedMipTailStartLod()); // Block height...Mip0Height + Max(Mip1Height, Sum of Mip2Height..MipnHeight) Mip1Height = GMM_ULT_ALIGN(gmmParams.BaseHeight >> 1, VAlign[i]); Mip2Height = Mip2Higher = GMM_ULT_ALIGN(gmmParams.BaseHeight >> 2, VAlign[i]); Mip1Width = GMM_ULT_ALIGN(gmmParams.BaseWidth64 >> 1, HAlign[i]); Mip2Width = GMM_ULT_ALIGN(gmmParams.BaseWidth64 >> 2, HAlign[i]); AlignedWidth = GMM_ULT_MAX(Mip0Width, Mip1Width + Mip2Width); } if(MipTailStartLod == 3) { EXPECT_EQ(3, ResourceInfo->GetPackedMipTailStartLod()); // Block height...Mip0Height + Max(Mip1Height, Sum of Mip2Height..MipnHeight) Mip1Height = GMM_ULT_ALIGN(gmmParams.BaseHeight >> 1, VAlign[i]); Mip2Height = GMM_ULT_ALIGN(gmmParams.BaseHeight >> 2, VAlign[i]); // Miptail started lod MipTailHeight = VAlign[i]; Mip2Higher = Mip2Height + Mip3Height + MipTailHeight; Mip1Width = GMM_ULT_ALIGN(gmmParams.BaseWidth64 >> 1, HAlign[i]); Mip2Width = GMM_ULT_ALIGN(gmmParams.BaseWidth64 >> 2, HAlign[i]); AlignedWidth = GMM_ULT_MAX(Mip0Width, Mip1Width + Mip2Width); } uint32_t MaxHeight = GMM_ULT_MAX(Mip1Height, Mip2Higher); AlignedHeight = Mip0Height + MaxHeight; AlignedHeight = GMM_ULT_ALIGN(AlignedHeight, VAlign[i]); ExpectedPitch = AlignedWidth * GetBppValue(bpp); ExpectedPitch = GMM_ULT_ALIGN(ExpectedPitch, GMM_BYTES(32)); ExpectedPitch = GMM_ULT_ALIGN(ExpectedPitch, TileSize[i][0] * 4); //Only for displayables - 16K pitch align VerifyResourcePitch(ResourceInfo, ExpectedPitch); VerifyResourcePitchInTiles(ResourceInfo, static_cast(ExpectedPitch / TileSize[i][0])); VerifyResourceSize(ResourceInfo, GMM_ULT_ALIGN(ExpectedPitch * AlignedHeight * gmmParams.ArraySize, PAGE_SIZE)); VerifyResourceQPitch(ResourceInfo, AlignedHeight); //test main surface base alignment is 16KB //For Yf test main surface pitch is 4-tileYF aligned EXPECT_EQ(GMM_KBYTE(64), ResourceInfo->GetBaseAlignment()); EXPECT_EQ(0, ResourceInfo->GetRenderPitchTiles() % 4); // Check on YF only //Aux-size enough to cover all if(const_cast(pGfxAdapterInfo->SkuTable).FtrLinearCCS) { EXPECT_EQ(0, ResourceInfo->GetUnifiedAuxSurfaceOffset(GMM_AUX_CCS) % PAGE_SIZE); } EXPECT_EQ(GMM_KBYTE(4), ResourceInfo->GetSizeAuxSurface(GMM_AUX_CCS)); ASSERT_LE(GMM_ULT_ALIGN(ResourceInfo->GetSizeMainSurface() / (GMM_KBYTE(16) / GMM_BYTES(64)), GMM_KBYTE(4)), ResourceInfo->GetSizeAuxSurface(GMM_AUX_CCS)); pGmmULTClientContext->DestroyResInfoObject(ResourceInfo); } } /// @brief ULT for Linear Buffer Compressed Resource TEST_F(CTestGen12dGPUResource, DISABLED_TestLinearCompressedResource) { // Horizontal pixel alignment const uint32_t MinPitch = 32; GMM_RESCREATE_PARAMS gmmParams = {}; gmmParams.Type = RESOURCE_BUFFER; gmmParams.NoGfxMemory = 1; gmmParams.Flags.Info.Linear = 1; gmmParams.Flags.Gpu.Texture = 1; gmmParams.Flags.Info.RenderCompressed = 1; // Allocate 1x1 surface for(uint32_t i = 0; i < TEST_BPP_MAX; i++) { gmmParams.Flags.Gpu.UnifiedAuxSurface = 1; //Turn off for separate aux creation gmmParams.Flags.Gpu.CCS = 1; //Turn off for separate aux creation TEST_BPP bpp = static_cast(i); gmmParams.Format = SetResourceFormat(bpp); gmmParams.BaseWidth64 = 0x1; gmmParams.BaseHeight = 1; gmmParams.Flags.Info.AllowVirtualPadding = (bpp != TEST_BPP_8); //OCL uses 8bpp buffers. Specification doesn't comment if Linear buffer compr allowed or not on bpp!=8. GMM_RESOURCE_INFO *ResourceInfo; ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); uint32_t AlignedWidth = GMM_ULT_ALIGN(gmmParams.BaseWidth64, MinPitch); uint32_t PitchInBytes = AlignedWidth * GetBppValue(bpp); uint32_t AlignedSize = GMM_ULT_ALIGN(PitchInBytes, PAGE_SIZE); VerifyResourceHAlign(ResourceInfo, 0); VerifyResourceVAlign(ResourceInfo, 0); // N/A for buffer VerifyResourcePitch(ResourceInfo, 0); // N/A for buffer VerifyResourcePitchInTiles(ResourceInfo, 0); // N/A for linear VerifyResourceSize(ResourceInfo, AlignedSize); VerifyResourceQPitch(ResourceInfo, 0); // N/A for non-arrayed //test main surface base alignment is 16KB EXPECT_EQ(GMM_KBYTE(64), ResourceInfo->GetBaseAlignment()); EXPECT_EQ(0, ResourceInfo->GetUnifiedAuxSurfaceOffset(GMM_AUX_CCS) % PAGE_SIZE); ASSERT_LE(GMM_ULT_ALIGN(ResourceInfo->GetSizeMainSurface() / (GMM_KBYTE(16) / GMM_BYTES(64)), GMM_KBYTE(4)), ResourceInfo->GetSizeAuxSurface(GMM_AUX_CCS)); { //separate Aux gmmParams.Flags.Gpu.UnifiedAuxSurface = 0; GMM_RESOURCE_INFO *AuxResourceInfo; AuxResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); EXPECT_EQ(ResourceInfo->GetAuxHAlign(), AuxResourceInfo->GetHAlign()); EXPECT_EQ(ResourceInfo->GetAuxVAlign(), AuxResourceInfo->GetVAlign()); EXPECT_EQ(ResourceInfo->GetUnifiedAuxPitch(), AuxResourceInfo->GetRenderPitch()); EXPECT_EQ(ResourceInfo->GetSizeAuxSurface(GMM_AUX_CCS), AuxResourceInfo->GetSizeSurface()); pGmmULTClientContext->DestroyResInfoObject(AuxResourceInfo); } pGmmULTClientContext->DestroyResInfoObject(ResourceInfo); } // Allocate more than 1 page for(uint32_t i = 0; i < TEST_BPP_MAX; i++) { TEST_BPP bpp = static_cast(i); gmmParams.Format = SetResourceFormat(bpp); gmmParams.BaseWidth64 = 0x1001; gmmParams.BaseHeight = 1; gmmParams.Flags.Info.AllowVirtualPadding = (bpp != TEST_BPP_8); //OCL uses 8bpp buffers. Specification doesn't comment if Linear buffer compr allowed or not on bpp!=8. gmmParams.Flags.Gpu.UnifiedAuxSurface = 1; //Turn off for separate aux creation gmmParams.Flags.Gpu.CCS = 1; GMM_RESOURCE_INFO *ResourceInfo; ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); uint32_t AlignedWidth = GMM_ULT_ALIGN(gmmParams.BaseWidth64, MinPitch); uint32_t PitchInBytes = AlignedWidth * GetBppValue(bpp); uint32_t AlignedSize = GMM_ULT_ALIGN(PitchInBytes, PAGE_SIZE); VerifyResourceHAlign(ResourceInfo, MinPitch); VerifyResourceVAlign(ResourceInfo, 0); // N/A for buffer VerifyResourcePitch(ResourceInfo, 0); // N/A for buffer VerifyResourcePitchInTiles(ResourceInfo, 0); // N/A for linear VerifyResourceSize(ResourceInfo, AlignedSize); VerifyResourceQPitch(ResourceInfo, 0); // N/A for non-arrayed //test main surface base alignment is 16KB EXPECT_EQ(GMM_KBYTE(64), ResourceInfo->GetBaseAlignment()); EXPECT_EQ(0, ResourceInfo->GetUnifiedAuxSurfaceOffset(GMM_AUX_CCS) % PAGE_SIZE); ASSERT_LE(GMM_ULT_ALIGN(ResourceInfo->GetSizeMainSurface() / (GMM_KBYTE(16) / GMM_BYTES(64)), GMM_KBYTE(4)), ResourceInfo->GetSizeAuxSurface(GMM_AUX_CCS)); { //separate Aux gmmParams.Flags.Gpu.UnifiedAuxSurface = 0; GMM_RESOURCE_INFO *AuxResourceInfo; AuxResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); EXPECT_EQ(ResourceInfo->GetAuxHAlign(), AuxResourceInfo->GetHAlign()); EXPECT_EQ(ResourceInfo->GetAuxVAlign(), AuxResourceInfo->GetVAlign()); EXPECT_EQ(ResourceInfo->GetUnifiedAuxPitch(), AuxResourceInfo->GetRenderPitch()); EXPECT_EQ(ResourceInfo->GetSizeAuxSurface(GMM_AUX_CCS), AuxResourceInfo->GetSizeSurface()); pGmmULTClientContext->DestroyResInfoObject(AuxResourceInfo); } pGmmULTClientContext->DestroyResInfoObject(ResourceInfo); } } ///Add MSAA/Depth Compressed Resource tests TEST_F(CTestGen12dGPUResource, DISABLED_TestLosslessMSAACompressedResource) { } ///Add MSAA/Depth Compressed Resource tests TEST_F(CTestGen12dGPUResource, DISABLED_TestDepthCompressedResource) { const uint32_t HAlign = 8; uint32_t VAlign = 4; //const uint32_t DepthTileSize[1][2] = { 64, 64 }; const uint32_t AllocTileSize[1][2] = {128, 32}; //HiZ is TileY GMM_RESCREATE_PARAMS gmmParams = {}; gmmParams.NoGfxMemory = 1; gmmParams.Flags.Info.TiledY = 1; //Not supported for Depth buffer, but HiZ output is TileY gmmParams.Flags.Gpu.Depth = 1; //GPU Flags= Depth/SeparateStencil + HiZ gmmParams.Flags.Gpu.HiZ = 1; gmmParams.Flags.Gpu.IndirectClearColor = 1; gmmParams.Flags.Gpu.CCS = 1; gmmParams.Flags.Info.RenderCompressed = 1; gmmParams.Flags.Gpu.UnifiedAuxSurface = 1; // Allocate 1x1 surface so that it occupies 1 Tile in X dimension for(uint32_t j = TEST_BPP_8; j <= TEST_BPP_128; j++) //Depth bpp doesn't matter, Depth px dimensions decide HiZ size in HW { { VAlign = (j == TEST_BPP_16) ? 8 : 4; } gmmParams.Format = SetResourceFormat(static_cast(j)); //Only 16,24,32 supported; But driver creates the resource even for other bpps without failing for(uint32_t i = RESOURCE_2D; i <= RESOURCE_CUBE; i++) //3D doesn't support HiZ - test driver returns proper? { gmmParams.Type = static_cast(i); gmmParams.BaseWidth64 = 0x1; gmmParams.BaseHeight = 0x1; //0x24; //not 1 tile //gmmParams.MaxLod = 6; --add expectedheight calc- mip0+max{mip1, sum{mip2,...n}} gmmParams.Depth = 0x1; if(i == RESOURCE_1D || i == RESOURCE_3D) { gmmParams.Flags.Gpu.HiZ = 0; } GMM_RESOURCE_INFO *ResourceInfo = NULL; ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); //EXPECT_NE(NULL, ResourceInfo); VerifyResourceHAlign(ResourceInfo, HAlign); VerifyResourceVAlign(ResourceInfo, VAlign); uint32_t ExpectedPitch = AllocTileSize[0][0] * 4; VerifyResourcePitch(ResourceInfo, ExpectedPitch); VerifyResourcePitchInTiles(ResourceInfo, 4); // 1 tileY wide uint32_t ExpectedHeight = GMM_ULT_ALIGN(gmmParams.BaseHeight, VAlign); if(gmmParams.ArraySize > 1 || gmmParams.Type == RESOURCE_CUBE) { uint32_t ExpectedQPitch = GMM_ULT_ALIGN(gmmParams.BaseHeight, VAlign); //Apply formula on Specification ExpectedQPitch = GMM_ULT_ALIGN(ExpectedQPitch / 2, VAlign); ExpectedHeight *= (gmmParams.Type == RESOURCE_CUBE) ? 6 : 1; VerifyResourceQPitch(ResourceInfo, ExpectedQPitch); // Each face should be VAlign rows apart within a tile, Turn on verification after clarity } VerifyResourceSize(ResourceInfo, GFX_ALIGN(ExpectedPitch * ExpectedHeight, 4 * PAGE_SIZE)); //1 Tile should be enough pGmmULTClientContext->DestroyResInfoObject(ResourceInfo); } // Allocate 2 tiles in X dimension. (muti-tiles Tiles in Y dimension for cube/array) for(uint32_t i = RESOURCE_2D; i <= RESOURCE_CUBE; i++) { gmmParams.Type = static_cast(i); gmmParams.BaseWidth64 = AllocTileSize[0][0] + 0x1; gmmParams.BaseHeight = (gmmParams.Type == RESOURCE_1D) ? 0x1 : (gmmParams.Type == RESOURCE_CUBE) ? gmmParams.BaseWidth64 : VAlign / 2; gmmParams.ArraySize = (gmmParams.Type != RESOURCE_3D) ? VAlign : 1; // Gen8 doesn't support 3D-arrays (so HiZ not supported) [test 3d arrays once -- HiZ would fail but ResCreate doesn't?] gmmParams.Depth = 0x1; GMM_RESOURCE_INFO *ResourceInfo; ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); VerifyResourceHAlign(ResourceInfo, HAlign); VerifyResourceVAlign(ResourceInfo, VAlign); uint32_t ExpectedPitch = GFX_ALIGN(gmmParams.BaseWidth * (int)pow(2, j), AllocTileSize[0][0] * 4); VerifyResourcePitch(ResourceInfo, ExpectedPitch); VerifyResourcePitchInTiles(ResourceInfo, 4); // 2 tileY wide uint32_t ExpectedQPitch = 0; if(gmmParams.ArraySize > 1 || gmmParams.Type == RESOURCE_CUBE) { ExpectedQPitch = GMM_ULT_ALIGN(gmmParams.BaseHeight, VAlign); //ExpectedQPitch = GMM_ULT_ALIGN(ExpectedQPitch / 2, VAlign); VerifyResourceQPitch(ResourceInfo, ExpectedQPitch); // Each face should be VAlign rows apart within a tile. Turn on verification after clarity } VerifyResourceSize(ResourceInfo, // PitchInBytes * Rows where Rows = (__GMM_MAX_CUBE_FACE x QPitch) /2 (Stencil height = halved due to interleaving), then aligned to tile boundary ((gmmParams.Type == RESOURCE_CUBE) ? ExpectedPitch * GMM_ULT_ALIGN(ExpectedQPitch * gmmParams.ArraySize * __GMM_MAX_CUBE_FACE, AllocTileSize[0][1]) : //cube ((gmmParams.ArraySize > 1) ? ExpectedPitch * GMM_ULT_ALIGN(ExpectedQPitch * gmmParams.ArraySize, AllocTileSize[0][1]) : //array 4 * GMM_KBYTE(4)))); pGmmULTClientContext->DestroyResInfoObject(ResourceInfo); } // Allocate 2 tiles in X/Y dimension (non-arrayed) Multi-tiles for 3D for(uint32_t i = RESOURCE_2D; i <= RESOURCE_3D; i++) { gmmParams.Type = static_cast(i); gmmParams.BaseWidth64 = AllocTileSize[0][0] + 0x1; gmmParams.BaseHeight = 2 * AllocTileSize[0][1] + 0x1; //Half-Depth Height or QPitch (lod!=0), aligned to 8 required by HW gmmParams.Depth = (gmmParams.Type == RESOURCE_2D) ? 0x1 : VAlign + 1; gmmParams.ArraySize = 1; GMM_RESOURCE_INFO *ResourceInfo; ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); VerifyResourceHAlign(ResourceInfo, HAlign); VerifyResourceVAlign(ResourceInfo, VAlign); uint32_t ExpectedPitch = AllocTileSize[0][0] * 4; VerifyResourcePitch(ResourceInfo, ExpectedPitch); VerifyResourcePitchInTiles(ResourceInfo, 4); // 2 tile wide uint32_t TwoDQPitch, ExpectedQPitch = 0; if(gmmParams.Type == RESOURCE_3D) { TwoDQPitch = GMM_ULT_ALIGN(gmmParams.BaseHeight, VAlign); ExpectedQPitch = gmmParams.Depth * GMM_ULT_ALIGN(TwoDQPitch / 2, VAlign); //Depth slices arranged as 2D-arrayed slices. } else { //HiZ for 3D not supported. Driver still allocates like IVB/HSW. (should Qpitch or only overall buffer height be Valigned ?) VerifyResourceSize(ResourceInfo, ((gmmParams.Type == RESOURCE_3D) ? ExpectedPitch * GMM_ULT_ALIGN(ExpectedQPitch, AllocTileSize[0][1]) : 2 * 2 * GMM_KBYTE(4))); } pGmmULTClientContext->DestroyResInfoObject(ResourceInfo); } } } TEST_F(CTestGen12dGPUResource, DISABLED_TestStencilCompressedResource) { const uint32_t HAlign = {16}; const uint32_t VAlign = {8}; const uint32_t TileSize[2] = {128, 32}; GMM_RESCREATE_PARAMS gmmParams = {}; gmmParams.Type = RESOURCE_2D; gmmParams.NoGfxMemory = 1; gmmParams.Flags.Info.TiledY = 1; //gmmParams.ArraySize = 4; gmmParams.Flags.Gpu.SeparateStencil = 1; gmmParams.Flags.Info.RenderCompressed = 1; // Turn on .MC or .RC flag - mandatory to tell compression-type, for Yf its also used to pad surf // to 4x1 tile // If unifiedAuxSurf reqd (mandatory for displayable or cross-adapter shared), turn on .CCS/.MMC and .UnifiedAuxSurface too //Allocate 1x1 surface { gmmParams.Flags.Gpu.UnifiedAuxSurface = 1; //Turn off for separate aux creation gmmParams.Flags.Gpu.CCS = 1; //Turn off for separate aux creation gmmParams.Flags.Gpu.IndirectClearColor = 1; TEST_BPP bpp = static_cast(TEST_BPP_8); GMM_TILE_MODE TileMode = LEGACY_TILE_Y; gmmParams.Format = SetResourceFormat(bpp); gmmParams.BaseWidth64 = 0x1; gmmParams.BaseHeight = 0x1; GMM_RESOURCE_INFO *ResourceInfo; ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); VerifyResourceHAlign(ResourceInfo, HAlign); VerifyResourceVAlign(ResourceInfo, VAlign); VerifyResourcePitch(ResourceInfo, 4 * TileSize[0]); // As wide as 4 Tile VerifyResourcePitchInTiles(ResourceInfo, 4); // 4 Tile wide VerifyResourceSize(ResourceInfo, 4 * GMM_KBYTE(4)); // 4 Tile Big VerifyResourceQPitch(ResourceInfo, 0); // Not Tested //test main surface base alignment is 16KB //For Yf test main surface pitch is 4-tileYF aligned EXPECT_EQ(GMM_KBYTE(64), ResourceInfo->GetBaseAlignment()); EXPECT_EQ(0, ResourceInfo->GetRenderPitchTiles() % 4); // Check on YF only EXPECT_EQ(0, ResourceInfo->GetUnifiedAuxSurfaceOffset(GMM_AUX_CCS) % PAGE_SIZE); EXPECT_EQ(GMM_KBYTE(4), ResourceInfo->GetSizeAuxSurface(GMM_AUX_CCS)); { //separate Aux gmmParams.Flags.Gpu.UnifiedAuxSurface = 0; GMM_RESOURCE_INFO *AuxResourceInfo; AuxResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); EXPECT_EQ(ResourceInfo->GetAuxHAlign(), AuxResourceInfo->GetHAlign()); EXPECT_EQ(ResourceInfo->GetAuxVAlign(), AuxResourceInfo->GetVAlign()); EXPECT_EQ(ResourceInfo->GetUnifiedAuxPitch(), AuxResourceInfo->GetRenderPitch()); EXPECT_EQ(ResourceInfo->GetSizeAuxSurface(GMM_AUX_CCS), AuxResourceInfo->GetSizeSurface()); pGmmULTClientContext->DestroyResInfoObject(AuxResourceInfo); } pGmmULTClientContext->DestroyResInfoObject(ResourceInfo); } // Allocate surface that requires multi tiles in two dimension // Allocate 2 tiles in X dimension { gmmParams.Flags.Gpu.UnifiedAuxSurface = 1; //Turn off for separate aux creation gmmParams.Flags.Gpu.CCS = 1; //Turn off for separate aux creation TEST_BPP bpp = static_cast(TEST_BPP_8); GMM_TILE_MODE TileMode = LEGACY_TILE_Y; gmmParams.Format = SetResourceFormat(bpp); gmmParams.BaseWidth64 = (TileSize[0] / GetBppValue(bpp)) + 1; // 1 pixel larger than 1 tile width gmmParams.BaseHeight = 0x1; gmmParams.Depth = 0x1; GMM_RESOURCE_INFO *ResourceInfo; ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); VerifyResourceHAlign(ResourceInfo, HAlign); VerifyResourceVAlign(ResourceInfo, VAlign); VerifyResourcePitch(ResourceInfo, TileSize[0] * 4); // As wide as 2 tile, but 4-tile pitch alignment VerifyResourcePitchInTiles(ResourceInfo, 4); // 2 tile wide, but 4-tile pitch alignment VerifyResourceSize(ResourceInfo, GMM_KBYTE(4) * 4); // 2 tile big, but 4-tile pitch alignment VerifyResourceQPitch(ResourceInfo, 0); // Not tested //test main surface base alignment is 16KB //For Y test main surface pitch is 4-tileY aligned EXPECT_EQ(GMM_KBYTE(64), ResourceInfo->GetBaseAlignment()); EXPECT_EQ(0, ResourceInfo->GetRenderPitchTiles() % 4); EXPECT_EQ(0, ResourceInfo->GetUnifiedAuxSurfaceOffset(GMM_AUX_CCS) % PAGE_SIZE); EXPECT_EQ(GMM_KBYTE(4), ResourceInfo->GetSizeAuxSurface(GMM_AUX_CCS)); { //separate Aux gmmParams.Flags.Gpu.UnifiedAuxSurface = 0; GMM_RESOURCE_INFO *AuxResourceInfo; AuxResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); EXPECT_EQ(ResourceInfo->GetAuxHAlign(), AuxResourceInfo->GetHAlign()); EXPECT_EQ(ResourceInfo->GetAuxVAlign(), AuxResourceInfo->GetVAlign()); EXPECT_EQ(ResourceInfo->GetUnifiedAuxPitch(), AuxResourceInfo->GetRenderPitch()); EXPECT_EQ(ResourceInfo->GetSizeAuxSurface(GMM_AUX_CCS), AuxResourceInfo->GetSizeSurface()); pGmmULTClientContext->DestroyResInfoObject(AuxResourceInfo); } pGmmULTClientContext->DestroyResInfoObject(ResourceInfo); } // Allocate surface that requires multi tiles in two dimension // Allocate 2 tiles in X/Y dimension { gmmParams.Flags.Gpu.UnifiedAuxSurface = 1; //Turn off for separate aux creation gmmParams.Flags.Gpu.CCS = 1; //Turn off for separate aux creation gmmParams.Flags.Gpu.IndirectClearColor = 1; TEST_BPP bpp = static_cast(TEST_BPP_8); GMM_TILE_MODE TileMode = LEGACY_TILE_Y; gmmParams.Format = SetResourceFormat(bpp); gmmParams.BaseWidth64 = (TileSize[0] / GetBppValue(bpp)) + 1; // 1 pixel larger than 1 tile width gmmParams.BaseHeight = TileSize[1] + 1; // 1 row larger than 1 tile height gmmParams.Depth = 0x1; GMM_RESOURCE_INFO *ResourceInfo; ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); VerifyResourceHAlign(ResourceInfo, HAlign); VerifyResourceVAlign(ResourceInfo, VAlign); VerifyResourcePitch(ResourceInfo, TileSize[0] * 4); // As wide as 2 tile, but 4-tile pitch alignment VerifyResourcePitchInTiles(ResourceInfo, 4); // 2 tile wide, but 4-tile pitch alignment VerifyResourceSize(ResourceInfo, GMM_KBYTE(4) * 4 * 2); // 4 tile wide; and 2-tile high VerifyResourceQPitch(ResourceInfo, 0); // Not tested //test main surface base alignment is 16KB //For Y test main surface pitch is 4-tileY aligned EXPECT_EQ(GMM_KBYTE(64), ResourceInfo->GetBaseAlignment()); EXPECT_EQ(0, ResourceInfo->GetRenderPitchTiles() % 4); EXPECT_EQ(0, ResourceInfo->GetUnifiedAuxSurfaceOffset(GMM_AUX_CCS) % PAGE_SIZE); EXPECT_EQ(GMM_KBYTE(4), ResourceInfo->GetSizeAuxSurface(GMM_AUX_CCS)); { //separate Aux gmmParams.Flags.Gpu.UnifiedAuxSurface = 0; GMM_RESOURCE_INFO *AuxResourceInfo; AuxResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); EXPECT_EQ(ResourceInfo->GetAuxHAlign(), AuxResourceInfo->GetHAlign()); EXPECT_EQ(ResourceInfo->GetAuxVAlign(), AuxResourceInfo->GetVAlign()); EXPECT_EQ(ResourceInfo->GetUnifiedAuxPitch(), AuxResourceInfo->GetRenderPitch()); EXPECT_EQ(ResourceInfo->GetSizeAuxSurface(GMM_AUX_CCS), AuxResourceInfo->GetSizeSurface()); pGmmULTClientContext->DestroyResInfoObject(AuxResourceInfo); } pGmmULTClientContext->DestroyResInfoObject(ResourceInfo); } } /// @brief ULT for 2D TileYf Compressed Resource TEST_F(CTestGen12dGPUResource, DISABLED_Test2DTileYfAMFSResource) { const uint32_t HAlign[TEST_BPP_MAX] = {64, 64, 32, 32, 16}; const uint32_t VAlign[TEST_BPP_MAX] = {64, 32, 32, 16, 16}; const uint32_t TileSize[TEST_BPP_MAX][2] = {{64, 64}, {128, 32}, {128, 32}, {256, 16}, {256, 16}}; GMM_RESCREATE_PARAMS gmmParams = {}; gmmParams.Type = RESOURCE_2D; gmmParams.NoGfxMemory = 1; gmmParams.Flags.Info.TiledY = 1; gmmParams.Flags.Info.TiledYf = 1; gmmParams.Flags.Gpu.Texture = 1; gmmParams.Flags.Gpu.ProceduralTexture = 1; // If unifiedAuxSurf reqd (mandatory for displayable or cross-adapter shared), turn on .CCS/.MMC and .UnifiedAuxSurface too //Allocate 1x1 surface for(uint32_t i = 0; i < TEST_BPP_MAX; i++) { gmmParams.Flags.Gpu.UnifiedAuxSurface = 1; //Turn off for separate aux creation gmmParams.Flags.Gpu.CCS = 1; //Turn off for separate aux creation //gmmParams.Flags.Gpu.MMC = 0; //Turn on to check unifiedaux creation TEST_BPP bpp = static_cast(i); GMM_TILE_MODE TileMode = DEFINE_TILE(YF_2D, bpp); gmmParams.Format = SetResourceFormat(bpp); gmmParams.BaseWidth64 = 0x1; gmmParams.BaseHeight = 0x1; GMM_RESOURCE_INFO *ResourceInfo; ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); VerifyResourceHAlign(ResourceInfo, HAlign[i]); VerifyResourceVAlign(ResourceInfo, VAlign[i]); VerifyResourcePitch(ResourceInfo, TileSize[i][0]); // As wide as 1 Tile VerifyResourcePitchInTiles(ResourceInfo, 1); // 1 Tile wide VerifyResourceSize(ResourceInfo, GMM_KBYTE(4)); // 1 Tile Big VerifyResourceQPitch(ResourceInfo, 0); // Not Tested //test main surface base alignment is 4KB, since AMFS PT isn't compressed //but uses same linear CCS as compression EXPECT_EQ(GMM_KBYTE(4), ResourceInfo->GetBaseAlignment()); EXPECT_EQ(0, ResourceInfo->GetUnifiedAuxSurfaceOffset(GMM_AUX_CCS) % PAGE_SIZE); EXPECT_EQ(GMM_KBYTE(4), ResourceInfo->GetSizeAuxSurface(GMM_AUX_CCS)); { //separate Aux gmmParams.Flags.Gpu.UnifiedAuxSurface = 0; GMM_RESOURCE_INFO *AuxResourceInfo; AuxResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); EXPECT_EQ(ResourceInfo->GetAuxHAlign(), AuxResourceInfo->GetHAlign()); EXPECT_EQ(ResourceInfo->GetAuxVAlign(), AuxResourceInfo->GetVAlign()); EXPECT_EQ(ResourceInfo->GetUnifiedAuxPitch(), AuxResourceInfo->GetRenderPitch()); EXPECT_EQ(ResourceInfo->GetSizeAuxSurface(GMM_AUX_CCS), AuxResourceInfo->GetSizeSurface()); EXPECT_EQ(0, AuxResourceInfo->GmmGetTileMode()); pGmmULTClientContext->DestroyResInfoObject(AuxResourceInfo); } pGmmULTClientContext->DestroyResInfoObject(ResourceInfo); } // Allocate surface that requires multi tiles in two dimension // Allocate 2 tiles in X dimension for(uint32_t i = 0; i < TEST_BPP_MAX; i++) { gmmParams.Flags.Gpu.UnifiedAuxSurface = 1; //Turn off for separate aux creation gmmParams.Flags.Gpu.CCS = 1; //Turn off for separate aux creation TEST_BPP bpp = static_cast(i); GMM_TILE_MODE TileMode = DEFINE_TILE(YF_2D, bpp); gmmParams.Format = SetResourceFormat(bpp); gmmParams.BaseWidth64 = (TileSize[i][0] / GetBppValue(bpp)) + 1; // 1 pixel larger than 1 tile width gmmParams.BaseHeight = 0x1; gmmParams.Depth = 0x1; GMM_RESOURCE_INFO *ResourceInfo; ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); VerifyResourceHAlign(ResourceInfo, HAlign[i]); VerifyResourceVAlign(ResourceInfo, VAlign[i]); VerifyResourcePitch(ResourceInfo, TileSize[i][0] * 2); // As wide as 2 tile VerifyResourcePitchInTiles(ResourceInfo, 2); // 2 tile wide VerifyResourceSize(ResourceInfo, GMM_KBYTE(4) * 2); // 2 tile big VerifyResourceQPitch(ResourceInfo, 0); //test main surface base alignment is 4KB EXPECT_EQ(GMM_KBYTE(4), ResourceInfo->GetBaseAlignment()); EXPECT_EQ(0, ResourceInfo->GetUnifiedAuxSurfaceOffset(GMM_AUX_CCS) % PAGE_SIZE); EXPECT_EQ(GMM_KBYTE(4), ResourceInfo->GetSizeAuxSurface(GMM_AUX_CCS)); { //separate Aux gmmParams.Flags.Gpu.UnifiedAuxSurface = 0; GMM_RESOURCE_INFO *AuxResourceInfo; AuxResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); EXPECT_EQ(ResourceInfo->GetAuxHAlign(), AuxResourceInfo->GetHAlign()); EXPECT_EQ(ResourceInfo->GetAuxVAlign(), AuxResourceInfo->GetVAlign()); EXPECT_EQ(ResourceInfo->GetUnifiedAuxPitch(), AuxResourceInfo->GetRenderPitch()); EXPECT_EQ(ResourceInfo->GetSizeAuxSurface(GMM_AUX_CCS), AuxResourceInfo->GetSizeSurface()); EXPECT_EQ(0, AuxResourceInfo->GmmGetTileMode()); pGmmULTClientContext->DestroyResInfoObject(AuxResourceInfo); } pGmmULTClientContext->DestroyResInfoObject(ResourceInfo); } // Allocate surface that requires multi tiles in two dimension // Allocate 2 tiles in X/Y dimension for(uint32_t i = 0; i < TEST_BPP_MAX; i++) { gmmParams.Flags.Gpu.UnifiedAuxSurface = 1; //Turn off for separate aux creation gmmParams.Flags.Gpu.CCS = 1; //Turn off for separate aux creation TEST_BPP bpp = static_cast(i); GMM_TILE_MODE TileMode = DEFINE_TILE(YF_2D, bpp); gmmParams.Format = SetResourceFormat(bpp); gmmParams.BaseWidth64 = (TileSize[i][0] / GetBppValue(bpp)) + 1; // 1 pixel larger than 1 tile width gmmParams.BaseHeight = TileSize[i][1] + 1; // 1 row larger than 1 tile height gmmParams.Depth = 0x1; GMM_RESOURCE_INFO *ResourceInfo; ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); VerifyResourceHAlign(ResourceInfo, HAlign[i]); VerifyResourceVAlign(ResourceInfo, VAlign[i]); VerifyResourcePitch(ResourceInfo, TileSize[i][0] * 2); // As wide as 2 tile VerifyResourcePitchInTiles(ResourceInfo, 2); // 2 tile wide VerifyResourceSize(ResourceInfo, GMM_KBYTE(4) * 2 * 2); // 2 tile wide; and 2-tile high VerifyResourceQPitch(ResourceInfo, 0); //test main surface base alignment is 4KB EXPECT_EQ(GMM_KBYTE(4), ResourceInfo->GetBaseAlignment()); EXPECT_EQ(0, ResourceInfo->GetUnifiedAuxSurfaceOffset(GMM_AUX_CCS) % PAGE_SIZE); EXPECT_EQ(GMM_KBYTE(4), ResourceInfo->GetSizeAuxSurface(GMM_AUX_CCS)); { //separate Aux gmmParams.Flags.Gpu.UnifiedAuxSurface = 0; GMM_RESOURCE_INFO *AuxResourceInfo; AuxResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); EXPECT_EQ(ResourceInfo->GetAuxHAlign(), AuxResourceInfo->GetHAlign()); EXPECT_EQ(ResourceInfo->GetAuxVAlign(), AuxResourceInfo->GetVAlign()); EXPECT_EQ(ResourceInfo->GetUnifiedAuxPitch(), AuxResourceInfo->GetRenderPitch()); EXPECT_EQ(ResourceInfo->GetSizeAuxSurface(GMM_AUX_CCS), AuxResourceInfo->GetSizeSurface()); EXPECT_EQ(0, AuxResourceInfo->GmmGetTileMode()); pGmmULTClientContext->DestroyResInfoObject(AuxResourceInfo); } pGmmULTClientContext->DestroyResInfoObject(ResourceInfo); } } /// @brief ULT for MSAA Resource - adddepth MSAA, MCS surf param verificaton, compression case TEST_F(CTestGen12dGPUResource, DISABLED_TestColorMSAA) { //Tile dimensions in Bytes const uint32_t MCSTileSize[1][2] = {128, 32}; //MCS is TileY const uint32_t TestDimensions[4][2] = { //Input dimensions in #Tiles {15, 20}, //16 Tiles x 20 {0, 0}, //1x1x1 {1, 0}, //2 Tilesx1 {1, 1}, //2 Tiles x 2 }; uint32_t TestArraySize[2] = {1, 5}; uint32_t MinPitch = 32; uint32_t HAlign, VAlign, TileDimX, TileDimY, MCSHAlign, MCSVAlign, TileSize; uint32_t ExpectedMCSBpp; std::vector> List; //TEST_TILE_TYPE, TEST_BPP, TEST_RESOURCE_TYPE, Depth or RT, TestDimension index, ArraySize auto Size = BuildInputIterator(List, 4, 2, false); // Size of arrays TestDimensions, TestArraySize for(auto element : List) { GMM_RESCREATE_PARAMS gmmParams = {}; gmmParams.Flags.Info = {0}; TEST_TILE_TYPE Tiling = (TEST_TILE_TYPE)std::get<0>(element); TEST_BPP Bpp = (TEST_BPP)std::get<1>(element); TEST_RESOURCE_TYPE ResType = (TEST_RESOURCE_TYPE)std::get<2>(element); bool IsRT = std::get<3>(element); // True for RT, False for Depth int TestDimIdx = std::get<4>(element); //index into TestDimensions array int ArrayIdx = std::get<5>(element); //index into TestArraySize TileSize = (Tiling == TEST_TILEYS) ? GMM_KBYTE(64) : GMM_KBYTE(4); //Discard un-supported Tiling/Res_type/bpp for this test if(ResType != TEST_RESOURCE_2D || //No 1D/3D/Cube. Supported 2D mip-maps/array (!IsRT && (Tiling == TEST_TILEX || //Specifications doesn't support TileX for Depth !(Bpp == TEST_BPP_16 || Bpp == TEST_BPP_32)))) //depth supported on 16bit, 32bit formats only continue; if(!IsRT) continue; //comment depth msaa for now (requires change in h/v align) SetTileFlag(gmmParams, Tiling); SetResType(gmmParams, ResType); SetResGpuFlags(gmmParams, IsRT); SetResArraySize(gmmParams, TestArraySize[ArrayIdx]); gmmParams.NoGfxMemory = 1; gmmParams.Format = SetResourceFormat(Bpp); for(uint32_t k = MSAA_2x; k <= MSAA_16x; k++) { GetAlignmentAndTileDimensionsForMSAA(Bpp, IsRT, Tiling, (TEST_MSAA)k, TileDimX, TileDimY, HAlign, VAlign, ExpectedMCSBpp, MCSHAlign, MCSVAlign); //gmmParams.BaseWidth64 = TestDimensions[TestDimIdx][0] * TileDimX + 0x1; //gmmParams.BaseHeight = TestDimensions[TestDimIdx][1] * TileDimY + 0x1; gmmParams.BaseWidth64 = 4; gmmParams.BaseHeight = 4; gmmParams.Depth = 0x1; gmmParams.MSAA.NumSamples = static_cast(pow((double)2, k)); gmmParams.Flags.Gpu.MCS = 0; //MSS surface GMM_RESOURCE_INFO *MSSResourceInfo; MSSResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); if(MSSResourceInfo) { VerifyResourceHAlign(MSSResourceInfo, HAlign); VerifyResourceVAlign(MSSResourceInfo, VAlign); if(IsRT) //Arrayed MSS { uint32_t ExpectedPitch = 0, ExpectedQPitch = 0; ExpectedPitch = GMM_ULT_ALIGN(GMM_ULT_ALIGN(gmmParams.BaseWidth64, HAlign) * (int)pow(2.0, Bpp), TileDimX); // Aligned width * bpp, aligned to TileWidth ExpectedPitch = GFX_MAX(ExpectedPitch, MinPitch); VerifyResourcePitch(MSSResourceInfo, ExpectedPitch); if(Tiling != TEST_LINEAR) VerifyResourcePitchInTiles(MSSResourceInfo, ExpectedPitch / TileDimX); ExpectedQPitch = GMM_ULT_ALIGN(gmmParams.BaseHeight, VAlign); if(gmmParams.ArraySize > 1) //Gen9: Qpitch is distance between array slices (not sample slices) { VerifyResourceQPitch(MSSResourceInfo, ExpectedQPitch); } uint32_t ExpectedHeight = GMM_ULT_ALIGN(ExpectedQPitch * gmmParams.MSAA.NumSamples * gmmParams.ArraySize, TileDimY); //Align Height =ExpectedPitch * NumSamples * ExpectedQPitch, to Tile-Height VerifyResourceSize(MSSResourceInfo, GMM_ULT_ALIGN(ExpectedPitch * ExpectedHeight, TileSize)); } } pGmmULTClientContext->DestroyResInfoObject(MSSResourceInfo); } //NumSamples = k } //Iterate through all Input types //Mip-mapped, MSAA case: } /// @brief ULT for auto-tile selction in Gmm. TEST_F(CTestGen12dGPUResource, Test2DMippedResourceAutoTiling) { GMM_RESCREATE_PARAMS gmmParams = {}; gmmParams.Type = RESOURCE_2D; gmmParams.NoGfxMemory = 1; gmmParams.Flags.Gpu.Texture = 1; gmmParams.MaxLod = 5; gmmParams.ArraySize = 4; for(uint32_t i = 0; i < TEST_BPP_MAX; i++) { TEST_BPP bpp = static_cast(i); gmmParams.Format = SetResourceFormat(bpp); gmmParams.BaseWidth64 = 0x120; gmmParams.BaseHeight = 0x120; GMM_RESOURCE_INFO *ResourceInfo; ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); GMM_RESOURCE_INFO *ResourceInfo2; ResourceInfo2 = pGmmULTClientContext->CreateResInfoObject(&gmmParams); //Verify Gmm tile-selection able to get same tiling mode for resources created with same GmmParams //... where 1st iteration uses auto-tile-selection, and next creates with previouly selected tile-mode. //Below ensures, Gmm modified gmmParams to final tile-mode, or left it at initial (no tiling selection). EXPECT_EQ(ResourceInfo->GmmGetTileMode(), ResourceInfo2->GmmGetTileMode()); pGmmULTClientContext->DestroyResInfoObject(ResourceInfo); pGmmULTClientContext->DestroyResInfoObject(ResourceInfo2); } } gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/ULT/GmmGen12dGPUResourceULT.h000066400000000000000000000042071466655022700250250ustar00rootroot00000000000000/*============================================================================== Copyright(c) 2020 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ============================================================================*/ #pragma once #include "GmmGen10ResourceULT.h" #include "../GmmLib/inc/Internal/Common/Platform/GmmGen12Platform.h" class CTestGen12dGPUResource : public CTestGen10Resource { public: static void SetUpTestCase(); static void TearDownTestCase(); }; #define DEFINE_TILE(xxx, bpp) \ (bpp == TEST_BPP_8) ? TILE_##xxx##_8bpe : \ (bpp == TEST_BPP_16) ? TILE_##xxx##_16bpe : \ (bpp == TEST_BPP_32) ? TILE_##xxx##_32bpe : \ (bpp == TEST_BPP_64) ? TILE_##xxx##_64bpe : \ TILE_##xxx##_128bpe gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/ULT/GmmGen9CachePolicyULT.cpp000066400000000000000000000152351466655022700251650ustar00rootroot00000000000000/*============================================================================== Copyright(c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ============================================================================*/ #include "GmmGen9CachePolicyULT.h" using namespace std; ///////////////////////////////////////////////////////////////////////////////////// /// Sets up common environment for Cache Policy fixture tests. this is called once per /// test case before executing all tests under resource fixture test case. /// It also calls SetupTestCase from CommonULT to initialize global context and others. /// ///////////////////////////////////////////////////////////////////////////////////// void CTestGen9CachePolicy::SetUpTestCase() { GfxPlatform.eProductFamily = IGFX_SKYLAKE; GfxPlatform.eRenderCoreFamily = IGFX_GEN9_CORE; AllocateAdapterInfo(); pGfxAdapterInfo->SystemInfo.L3CacheSizeInKb = 768; pGfxAdapterInfo->SystemInfo.LLCCacheSizeInKb = 2 * 1024; //2 MB pGfxAdapterInfo->SystemInfo.EdramSizeInKb = 128 * 1024; //128 MB const_cast(pGfxAdapterInfo->SkuTable).FtrEDram = 1; CommonULT::SetUpTestCase(); printf("%s\n", __FUNCTION__); } ///////////////////////////////////////////////////////////////////////////////////// /// cleans up once all the tests finish execution. It also calls TearDownTestCase /// from CommonULT to destroy global context and others. /// ///////////////////////////////////////////////////////////////////////////////////// void CTestGen9CachePolicy::TearDownTestCase() { printf("%s\n", __FUNCTION__); CommonULT::TearDownTestCase(); } void CTestGen9CachePolicy::CheckL3CachePolicy() { const uint32_t L3_WB_CACHEABLE = 0x3; const uint32_t L3_UNCACHEABLE = 0x1; // Check Usage MOCS index against MOCS settings for(uint32_t Usage = GMM_RESOURCE_USAGE_UNKNOWN; Usage < GMM_RESOURCE_USAGE_MAX; Usage++) { GMM_CACHE_POLICY_ELEMENT ClientRequest = pGmmULTClientContext->GetCachePolicyElement((GMM_RESOURCE_USAGE_TYPE)Usage); uint32_t AssignedMocsIdx = ClientRequest.MemoryObjectOverride.Gen9.Index; GMM_CACHE_POLICY_TBL_ELEMENT Mocs = pGmmULTClientContext->GetCachePolicyTlbElement(AssignedMocsIdx); EXPECT_EQ(0, Mocs.L3.ESC) << "Usage# " << Usage << ": ESC is non-zero"; EXPECT_EQ(0, Mocs.L3.SCC) << "Usage# " << Usage << ": SCC is non-zero"; EXPECT_EQ(0, Mocs.L3.Reserved) << "Usage# " << Usage << ": Reserved field is non-zero"; if(ClientRequest.L3) { EXPECT_EQ(L3_WB_CACHEABLE, Mocs.L3.Cacheability) << "Usage# " << Usage << ": Incorrect L3 cachebility setting"; } else { EXPECT_EQ(L3_UNCACHEABLE, Mocs.L3.Cacheability) << "Usage# " << Usage << ": Incorrect L3 cachebility setting"; } } } TEST_F(CTestGen9CachePolicy, TestL3CachePolicy) { CheckL3CachePolicy(); } void CTestGen9CachePolicy::CheckLlcEdramCachePolicy() { const uint32_t TargetCache_ELLC = 0; const uint32_t TargetCache_LLC = 1; const uint32_t TargetCache_LLC_ELLC = 2; const uint32_t LeCC_UNCACHEABLE = 0x1; const uint32_t LeCC_WB_CACHEABLE = 0x3; // Check Usage MOCS index against MOCS settings for(uint32_t Usage = GMM_RESOURCE_USAGE_UNKNOWN; Usage < GMM_RESOURCE_USAGE_MAX; Usage++) { GMM_CACHE_POLICY_ELEMENT ClientRequest = pGmmULTClientContext->GetCachePolicyElement((GMM_RESOURCE_USAGE_TYPE)Usage); uint32_t AssignedMocsIdx = ClientRequest.MemoryObjectOverride.Gen9.Index; GMM_CACHE_POLICY_TBL_ELEMENT Mocs = pGmmULTClientContext->GetCachePolicyTlbElement(AssignedMocsIdx); // Check for unused fields EXPECT_EQ(0, Mocs.LeCC.AOM) << "Usage# " << Usage << ": AOM is non-zero"; EXPECT_EQ(0, Mocs.LeCC.CoS) << "Usage# " << Usage << ": CoS is non-zero"; EXPECT_EQ(0, Mocs.LeCC.PFM) << "Usage# " << Usage << ": PFM is non-zero"; EXPECT_EQ(0, Mocs.LeCC.SCC) << "Usage# " << Usage << ": SCC is non-zero"; EXPECT_EQ(0, Mocs.LeCC.SCF) << "Usage# " << Usage << ": SCF is non-zero"; EXPECT_EQ(0, Mocs.LeCC.SelfSnoop) << "Usage# " << Usage << ": Self Snoop is non-zero"; EXPECT_EQ(0, Mocs.LeCC.ESC) << "Usage# " << Usage << ": ESC is non-zero"; EXPECT_EQ(0, Mocs.LeCC.Reserved) << "Usage# " << Usage << ": Reserved field is non-zero"; // Check for age EXPECT_EQ(ClientRequest.AGE, Mocs.LeCC.LRUM) << "Usage# " << Usage << ": Incorrect AGE settings"; if(!ClientRequest.LLC && !ClientRequest.ELLC) // Uncached { EXPECT_EQ(LeCC_UNCACHEABLE, Mocs.LeCC.Cacheability) << "Usage# " << Usage << ": Incorrect LLC/eDRAM cachebility setting"; } else { EXPECT_EQ(LeCC_WB_CACHEABLE, Mocs.LeCC.Cacheability) << "Usage# " << Usage << ": Incorrect LLC/eDRAM cachebility setting"; if(ClientRequest.LLC && !ClientRequest.ELLC) // LLC only { EXPECT_EQ(TargetCache_LLC, Mocs.LeCC.TargetCache) << "Usage# " << Usage << ": Incorrect target cache setting"; } else if(!ClientRequest.LLC && ClientRequest.ELLC) // eLLC only { EXPECT_EQ(TargetCache_ELLC, Mocs.LeCC.TargetCache) << "Usage# " << Usage << ": Incorrect target cache setting"; } else { EXPECT_EQ(TargetCache_LLC_ELLC, Mocs.LeCC.TargetCache) << "Usage# " << Usage << ": Incorrect target cache setting"; } } } } TEST_F(CTestGen9CachePolicy, TestLlcEdramCachePolicy) { CheckLlcEdramCachePolicy(); } gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/ULT/GmmGen9CachePolicyULT.h000066400000000000000000000027641466655022700246350ustar00rootroot00000000000000/*============================================================================== Copyright(c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ============================================================================*/ #pragma once #include "GmmCachePolicyULT.h" class CTestGen9CachePolicy : public CTestCachePolicy { protected: virtual void CheckL3CachePolicy(); virtual void CheckLlcEdramCachePolicy(); public: static void SetUpTestCase(); static void TearDownTestCase(); }; gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/ULT/GmmGen9ResourceULT.cpp000066400000000000000000005743241466655022700246020ustar00rootroot00000000000000/*============================================================================== Copyright(c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ============================================================================*/ #include "GmmGen9ResourceULT.h" using namespace std; ///////////////////////////////////////////////////////////////////////////////////// /// CTestGen9Resource Constructor /// ///////////////////////////////////////////////////////////////////////////////////// CTestGen9Resource::CTestGen9Resource() { } ///////////////////////////////////////////////////////////////////////////////////// /// CTestGen9Resource Destructor /// ///////////////////////////////////////////////////////////////////////////////////// CTestGen9Resource::~CTestGen9Resource() { } ///////////////////////////////////////////////////////////////////////////////////// /// Sets up common environment for Resource fixture tests. this is called once per /// test case before executing all tests under resource fixture test case. /// It also calls SetupTestCase from CommonULT to initialize global context and others. ///////////////////////////////////////////////////////////////////////////////////// void CTestGen9Resource::SetUpTestCase() { GfxPlatform.eProductFamily = IGFX_SKYLAKE; GfxPlatform.eRenderCoreFamily = IGFX_GEN9_CORE; CommonULT::SetUpTestCase(); printf("%s\n", __FUNCTION__); } ///////////////////////////////////////////////////////////////////////////////////// /// cleans up once all the tests finish execution. It also calls TearDownTestCase /// from CommonULT to destroy global context and others. ///////////////////////////////////////////////////////////////////////////////////// void CTestGen9Resource::TearDownTestCase() { printf("%s\n", __FUNCTION__); CommonULT::TearDownTestCase(); } // ********************************************************************************// /// @brief ULT for 1D Linear Resource TEST_F(CTestGen9Resource, Test1DLinearResource) { // Horizontal pixel alignment const uint32_t HAlign = 64; GMM_RESCREATE_PARAMS gmmParams = {}; gmmParams.Type = RESOURCE_1D; gmmParams.NoGfxMemory = 1; gmmParams.Flags.Info.Linear = 1; gmmParams.Flags.Gpu.Texture = 1; // Allocate 1x1 surface for(uint32_t i = 0; i < TEST_BPP_MAX; i++) { TEST_BPP bpp = static_cast(i); gmmParams.Format = SetResourceFormat(bpp); gmmParams.BaseWidth64 = 0x1; gmmParams.BaseHeight = 1; GMM_RESOURCE_INFO *ResourceInfo; ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); uint32_t AlignedWidth = GMM_ULT_ALIGN(gmmParams.BaseWidth64, HAlign); uint32_t PitchInBytes = AlignedWidth * GetBppValue(bpp); uint32_t AlignedSize = GMM_ULT_ALIGN(PitchInBytes, PAGE_SIZE); VerifyResourceHAlign(ResourceInfo, HAlign); VerifyResourceVAlign(ResourceInfo, 0); // N/A for 1D VerifyResourcePitch(ResourceInfo, 0); // N/A for 1D VerifyResourcePitchInTiles(ResourceInfo, 0); // N/A for linear VerifyResourceSize(ResourceInfo, AlignedSize); VerifyResourceQPitch(ResourceInfo, 0); // N/A for non-arrayed pGmmULTClientContext->DestroyResInfoObject(ResourceInfo); } // Allocate more than 1 page for(uint32_t i = 0; i < TEST_BPP_MAX; i++) { TEST_BPP bpp = static_cast(i); gmmParams.Format = SetResourceFormat(bpp); gmmParams.BaseWidth64 = 0x1001; gmmParams.BaseHeight = 1; GMM_RESOURCE_INFO *ResourceInfo; ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); uint32_t AlignedWidth = GMM_ULT_ALIGN(gmmParams.BaseWidth64, HAlign); uint32_t PitchInBytes = AlignedWidth * GetBppValue(bpp); uint32_t AlignedSize = GMM_ULT_ALIGN(PitchInBytes, PAGE_SIZE); VerifyResourceHAlign(ResourceInfo, HAlign); VerifyResourceVAlign(ResourceInfo, 0); // N/A for 1D VerifyResourcePitch(ResourceInfo, 0); // N/A for 1D VerifyResourcePitchInTiles(ResourceInfo, 0); // N/A for linear VerifyResourceSize(ResourceInfo, AlignedSize); VerifyResourceQPitch(ResourceInfo, 0); // N/A for non-arrayed pGmmULTClientContext->DestroyResInfoObject(ResourceInfo); } } /// @brief ULT for 1D Linear Resource Arrays TEST_F(CTestGen9Resource, Test1DLinearResourceArrays) { // Horizontal pixel alignment const uint32_t HAlign = 64; GMM_RESCREATE_PARAMS gmmParams = {}; gmmParams.Type = RESOURCE_1D; gmmParams.NoGfxMemory = 1; gmmParams.Flags.Info.Linear = 1; gmmParams.Flags.Gpu.Texture = 1; gmmParams.ArraySize = 4; // Allocate more than 1 page for(uint32_t i = 0; i < TEST_BPP_MAX; i++) { TEST_BPP bpp = static_cast(i); gmmParams.Format = SetResourceFormat(bpp); gmmParams.BaseWidth64 = 0x1001; gmmParams.BaseHeight = 1; GMM_RESOURCE_INFO *ResourceInfo; ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); uint32_t AlignedWidth = GMM_ULT_ALIGN(gmmParams.BaseWidth64, HAlign); uint32_t PitchInBytes = AlignedWidth * GetBppValue(bpp); uint32_t AlignedSize = GMM_ULT_ALIGN(PitchInBytes * gmmParams.ArraySize, PAGE_SIZE); VerifyResourceHAlign(ResourceInfo, HAlign); VerifyResourceVAlign(ResourceInfo, 0); // N/A for 1D VerifyResourcePitch(ResourceInfo, 0); // N/A for 1D VerifyResourcePitchInTiles(ResourceInfo, 0); // N/A for linear VerifyResourceSize(ResourceInfo, AlignedSize); VerifyResourceQPitch(ResourceInfo, AlignedWidth); pGmmULTClientContext->DestroyResInfoObject(ResourceInfo); } } /// @brief ULT for 1D Mipped Linear Resource TEST_F(CTestGen9Resource, Test1DLinearResourceMips) { // Horizontal pixel alignment const uint32_t HAlign = 64; GMM_RESCREATE_PARAMS gmmParams = {}; gmmParams.Type = RESOURCE_1D; gmmParams.NoGfxMemory = 1; gmmParams.Flags.Info.Linear = 1; gmmParams.Flags.Gpu.Texture = 1; gmmParams.MaxLod = 5; // Allocate 256x1 surface for(uint32_t i = 0; i < TEST_BPP_MAX; i++) { TEST_BPP bpp = static_cast(i); gmmParams.Format = SetResourceFormat(bpp); gmmParams.BaseWidth64 = 0x100; gmmParams.BaseHeight = 0x1; GMM_RESOURCE_INFO *ResourceInfo; ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); uint32_t AlignedWidth = GMM_ULT_ALIGN(gmmParams.BaseWidth64, HAlign); for(int mip = 1; mip <= gmmParams.MaxLod; mip++) { // Since 1D doesn't have a height, mips are just based on width AlignedWidth += GMM_ULT_ALIGN(gmmParams.BaseWidth64 >> mip, HAlign); } uint32_t PitchInBytes = AlignedWidth * GetBppValue(bpp); uint32_t AlignedSize = GMM_ULT_ALIGN(PitchInBytes, PAGE_SIZE); VerifyResourceHAlign(ResourceInfo, HAlign); VerifyResourceVAlign(ResourceInfo, 0); // N/A for 1D VerifyResourcePitch(ResourceInfo, 0); // N/A for 1D VerifyResourcePitchInTiles(ResourceInfo, 0); // N/A for linear VerifyResourceSize(ResourceInfo, AlignedSize); VerifyResourceQPitch(ResourceInfo, 0); // N/A for non-arrayed // Mip0 should be at offset 0. X/Y/Z Offset should be 0 for linear. GMM_REQ_OFFSET_INFO OffsetInfo = {}; OffsetInfo.ReqRender = 1; OffsetInfo.MipLevel = 0; //Mip 0 ResourceInfo->GetOffset(OffsetInfo); EXPECT_EQ(0, OffsetInfo.Render.Offset64); EXPECT_EQ(0, OffsetInfo.Render.XOffset); EXPECT_EQ(0, OffsetInfo.Render.YOffset); EXPECT_EQ(0, OffsetInfo.Render.ZOffset); // All mips should be right after one another linearly uint32_t StartOfMip = 0; for(int mip = 1; mip <= gmmParams.MaxLod; mip++) { OffsetInfo = {}; OffsetInfo.ReqRender = 1; OffsetInfo.MipLevel = mip; ResourceInfo->GetOffset(OffsetInfo); StartOfMip += GMM_ULT_ALIGN(gmmParams.BaseWidth64 >> (mip - 1), HAlign) * GetBppValue(bpp); EXPECT_EQ(StartOfMip, OffsetInfo.Render.Offset64); EXPECT_EQ(0, OffsetInfo.Render.XOffset); EXPECT_EQ(0, OffsetInfo.Render.YOffset); EXPECT_EQ(0, OffsetInfo.Render.ZOffset); } pGmmULTClientContext->DestroyResInfoObject(ResourceInfo); } } /// @brief ULT for 1D TileYs Resource -TRMODE_64KB TEST_F(CTestGen9Resource, Test1DTileYsResource) { const uint32_t TileSize[TEST_BPP_MAX] = {65536, 32768, 16384, 8192, 4096}; GMM_RESCREATE_PARAMS gmmParams = {}; gmmParams.Type = RESOURCE_1D; gmmParams.NoGfxMemory = 1; gmmParams.Flags.Info.TiledYs = 1; gmmParams.Flags.Gpu.Texture = 1; // Allocate 1x1 surface for(uint32_t i = 0; i < TEST_BPP_MAX; i++) { TEST_BPP bpp = static_cast(i); gmmParams.Format = SetResourceFormat(bpp); gmmParams.BaseWidth64 = 0x1; gmmParams.BaseHeight = 1; GMM_RESOURCE_INFO *ResourceInfo; ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); uint32_t AlignedWidth = GMM_ULT_ALIGN(gmmParams.BaseWidth64, TileSize[i]); uint32_t PitchInBytes = AlignedWidth * GetBppValue(bpp); uint32_t AlignedSize = GMM_ULT_ALIGN(PitchInBytes, PAGE_SIZE); VerifyResourceHAlign(ResourceInfo, TileSize[i]); VerifyResourceVAlign(ResourceInfo, 0); // N/A for 1D VerifyResourcePitch(ResourceInfo, 0); // N/A for 1D VerifyResourcePitchInTiles(ResourceInfo, 0); // N/A for linear VerifyResourceSize(ResourceInfo, AlignedSize); VerifyResourceQPitch(ResourceInfo, 0); // N/A for non-arrayed pGmmULTClientContext->DestroyResInfoObject(ResourceInfo); } // Allocate more than 1 "tile", where applicable. Max width of the surface can only be // 16K (see RENDER_SURFACE_STATE). Depending on the bpp, 16K width may not use more than // 1 "tile" (only 64/128 will use "multi-tile"). for(uint32_t i = 0; i < TEST_BPP_MAX; i++) { TEST_BPP bpp = static_cast(i); gmmParams.Format = SetResourceFormat(bpp); gmmParams.BaseWidth64 = 16 * 1024; // 16K is the max width you can specify gmmParams.BaseHeight = 1; GMM_RESOURCE_INFO *ResourceInfo; ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); uint32_t AlignedWidth = GMM_ULT_ALIGN(gmmParams.BaseWidth64, TileSize[i]); uint32_t PitchInBytes = AlignedWidth * GetBppValue(bpp); uint32_t AlignedSize = GMM_ULT_ALIGN(PitchInBytes, PAGE_SIZE); VerifyResourceHAlign(ResourceInfo, TileSize[i]); VerifyResourceVAlign(ResourceInfo, 0); // N/A for 1D VerifyResourcePitch(ResourceInfo, 0); // N/A for 1D VerifyResourcePitchInTiles(ResourceInfo, 0); // N/A for linear VerifyResourceSize(ResourceInfo, AlignedSize); VerifyResourceQPitch(ResourceInfo, 0); // N/A for non-arrayed pGmmULTClientContext->DestroyResInfoObject(ResourceInfo); } } /// @brief ULT for 1D TileYS Resource Arrays TEST_F(CTestGen9Resource, Test1DTileYsResourceArrays) { const uint32_t TileSize[TEST_BPP_MAX] = {65536, 32768, 16384, 8192, 4096}; GMM_RESCREATE_PARAMS gmmParams = {}; gmmParams.Type = RESOURCE_1D; gmmParams.NoGfxMemory = 1; gmmParams.Flags.Info.TiledYs = 1; gmmParams.Flags.Gpu.Texture = 1; gmmParams.ArraySize = 4; // Allocate more than 1 page for(uint32_t i = 0; i < TEST_BPP_MAX; i++) { TEST_BPP bpp = static_cast(i); gmmParams.Format = SetResourceFormat(bpp); gmmParams.BaseWidth64 = 16 * 1024; // 16K is the max width you can specify gmmParams.BaseHeight = 1; GMM_RESOURCE_INFO *ResourceInfo; ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); uint32_t AlignedWidth = GMM_ULT_ALIGN(gmmParams.BaseWidth64, TileSize[i]); uint32_t PitchInBytes = AlignedWidth * GetBppValue(bpp); uint32_t AlignedSize = GMM_ULT_ALIGN(PitchInBytes * gmmParams.ArraySize, PAGE_SIZE); VerifyResourceHAlign(ResourceInfo, TileSize[i]); VerifyResourceVAlign(ResourceInfo, 0); // N/A for 1D VerifyResourcePitch(ResourceInfo, 0); // N/A for 1D VerifyResourcePitchInTiles(ResourceInfo, 0); // N/A for linear VerifyResourceSize(ResourceInfo, AlignedSize); VerifyResourceQPitch(ResourceInfo, AlignedWidth); pGmmULTClientContext->DestroyResInfoObject(ResourceInfo); } } /// @brief ULT for 1D Mipped TileYS Resource TEST_F(CTestGen9Resource, Test1DTileYsResourceMips) { const uint32_t TileSize[TEST_BPP_MAX] = {65536, 32768, 16384, 8192, 4096}; const uint32_t Mts[TEST_BPP_MAX] = {32768, 16384, 8192, 4096, 2048}; GMM_RESCREATE_PARAMS gmmParams = {}; gmmParams.Type = RESOURCE_1D; gmmParams.NoGfxMemory = 1; gmmParams.Flags.Info.TiledYs = 1; gmmParams.Flags.Gpu.Texture = 1; gmmParams.MaxLod = 5; // Allocate all mips in 1 tile or multiple tiles, depending on the bpp for(uint32_t i = 0; i < TEST_BPP_MAX; i++) { TEST_BPP bpp = static_cast(i); gmmParams.Format = SetResourceFormat(bpp); gmmParams.BaseWidth64 = 16 * 1024; // 16K is the max width you can specify gmmParams.BaseHeight = 0x1; GMM_RESOURCE_INFO *ResourceInfo; ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); uint32_t MaxMip; uint32_t MipTailStart = gmmParams.MaxLod; for(MaxMip = 0; MaxMip <= gmmParams.MaxLod; MaxMip++) { if((gmmParams.BaseWidth64 >> MaxMip) <= Mts[i]) { MipTailStart = MaxMip; break; } } uint32_t AlignedWidth = 0; for(int mip = 0; mip <= MaxMip; mip++) { // Since 1D doesn't have a height, mips are just based on width AlignedWidth += GMM_ULT_ALIGN(gmmParams.BaseWidth64 >> mip, TileSize[i]); ; } uint32_t PitchInBytes = AlignedWidth * GetBppValue(bpp); uint32_t AlignedSize = GMM_ULT_ALIGN(PitchInBytes, PAGE_SIZE); VerifyResourceHAlign(ResourceInfo, TileSize[i]); VerifyResourceVAlign(ResourceInfo, 0); // N/A for 1D VerifyResourcePitch(ResourceInfo, 0); // N/A for 1D VerifyResourcePitchInTiles(ResourceInfo, 0); // N/A for linear VerifyResourceSize(ResourceInfo, AlignedSize); VerifyResourceQPitch(ResourceInfo, 0); // N/A for non-arrayed // All mips should be right after one another linearly, until the miptail uint32_t StartOfMip = 0; int mip; for(mip = 0; mip < MaxMip; mip++) { GMM_REQ_OFFSET_INFO OffsetInfo = {}; OffsetInfo.ReqRender = 1; OffsetInfo.MipLevel = mip; ResourceInfo->GetOffset(OffsetInfo); StartOfMip += (mip == 0 ? 0 : GMM_ULT_ALIGN(gmmParams.BaseWidth64 >> (mip - 1), TileSize[i]) * GetBppValue(bpp)); EXPECT_EQ(StartOfMip, OffsetInfo.Render.Offset64); EXPECT_EQ(0, OffsetInfo.Render.XOffset); EXPECT_EQ(0, OffsetInfo.Render.YOffset); EXPECT_EQ(0, OffsetInfo.Render.ZOffset); } uint32_t MipTailOffsets[GMM_ULT_MAX_MIPMAP] = {32768, 16384, 8192, 4096, 2048, 1024, 768, 512, 448, 384, 320, 256, 192, 128, 64}; // Check for offset inside miptails. EXPECT_EQ(MipTailStart, ResourceInfo->GetPackedMipTailStartLod()); StartOfMip += GMM_ULT_ALIGN(gmmParams.BaseWidth64 >> (mip - 1), TileSize[i]) * GetBppValue(bpp); // Start of MipTail for(int slot = 0; mip <= gmmParams.MaxLod; mip++, slot++) { GMM_REQ_OFFSET_INFO OffsetInfo = {}; OffsetInfo.ReqRender = 1; OffsetInfo.MipLevel = mip; ResourceInfo->GetOffset(OffsetInfo); EXPECT_EQ(StartOfMip, OffsetInfo.Render.Offset64); // Start of Miptail EXPECT_EQ(MipTailOffsets[slot], OffsetInfo.Render.XOffset); // Offset within miptail EXPECT_EQ(0, OffsetInfo.Render.YOffset); EXPECT_EQ(0, OffsetInfo.Render.ZOffset); } pGmmULTClientContext->DestroyResInfoObject(ResourceInfo); } } /// @brief ULT for 1D TileYs Resource -TRMODE_4KB TEST_F(CTestGen9Resource, Test1DTileYfResource) { const uint32_t TileSize[TEST_BPP_MAX] = {4096, 2048, 1024, 512, 256}; GMM_RESCREATE_PARAMS gmmParams = {}; gmmParams.Type = RESOURCE_1D; gmmParams.NoGfxMemory = 1; gmmParams.Flags.Info.TiledYf = 1; gmmParams.Flags.Gpu.Texture = 1; // Allocate 1x1 surface for(uint32_t i = 0; i < TEST_BPP_MAX; i++) { TEST_BPP bpp = static_cast(i); gmmParams.Format = SetResourceFormat(bpp); gmmParams.BaseWidth64 = 0x1; gmmParams.BaseHeight = 1; GMM_RESOURCE_INFO *ResourceInfo; ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); uint32_t AlignedWidth = GMM_ULT_ALIGN(gmmParams.BaseWidth64, TileSize[i]); uint32_t PitchInBytes = AlignedWidth * GetBppValue(bpp); uint32_t AlignedSize = GMM_ULT_ALIGN(PitchInBytes, PAGE_SIZE); VerifyResourceHAlign(ResourceInfo, TileSize[i]); VerifyResourceVAlign(ResourceInfo, 0); // N/A for 1D VerifyResourcePitch(ResourceInfo, 0); // N/A for 1D VerifyResourcePitchInTiles(ResourceInfo, 0); // N/A for linear VerifyResourceSize(ResourceInfo, AlignedSize); VerifyResourceQPitch(ResourceInfo, 0); // N/A for non-arrayed pGmmULTClientContext->DestroyResInfoObject(ResourceInfo); } // Allocate more than 1 "tile" for(uint32_t i = 0; i < TEST_BPP_MAX; i++) { TEST_BPP bpp = static_cast(i); gmmParams.Format = SetResourceFormat(bpp); gmmParams.BaseWidth64 = TileSize[i] + 1; gmmParams.BaseHeight = 1; GMM_RESOURCE_INFO *ResourceInfo; ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); uint32_t AlignedWidth = GMM_ULT_ALIGN(gmmParams.BaseWidth64, TileSize[i]); uint32_t PitchInBytes = AlignedWidth * GetBppValue(bpp); uint32_t AlignedSize = GMM_ULT_ALIGN(PitchInBytes, PAGE_SIZE); VerifyResourceHAlign(ResourceInfo, TileSize[i]); VerifyResourceVAlign(ResourceInfo, 0); // N/A for 1D VerifyResourcePitch(ResourceInfo, 0); // N/A for 1D VerifyResourcePitchInTiles(ResourceInfo, 0); // N/A for linear VerifyResourceSize(ResourceInfo, AlignedSize); VerifyResourceQPitch(ResourceInfo, 0); // N/A for non-arrayed pGmmULTClientContext->DestroyResInfoObject(ResourceInfo); } } /// @brief ULT for 1D TileYF Resource Arrays TEST_F(CTestGen9Resource, Test1DTileYfResourceArrays) { const uint32_t TileSize[TEST_BPP_MAX] = {4096, 2048, 1024, 512, 256}; GMM_RESCREATE_PARAMS gmmParams = {}; gmmParams.Type = RESOURCE_1D; gmmParams.NoGfxMemory = 1; gmmParams.Flags.Info.TiledYf = 1; gmmParams.Flags.Gpu.Texture = 1; gmmParams.ArraySize = 4; // Allocate more than 1 page for(uint32_t i = 0; i < TEST_BPP_MAX; i++) { TEST_BPP bpp = static_cast(i); gmmParams.Format = SetResourceFormat(bpp); gmmParams.BaseWidth64 = 16 * 1024; // 16K is the max width you can specify gmmParams.BaseHeight = 1; GMM_RESOURCE_INFO *ResourceInfo; ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); uint32_t AlignedWidth = GMM_ULT_ALIGN(gmmParams.BaseWidth64, TileSize[i]); uint32_t PitchInBytes = AlignedWidth * GetBppValue(bpp); uint32_t AlignedSize = GMM_ULT_ALIGN(PitchInBytes * gmmParams.ArraySize, PAGE_SIZE); VerifyResourceHAlign(ResourceInfo, TileSize[i]); VerifyResourceVAlign(ResourceInfo, 0); // N/A for 1D VerifyResourcePitch(ResourceInfo, 0); // N/A for 1D VerifyResourcePitchInTiles(ResourceInfo, 0); // N/A for linear VerifyResourceSize(ResourceInfo, AlignedSize); VerifyResourceQPitch(ResourceInfo, AlignedWidth); pGmmULTClientContext->DestroyResInfoObject(ResourceInfo); } } /// @brief ULT for 1D Mipped TileYF Resource TEST_F(CTestGen9Resource, Test1DTileYfResourceMips) { const uint32_t TileSize[TEST_BPP_MAX] = {4096, 2048, 1024, 512, 256}; const uint32_t Mts[TEST_BPP_MAX] = {2048, 1024, 512, 256, 128}; GMM_RESCREATE_PARAMS gmmParams = {}; gmmParams.Type = RESOURCE_1D; gmmParams.NoGfxMemory = 1; gmmParams.Flags.Info.TiledYf = 1; gmmParams.Flags.Gpu.Texture = 1; gmmParams.MaxLod = 8; // Allocate all mips in 1 tile or multiple tiles, depending on the bpp for(uint32_t i = 0; i < TEST_BPP_MAX; i++) { TEST_BPP bpp = static_cast(i); gmmParams.Format = SetResourceFormat(bpp); gmmParams.BaseWidth64 = 16 * 1024; // 16K is the max width you can specify gmmParams.BaseHeight = 0x1; GMM_RESOURCE_INFO *ResourceInfo; ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); uint32_t MaxMip; uint32_t MipTailStart = gmmParams.MaxLod; for(MaxMip = 0; MaxMip <= gmmParams.MaxLod; MaxMip++) { if((gmmParams.BaseWidth64 >> MaxMip) <= Mts[i]) { MipTailStart = MaxMip; break; } } uint32_t AlignedWidth = 0; for(int mip = 0; mip <= MaxMip; mip++) { // Since 1D doesn't have a height, mips are just based on width AlignedWidth += GMM_ULT_ALIGN(gmmParams.BaseWidth64 >> mip, TileSize[i]); } uint32_t PitchInBytes = AlignedWidth * GetBppValue(bpp); uint32_t AlignedSize = GMM_ULT_ALIGN(PitchInBytes, PAGE_SIZE); VerifyResourceHAlign(ResourceInfo, TileSize[i]); VerifyResourceVAlign(ResourceInfo, 0); // N/A for 1D VerifyResourcePitch(ResourceInfo, 0); // N/A for 1D VerifyResourcePitchInTiles(ResourceInfo, 0); // N/A for linear VerifyResourceSize(ResourceInfo, AlignedSize); VerifyResourceQPitch(ResourceInfo, 0); // N/A for non-arrayed // All mips should be right after one another linearly, until the miptail uint32_t StartOfMip = 0; int mip; for(mip = 0; mip < MaxMip; mip++) { GMM_REQ_OFFSET_INFO OffsetInfo = {}; OffsetInfo.ReqRender = 1; OffsetInfo.MipLevel = mip; ResourceInfo->GetOffset(OffsetInfo); StartOfMip += (mip == 0 ? 0 : GMM_ULT_ALIGN(gmmParams.BaseWidth64 >> (mip - 1), TileSize[i]) * GetBppValue(bpp)); EXPECT_EQ(StartOfMip, OffsetInfo.Render.Offset64); EXPECT_EQ(0, OffsetInfo.Render.XOffset); EXPECT_EQ(0, OffsetInfo.Render.YOffset); EXPECT_EQ(0, OffsetInfo.Render.ZOffset); } uint32_t MipTailOffsets[12] = {2048, 1024, 768, 512, 448, 384, 320, 256, 192, 128, 64, 0}; // Check for offset inside miptails. EXPECT_EQ(MipTailStart, ResourceInfo->GetPackedMipTailStartLod()); StartOfMip += GMM_ULT_ALIGN(gmmParams.BaseWidth64 >> (mip - 1), TileSize[i]) * GetBppValue(bpp); // Start of MipTail for(int slot = 0; mip <= gmmParams.MaxLod; mip++, slot++) { GMM_REQ_OFFSET_INFO OffsetInfo = {}; OffsetInfo.ReqRender = 1; OffsetInfo.MipLevel = mip; ResourceInfo->GetOffset(OffsetInfo); EXPECT_EQ(StartOfMip, OffsetInfo.Render.Offset64); // Start of Miptail EXPECT_EQ(MipTailOffsets[slot], OffsetInfo.Render.XOffset); // Offset within miptail EXPECT_EQ(0, OffsetInfo.Render.YOffset); EXPECT_EQ(0, OffsetInfo.Render.ZOffset); } pGmmULTClientContext->DestroyResInfoObject(ResourceInfo); } } // ********************************************************************************// /// @brief ULT for 2D TileYs Resource TEST_F(CTestGen9Resource, Test2DTileYsResource) { const uint32_t HAlign[TEST_BPP_MAX] = {256, 256, 128, 128, 64}; const uint32_t VAlign[TEST_BPP_MAX] = {256, 128, 128, 64, 64}; const uint32_t TileSize[TEST_BPP_MAX][2] = {{256, 256}, {512, 128}, {512, 128}, {1024, 64}, {1024, 64}}; GMM_RESCREATE_PARAMS gmmParams = {}; gmmParams.Type = RESOURCE_2D; gmmParams.NoGfxMemory = 1; gmmParams.Flags.Info.TiledY = 1; gmmParams.Flags.Info.TiledYs = 1; gmmParams.Flags.Gpu.Texture = 1; //Allocate 1x1 surface for(uint32_t i = 0; i < TEST_BPP_MAX; i++) { TEST_BPP bpp = static_cast(i); gmmParams.Format = SetResourceFormat(bpp); gmmParams.BaseWidth64 = 0x1; gmmParams.BaseHeight = 0x1; GMM_RESOURCE_INFO *ResourceInfo; ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); VerifyResourceHAlign(ResourceInfo, HAlign[i]); VerifyResourceVAlign(ResourceInfo, VAlign[i]); VerifyResourcePitch(ResourceInfo, TileSize[i][0]); // As wide as 1 Tile VerifyResourcePitchInTiles(ResourceInfo, 1); // 1 Tile wide VerifyResourceSize(ResourceInfo, GMM_KBYTE(64)); // 1 Tile Big VerifyResourceQPitch(ResourceInfo, 0); // Not Tested pGmmULTClientContext->DestroyResInfoObject(ResourceInfo); } // Allocate surface that requires multi tiles in two dimension // Allocate 2 tiles in X dimension for(uint32_t i = 0; i < TEST_BPP_MAX; i++) { TEST_BPP bpp = static_cast(i); gmmParams.Format = SetResourceFormat(bpp); gmmParams.BaseWidth64 = (TileSize[i][0] / GetBppValue(bpp)) + 1; // 1 pixel larger than 1 tile width gmmParams.BaseHeight = 0x1; gmmParams.Depth = 0x1; GMM_RESOURCE_INFO *ResourceInfo; ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); VerifyResourceHAlign(ResourceInfo, HAlign[i]); VerifyResourceVAlign(ResourceInfo, VAlign[i]); VerifyResourcePitch(ResourceInfo, TileSize[i][0] * 2); // As wide as 2 tile VerifyResourcePitchInTiles(ResourceInfo, 2); // 2 tile wide VerifyResourceSize(ResourceInfo, GMM_KBYTE(64) * 2); // 2 tile big VerifyResourceQPitch(ResourceInfo, 0); // Not tested pGmmULTClientContext->DestroyResInfoObject(ResourceInfo); } // Allocate 2 tiles in X/Y dimension for(uint32_t i = 0; i < TEST_BPP_MAX; i++) { TEST_BPP bpp = static_cast(i); gmmParams.Format = SetResourceFormat(bpp); gmmParams.BaseWidth64 = (TileSize[i][0] / GetBppValue(bpp)) + 1; // 1 pixel larger than 1 tile width gmmParams.BaseHeight = TileSize[i][1] + 1; // 1 row larger than 1 tile height gmmParams.Depth = 0x1; GMM_RESOURCE_INFO *ResourceInfo; ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); VerifyResourceHAlign(ResourceInfo, HAlign[i]); VerifyResourceVAlign(ResourceInfo, VAlign[i]); VerifyResourcePitch(ResourceInfo, TileSize[i][0] * 2); // As wide as 2 tile VerifyResourcePitchInTiles(ResourceInfo, 2); // 2 tile wide VerifyResourceSize(ResourceInfo, GMM_KBYTE(64) * 4); // 4 tile big VerifyResourceQPitch(ResourceInfo, 0); // Not tested pGmmULTClientContext->DestroyResInfoObject(ResourceInfo); } } /// @brief ULT for 2D TileYs Resource with Mips TEST_F(CTestGen9Resource, Test2DTileYsMippedResource) { const uint32_t HAlign[TEST_BPP_MAX] = {256, 256, 128, 128, 64}; const uint32_t VAlign[TEST_BPP_MAX] = {256, 128, 128, 64, 64}; const uint32_t TileSize[TEST_BPP_MAX][2] = {{256, 256}, {512, 128}, {512, 128}, {1024, 64}, {1024, 64}}; const uint32_t MtsWidth[TEST_BPP_MAX] = {128, 128, 64, 64, 32}; const uint32_t MtsHeight[TEST_BPP_MAX] = {256, 128, 128, 64, 64}; GMM_RESCREATE_PARAMS gmmParams = {}; gmmParams.Type = RESOURCE_2D; gmmParams.NoGfxMemory = 1; gmmParams.Flags.Info.TiledY = 1; gmmParams.Flags.Info.TiledYs = 1; gmmParams.Flags.Gpu.Texture = 1; gmmParams.MaxLod = 5; gmmParams.ArraySize = 4; for(uint32_t i = 0; i < TEST_BPP_MAX; i++) { uint32_t AlignedWidth = 0; uint32_t AlignedHeight = 0; uint32_t ExpectedPitch = 0; uint32_t MipTailStartLod = 0; // Valigned Mip Heights uint32_t Mip0Height = 0; uint32_t Mip1Height = 0; uint32_t Mip2Height = 0; uint32_t Mip3Height = 0; uint32_t Mip2Higher = 0; // Sum of aligned heights of Mip2 and above uint32_t MipTailHeight = 0; // Haligned Mip Widths uint32_t Mip0Width = 0; uint32_t Mip1Width = 0; uint32_t Mip2Width = 0; TEST_BPP bpp = static_cast(i); gmmParams.Format = SetResourceFormat(bpp); gmmParams.BaseWidth64 = 0x120; gmmParams.BaseHeight = 0x120; GMM_RESOURCE_INFO *ResourceInfo; ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); VerifyResourceHAlign(ResourceInfo, HAlign[i]); VerifyResourceVAlign(ResourceInfo, VAlign[i]); // find the miptail start level { uint32_t MipWidth = gmmParams.BaseWidth64; uint32_t MipHeight = gmmParams.BaseHeight; while(!(MipWidth <= MtsWidth[i] && MipHeight <= MtsHeight[i])) { MipTailStartLod++; MipWidth = (uint32_t)(GMM_ULT_MAX(1, gmmParams.BaseWidth64 >> MipTailStartLod)); MipHeight = GMM_ULT_MAX(1, gmmParams.BaseHeight >> MipTailStartLod); } } // Mip resource Aligned Width calculation Mip0Width = GMM_ULT_ALIGN(gmmParams.BaseWidth64, HAlign[i]); Mip1Width = GMM_ULT_ALIGN(gmmParams.BaseWidth64 >> 1, HAlign[i]); Mip2Width = GMM_ULT_ALIGN(gmmParams.BaseWidth64 >> 2, HAlign[i]); AlignedWidth = GMM_ULT_MAX(Mip0Width, Mip1Width + Mip2Width); Mip0Height = GMM_ULT_ALIGN(gmmParams.BaseHeight, VAlign[i]); if(MipTailStartLod == 2) { EXPECT_EQ(2, ResourceInfo->GetPackedMipTailStartLod()); // Block height...Mip0Height + Max(Mip1Height, Sum of Mip2Height..MipnHeight) Mip1Height = GMM_ULT_ALIGN(gmmParams.BaseHeight >> 1, VAlign[i]); Mip2Height = Mip2Higher = GMM_ULT_ALIGN(gmmParams.BaseHeight >> 2, VAlign[i]); } else if(MipTailStartLod == 3) { EXPECT_EQ(3, ResourceInfo->GetPackedMipTailStartLod()); // Block height...Mip0Height + Max(Mip1Height, Sum of Mip2Height..MipnHeight) Mip1Height = GMM_ULT_ALIGN(gmmParams.BaseHeight >> 1, VAlign[i]); Mip2Height = GMM_ULT_ALIGN(gmmParams.BaseHeight >> 2, VAlign[i]); // Miptail started lod MipTailHeight = VAlign[i]; Mip2Higher = Mip2Height + MipTailHeight; } else if(MipTailStartLod == 4) { EXPECT_EQ(4, ResourceInfo->GetPackedMipTailStartLod()); // Block height...Mip0Height + Max(Mip1Height, Sum of Mip2Height..MipnHeight) Mip1Height = GMM_ULT_ALIGN(gmmParams.BaseHeight >> 1, VAlign[i]); Mip2Height = GMM_ULT_ALIGN(gmmParams.BaseHeight >> 2, VAlign[i]); Mip3Height = GMM_ULT_ALIGN(gmmParams.BaseHeight >> 3, VAlign[i]); // Miptail started lod MipTailHeight = VAlign[i]; Mip2Higher = Mip2Height + Mip3Height + MipTailHeight; } uint32_t MaxHeight = GMM_ULT_MAX(Mip1Height, Mip2Higher); AlignedHeight = Mip0Height + MaxHeight; AlignedHeight = GMM_ULT_ALIGN(AlignedHeight, VAlign[i]); ExpectedPitch = AlignedWidth * GetBppValue(bpp); ExpectedPitch = GMM_ULT_ALIGN(ExpectedPitch, GMM_BYTES(32)); VerifyResourcePitch(ResourceInfo, ExpectedPitch); VerifyResourcePitchInTiles(ResourceInfo, static_cast(ExpectedPitch / TileSize[i][0])); VerifyResourceSize(ResourceInfo, GMM_ULT_ALIGN(ExpectedPitch * AlignedHeight * gmmParams.ArraySize, PAGE_SIZE)); VerifyResourceQPitch(ResourceInfo, AlignedHeight); // Mip 0 offsets, offset is 0,0 GMM_REQ_OFFSET_INFO ReqInfo = {0}; ReqInfo.MipLevel = 0; ReqInfo.ReqRender = 1; ResourceInfo->GetOffset(ReqInfo); uint32_t Mip0Size = ExpectedPitch * Mip0Height; EXPECT_EQ(0, ReqInfo.Render.Offset64); EXPECT_EQ(0, ReqInfo.Render.XOffset); EXPECT_EQ(0, ReqInfo.Render.YOffset); // Mip 1 offsets ReqInfo = {0}; ReqInfo.MipLevel = 1; ReqInfo.ReqRender = 1; ResourceInfo->GetOffset(ReqInfo); uint32_t Mip1Offset = Mip0Size; EXPECT_EQ(Mip1Offset, ReqInfo.Render.Offset64); EXPECT_EQ(0, ReqInfo.Render.XOffset); EXPECT_EQ(0, ReqInfo.Render.YOffset); // Mip 2 offset ReqInfo = {0}; ReqInfo.MipLevel = 2; ReqInfo.ReqRender = 1; ResourceInfo->GetOffset(ReqInfo); uint32_t Mip2Offset = Mip1Width * GetBppValue(bpp) + Mip0Height * ExpectedPitch; uint32_t Mip2X = GFX_ALIGN_FLOOR(uint32_t(Mip2Offset % ExpectedPitch), TileSize[i][0]); uint32_t Mip2Y = GFX_ALIGN_FLOOR(uint32_t(Mip2Offset / ExpectedPitch), TileSize[i][1]); uint32_t Mip2RenderAlignedOffset = Mip2Y * ExpectedPitch + (Mip2X / TileSize[i][0]) * (TileSize[i][0] * TileSize[i][1]); EXPECT_EQ(Mip2RenderAlignedOffset, ReqInfo.Render.Offset64); switch(bpp) { case TEST_BPP_8: EXPECT_EQ(128, ReqInfo.Render.XOffset); EXPECT_EQ(0, ReqInfo.Render.YOffset); break; case TEST_BPP_16: EXPECT_EQ(256, ReqInfo.Render.XOffset); EXPECT_EQ(0, ReqInfo.Render.YOffset); break; case TEST_BPP_32: EXPECT_EQ(0, ReqInfo.Render.XOffset); EXPECT_EQ(0, ReqInfo.Render.YOffset); break; case TEST_BPP_64: EXPECT_EQ(0, ReqInfo.Render.XOffset); EXPECT_EQ(0, ReqInfo.Render.YOffset); break; case TEST_BPP_128: EXPECT_EQ(0, ReqInfo.Render.XOffset); EXPECT_EQ(0, ReqInfo.Render.YOffset); break; default: break; } // Mip 3 offset ReqInfo = {0}; ReqInfo.MipLevel = 3; ReqInfo.ReqRender = 1; ResourceInfo->GetOffset(ReqInfo); uint32_t Mip3Offset = 0; switch(bpp) { case TEST_BPP_8: Mip3Offset = Mip1Width * GetBppValue(bpp) + Mip0Height * ExpectedPitch; EXPECT_EQ(0, ReqInfo.Render.XOffset); EXPECT_EQ(128, ReqInfo.Render.YOffset); break; case TEST_BPP_16: Mip3Offset = Mip1Width * GetBppValue(bpp) + Mip0Height * ExpectedPitch; EXPECT_EQ(0, ReqInfo.Render.XOffset); EXPECT_EQ(64, ReqInfo.Render.YOffset); break; case TEST_BPP_32: Mip3Offset = Mip1Width * GetBppValue(bpp) + (Mip0Height + Mip2Height) * ExpectedPitch; EXPECT_EQ(256, ReqInfo.Render.XOffset); EXPECT_EQ(0, ReqInfo.Render.YOffset); break; case TEST_BPP_64: Mip3Offset = Mip1Width * GetBppValue(bpp) + (Mip0Height + Mip2Height) * ExpectedPitch; EXPECT_EQ(512, ReqInfo.Render.XOffset); EXPECT_EQ(0, ReqInfo.Render.YOffset); break; case TEST_BPP_128: Mip3Offset = Mip1Width * GetBppValue(bpp) + (Mip0Height + Mip2Height) * ExpectedPitch; EXPECT_EQ(0, ReqInfo.Render.XOffset); EXPECT_EQ(0, ReqInfo.Render.YOffset); break; default: break; } uint32_t Mip3X = GFX_ALIGN_FLOOR(uint32_t(Mip3Offset % ExpectedPitch), TileSize[i][0]); uint32_t Mip3Y = GFX_ALIGN_FLOOR(uint32_t(Mip3Offset / ExpectedPitch), TileSize[i][1]); uint32_t Mip3RenderAlignedOffset = Mip3Y * ExpectedPitch + (Mip3X / TileSize[i][0]) * (TileSize[i][0] * TileSize[i][1]); EXPECT_EQ(Mip3RenderAlignedOffset, ReqInfo.Render.Offset64); // Mip 4 offset ReqInfo = {0}; ReqInfo.MipLevel = 4; ReqInfo.ReqRender = 1; ResourceInfo->GetOffset(ReqInfo); uint32_t Mip4Offset = 0; switch(bpp) { case TEST_BPP_8: Mip4Offset = Mip1Width * GetBppValue(bpp) + Mip0Height * ExpectedPitch; EXPECT_EQ(64, ReqInfo.Render.XOffset); EXPECT_EQ(0, ReqInfo.Render.YOffset); break; case TEST_BPP_16: Mip4Offset = Mip1Width * GetBppValue(bpp) + Mip0Height * ExpectedPitch; EXPECT_EQ(128, ReqInfo.Render.XOffset); EXPECT_EQ(0, ReqInfo.Render.YOffset); break; case TEST_BPP_32: Mip4Offset = Mip1Width * GetBppValue(bpp) + (Mip0Height + Mip2Height) * ExpectedPitch; EXPECT_EQ(0, ReqInfo.Render.XOffset); EXPECT_EQ(64, ReqInfo.Render.YOffset); break; case TEST_BPP_64: Mip4Offset = Mip1Width * GetBppValue(bpp) + (Mip0Height + Mip2Height) * ExpectedPitch; EXPECT_EQ(0, ReqInfo.Render.XOffset); EXPECT_EQ(32, ReqInfo.Render.YOffset); break; case TEST_BPP_128: Mip4Offset = Mip1Width * GetBppValue(bpp) + (Mip0Height + Mip2Height + Mip3Height) * ExpectedPitch; EXPECT_EQ(512, ReqInfo.Render.XOffset); EXPECT_EQ(0, ReqInfo.Render.YOffset); break; default: break; } uint32_t Mip4X = GFX_ALIGN_FLOOR(uint32_t(Mip4Offset % ExpectedPitch), TileSize[i][0]); uint32_t Mip4Y = GFX_ALIGN_FLOOR(uint32_t(Mip4Offset / ExpectedPitch), TileSize[i][1]); uint32_t Mip4RenderAlignedOffset = Mip4Y * ExpectedPitch + (Mip4X / TileSize[i][0]) * (TileSize[i][0] * TileSize[i][1]); EXPECT_EQ(Mip4RenderAlignedOffset, ReqInfo.Render.Offset64); // Mip 5 offset ReqInfo = {0}; ReqInfo.MipLevel = 4; ReqInfo.ReqRender = 1; ResourceInfo->GetOffset(ReqInfo); uint32_t Mip5Offset = 0; switch(bpp) { case TEST_BPP_8: Mip5Offset = Mip1Width * GetBppValue(bpp) + Mip0Height * ExpectedPitch; EXPECT_EQ(64, ReqInfo.Render.XOffset); EXPECT_EQ(0, ReqInfo.Render.YOffset); break; case TEST_BPP_16: Mip5Offset = Mip1Width * GetBppValue(bpp) + Mip0Height * ExpectedPitch; EXPECT_EQ(128, ReqInfo.Render.XOffset); EXPECT_EQ(0, ReqInfo.Render.YOffset); break; case TEST_BPP_32: Mip5Offset = Mip1Width * GetBppValue(bpp) + (Mip0Height + Mip2Height) * ExpectedPitch; EXPECT_EQ(0, ReqInfo.Render.XOffset); EXPECT_EQ(64, ReqInfo.Render.YOffset); break; case TEST_BPP_64: Mip5Offset = Mip1Width * GetBppValue(bpp) + (Mip0Height + Mip2Height) * ExpectedPitch; EXPECT_EQ(0, ReqInfo.Render.XOffset); EXPECT_EQ(32, ReqInfo.Render.YOffset); break; case TEST_BPP_128: Mip5Offset = Mip1Width * GetBppValue(bpp) + (Mip0Height + Mip2Height + Mip3Height) * ExpectedPitch; EXPECT_EQ(512, ReqInfo.Render.XOffset); EXPECT_EQ(0, ReqInfo.Render.YOffset); break; default: break; } uint32_t Mip5X = GFX_ALIGN_FLOOR(uint32_t(Mip4Offset % ExpectedPitch), TileSize[i][0]); uint32_t Mip5Y = GFX_ALIGN_FLOOR(uint32_t(Mip4Offset / ExpectedPitch), TileSize[i][1]); uint32_t Mip5RenderAlignedOffset = Mip5Y * ExpectedPitch + (Mip5X / TileSize[i][0]) * (TileSize[i][0] * TileSize[i][1]); EXPECT_EQ(Mip5RenderAlignedOffset, ReqInfo.Render.Offset64); pGmmULTClientContext->DestroyResInfoObject(ResourceInfo); } } /// @brief ULT for 2D TileYf Resource TEST_F(CTestGen9Resource, Test2DTileYfResource) { const uint32_t HAlign[TEST_BPP_MAX] = {64, 64, 32, 32, 16}; const uint32_t VAlign[TEST_BPP_MAX] = {64, 32, 32, 16, 16}; const uint32_t TileSize[TEST_BPP_MAX][2] = {{64, 64}, {128, 32}, {128, 32}, {256, 16}, {256, 16}}; GMM_RESCREATE_PARAMS gmmParams = {}; gmmParams.Type = RESOURCE_2D; gmmParams.NoGfxMemory = 1; gmmParams.Flags.Info.TiledY = 1; gmmParams.Flags.Info.TiledYf = 1; gmmParams.Flags.Gpu.Texture = 1; //Allocate 1x1 surface for(uint32_t i = 0; i < TEST_BPP_MAX; i++) { TEST_BPP bpp = static_cast(i); gmmParams.Format = SetResourceFormat(bpp); gmmParams.BaseWidth64 = 0x1; gmmParams.BaseHeight = 0x1; GMM_RESOURCE_INFO *ResourceInfo; ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); VerifyResourceHAlign(ResourceInfo, HAlign[i]); VerifyResourceVAlign(ResourceInfo, VAlign[i]); VerifyResourcePitch(ResourceInfo, TileSize[i][0]); // As wide as 1 Tile VerifyResourcePitchInTiles(ResourceInfo, 1); // 1 Tile wide VerifyResourceSize(ResourceInfo, GMM_KBYTE(4)); // 1 Tile Big VerifyResourceQPitch(ResourceInfo, 0); // Not Tested pGmmULTClientContext->DestroyResInfoObject(ResourceInfo); } // Allocate surface that requires multi tiles in two dimension // Allocate 2 tiles in X dimension for(uint32_t i = 0; i < TEST_BPP_MAX; i++) { TEST_BPP bpp = static_cast(i); gmmParams.Format = SetResourceFormat(bpp); gmmParams.BaseWidth64 = (TileSize[i][0] / GetBppValue(bpp)) + 1; // 1 pixel larger than 1 tile width gmmParams.BaseHeight = 0x1; gmmParams.Depth = 0x1; GMM_RESOURCE_INFO *ResourceInfo; ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); VerifyResourceHAlign(ResourceInfo, HAlign[i]); VerifyResourceVAlign(ResourceInfo, VAlign[i]); VerifyResourcePitch(ResourceInfo, TileSize[i][0] * 2); // As wide as 2 tile VerifyResourcePitchInTiles(ResourceInfo, 2); // 2 tile wide VerifyResourceSize(ResourceInfo, GMM_KBYTE(4) * 2); // 2 tile big VerifyResourceQPitch(ResourceInfo, 0); // Not tested pGmmULTClientContext->DestroyResInfoObject(ResourceInfo); } // Allocate 2 tiles in X/Y dimension for(uint32_t i = 0; i < TEST_BPP_MAX; i++) { TEST_BPP bpp = static_cast(i); gmmParams.Format = SetResourceFormat(bpp); gmmParams.BaseWidth64 = (TileSize[i][0] / GetBppValue(bpp)) + 1; // 1 pixel larger than 1 tile width gmmParams.BaseHeight = TileSize[i][1] + 1; // 1 row larger than 1 tile height gmmParams.Depth = 0x1; GMM_RESOURCE_INFO *ResourceInfo; ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); VerifyResourceHAlign(ResourceInfo, HAlign[i]); VerifyResourceVAlign(ResourceInfo, VAlign[i]); VerifyResourcePitch(ResourceInfo, TileSize[i][0] * 2); // As wide as 2 tile VerifyResourcePitchInTiles(ResourceInfo, 2); // 2 tile wide VerifyResourceSize(ResourceInfo, GMM_KBYTE(4) * 4); // 4 tile big VerifyResourceQPitch(ResourceInfo, 0); // Not tested pGmmULTClientContext->DestroyResInfoObject(ResourceInfo); } } /// @brief ULT for 2D TileYf Mipped Resource TEST_F(CTestGen9Resource, Test2DTileYfMippedResource) { const uint32_t HAlign[TEST_BPP_MAX] = {64, 64, 32, 32, 16}; const uint32_t VAlign[TEST_BPP_MAX] = {64, 32, 32, 16, 16}; const uint32_t TileSize[TEST_BPP_MAX][2] = {{64, 64}, {128, 32}, {128, 32}, {256, 16}, {256, 16}}; const uint32_t MtsWidth[TEST_BPP_MAX] = {32, 32, 16, 16, 8}; const uint32_t MtsHeight[TEST_BPP_MAX] = {64, 32, 32, 16, 16}; GMM_RESCREATE_PARAMS gmmParams = {}; gmmParams.Type = RESOURCE_2D; gmmParams.NoGfxMemory = 1; gmmParams.Flags.Info.TiledY = 1; gmmParams.Flags.Info.TiledYf = 1; gmmParams.Flags.Gpu.Texture = 1; gmmParams.MaxLod = 4; gmmParams.ArraySize = 4; for(uint32_t i = 0; i < TEST_BPP_MAX; i++) { uint32_t AlignedWidth = 0; uint32_t AlignedHeight = 0; uint32_t ExpectedPitch = 0; uint32_t MipTailStartLod = 0; // Valigned Mip Heights uint32_t Mip0Height = 0; uint32_t Mip1Height = 0; uint32_t Mip2Height = 0; uint32_t Mip3Height = 0; uint32_t Mip2Higher = 0; // Sum of aligned heights of Mip2 and above uint32_t MipTailHeight = 0; // Haligned Mip Widths uint32_t Mip0Width = 0; uint32_t Mip1Width = 0; uint32_t Mip2Width = 0; TEST_BPP bpp = static_cast(i); gmmParams.Format = SetResourceFormat(bpp); gmmParams.BaseWidth64 = 0x38; gmmParams.BaseHeight = 0x38; GMM_RESOURCE_INFO *ResourceInfo; ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); VerifyResourceHAlign(ResourceInfo, HAlign[i]); VerifyResourceVAlign(ResourceInfo, VAlign[i]); // find the miptail start level { uint32_t MipWidth = gmmParams.BaseWidth64; uint32_t MipHeight = gmmParams.BaseHeight; while(!(MipWidth <= MtsWidth[i] && MipHeight <= MtsHeight[i])) { MipTailStartLod++; MipWidth = (uint32_t)(GMM_ULT_MAX(1, gmmParams.BaseWidth64 >> MipTailStartLod)); MipHeight = GMM_ULT_MAX(1, gmmParams.BaseHeight >> MipTailStartLod); } } // Mip resource Aligned Width calculation Mip0Width = GMM_ULT_ALIGN(gmmParams.BaseWidth64, HAlign[i]); Mip0Height = GMM_ULT_ALIGN(gmmParams.BaseHeight, VAlign[i]); if(MipTailStartLod == 1) { EXPECT_EQ(1, ResourceInfo->GetPackedMipTailStartLod()); // Block height...Mip0Height + Max(Mip1Height, Sum of Mip2Height..MipnHeight) Mip1Height = GMM_ULT_ALIGN(gmmParams.BaseHeight >> 1, VAlign[i]); AlignedWidth = Mip0Width; } if(MipTailStartLod == 2) { EXPECT_EQ(2, ResourceInfo->GetPackedMipTailStartLod()); // Block height...Mip0Height + Max(Mip1Height, Sum of Mip2Height..MipnHeight) Mip1Height = GMM_ULT_ALIGN(gmmParams.BaseHeight >> 1, VAlign[i]); Mip2Height = Mip2Higher = GMM_ULT_ALIGN(gmmParams.BaseHeight >> 2, VAlign[i]); Mip1Width = GMM_ULT_ALIGN(gmmParams.BaseWidth64 >> 1, HAlign[i]); Mip2Width = GMM_ULT_ALIGN(gmmParams.BaseWidth64 >> 2, HAlign[i]); AlignedWidth = GMM_ULT_MAX(Mip0Width, Mip1Width + Mip2Width); } if(MipTailStartLod == 3) { EXPECT_EQ(3, ResourceInfo->GetPackedMipTailStartLod()); // Block height...Mip0Height + Max(Mip1Height, Sum of Mip2Height..MipnHeight) Mip1Height = GMM_ULT_ALIGN(gmmParams.BaseHeight >> 1, VAlign[i]); Mip2Height = GMM_ULT_ALIGN(gmmParams.BaseHeight >> 2, VAlign[i]); // Miptail started lod MipTailHeight = VAlign[i]; Mip2Higher = Mip2Height + Mip3Height + MipTailHeight; Mip1Width = GMM_ULT_ALIGN(gmmParams.BaseWidth64 >> 1, HAlign[i]); Mip2Width = GMM_ULT_ALIGN(gmmParams.BaseWidth64 >> 2, HAlign[i]); AlignedWidth = GMM_ULT_MAX(Mip0Width, Mip1Width + Mip2Width); } uint32_t MaxHeight = GMM_ULT_MAX(Mip1Height, Mip2Higher); AlignedHeight = Mip0Height + MaxHeight; AlignedHeight = GMM_ULT_ALIGN(AlignedHeight, VAlign[i]); ExpectedPitch = AlignedWidth * GetBppValue(bpp); ExpectedPitch = GMM_ULT_ALIGN(ExpectedPitch, GMM_BYTES(32)); VerifyResourcePitch(ResourceInfo, ExpectedPitch); VerifyResourcePitchInTiles(ResourceInfo, static_cast(ExpectedPitch / TileSize[i][0])); VerifyResourceSize(ResourceInfo, GMM_ULT_ALIGN(ExpectedPitch * AlignedHeight * gmmParams.ArraySize, PAGE_SIZE)); VerifyResourceQPitch(ResourceInfo, AlignedHeight); // Mip 0 offsets, offset is 0,0 GMM_REQ_OFFSET_INFO ReqInfo = {0}; ReqInfo.MipLevel = 0; ReqInfo.ReqRender = 1; ResourceInfo->GetOffset(ReqInfo); uint32_t Mip0Size = ExpectedPitch * Mip0Height; EXPECT_EQ(0, ReqInfo.Render.Offset64); EXPECT_EQ(0, ReqInfo.Render.XOffset); EXPECT_EQ(0, ReqInfo.Render.YOffset); // Mip 1 offsets ReqInfo = {0}; ReqInfo.MipLevel = 1; ReqInfo.ReqRender = 1; ResourceInfo->GetOffset(ReqInfo); uint32_t Mip1Offset = Mip0Size; switch(bpp) { case TEST_BPP_8: EXPECT_EQ(32, ReqInfo.Render.XOffset); EXPECT_EQ(0, ReqInfo.Render.YOffset); break; case TEST_BPP_16: EXPECT_EQ(64, ReqInfo.Render.XOffset); EXPECT_EQ(0, ReqInfo.Render.YOffset); break; case TEST_BPP_32: EXPECT_EQ(0, ReqInfo.Render.XOffset); EXPECT_EQ(0, ReqInfo.Render.YOffset); break; case TEST_BPP_64: EXPECT_EQ(0, ReqInfo.Render.XOffset); EXPECT_EQ(0, ReqInfo.Render.YOffset); break; case TEST_BPP_128: EXPECT_EQ(0, ReqInfo.Render.XOffset); EXPECT_EQ(0, ReqInfo.Render.YOffset); break; default: break; } EXPECT_EQ(Mip1Offset, ReqInfo.Render.Offset64); // Mip 2 offset ReqInfo = {0}; ReqInfo.MipLevel = 2; ReqInfo.ReqRender = 1; ResourceInfo->GetOffset(ReqInfo); uint32_t Mip2Offset = Mip1Width * GetBppValue(bpp) + Mip0Height * ExpectedPitch; switch(bpp) { case TEST_BPP_8: EXPECT_EQ(16, ReqInfo.Render.XOffset); EXPECT_EQ(32, ReqInfo.Render.YOffset); break; case TEST_BPP_16: EXPECT_EQ(32, ReqInfo.Render.XOffset); EXPECT_EQ(16, ReqInfo.Render.YOffset); break; case TEST_BPP_32: EXPECT_EQ(64, ReqInfo.Render.XOffset); EXPECT_EQ(0, ReqInfo.Render.YOffset); break; case TEST_BPP_64: EXPECT_EQ(128, ReqInfo.Render.XOffset); EXPECT_EQ(0, ReqInfo.Render.YOffset); break; case TEST_BPP_128: EXPECT_EQ(0, ReqInfo.Render.XOffset); EXPECT_EQ(0, ReqInfo.Render.YOffset); break; default: break; } uint32_t Mip2X = GFX_ALIGN_FLOOR(uint32_t(Mip2Offset % ExpectedPitch), TileSize[i][0]); uint32_t Mip2Y = GFX_ALIGN_FLOOR(uint32_t(Mip2Offset / ExpectedPitch), TileSize[i][1]); uint32_t Mip2RenderAlignedOffset = Mip2Y * ExpectedPitch + (Mip2X / TileSize[i][0]) * (TileSize[i][0] * TileSize[i][1]); EXPECT_EQ(Mip2RenderAlignedOffset, ReqInfo.Render.Offset64); // Mip 3 offset ReqInfo = {0}; ReqInfo.MipLevel = 3; ReqInfo.ReqRender = 1; ResourceInfo->GetOffset(ReqInfo); uint32_t Mip3Offset = 0; switch(bpp) { case TEST_BPP_8: Mip3Offset = Mip1Width * GetBppValue(bpp) + Mip0Height * ExpectedPitch; EXPECT_EQ(0, ReqInfo.Render.XOffset); EXPECT_EQ(48, ReqInfo.Render.YOffset); break; case TEST_BPP_16: Mip3Offset = Mip1Width * GetBppValue(bpp) + Mip0Height * ExpectedPitch; EXPECT_EQ(0, ReqInfo.Render.XOffset); EXPECT_EQ(24, ReqInfo.Render.YOffset); break; case TEST_BPP_32: Mip3Offset = Mip1Width * GetBppValue(bpp) + Mip0Height * ExpectedPitch; EXPECT_EQ(32, ReqInfo.Render.XOffset); EXPECT_EQ(16, ReqInfo.Render.YOffset); break; case TEST_BPP_64: Mip3Offset = Mip1Width * GetBppValue(bpp) + Mip0Height * ExpectedPitch; EXPECT_EQ(64, ReqInfo.Render.XOffset); EXPECT_EQ(8, ReqInfo.Render.YOffset); break; case TEST_BPP_128: Mip3Offset = Mip1Width * GetBppValue(bpp) + (Mip0Height + Mip2Height) * ExpectedPitch; EXPECT_EQ(128, ReqInfo.Render.XOffset); EXPECT_EQ(0, ReqInfo.Render.YOffset); break; default: break; } uint32_t Mip3X = GFX_ALIGN_FLOOR(uint32_t(Mip3Offset % ExpectedPitch), TileSize[i][0]); uint32_t Mip3Y = GFX_ALIGN_FLOOR(uint32_t(Mip3Offset / ExpectedPitch), TileSize[i][1]); uint32_t Mip3RenderAlignedOffset = Mip3Y * ExpectedPitch + (Mip3X / TileSize[i][0]) * (TileSize[i][0] * TileSize[i][1]); EXPECT_EQ(Mip3RenderAlignedOffset, ReqInfo.Render.Offset64); // Mip 4 offset ReqInfo = {0}; ReqInfo.MipLevel = 4; ReqInfo.ReqRender = 1; ResourceInfo->GetOffset(ReqInfo); uint32_t Mip4Offset = 0; switch(bpp) { case TEST_BPP_8: Mip4Offset = Mip1Width * GetBppValue(bpp) + Mip0Height * ExpectedPitch; EXPECT_EQ(0, ReqInfo.Render.XOffset); EXPECT_EQ(32, ReqInfo.Render.YOffset); break; case TEST_BPP_16: Mip4Offset = Mip1Width * GetBppValue(bpp) + Mip0Height * ExpectedPitch; EXPECT_EQ(0, ReqInfo.Render.XOffset); EXPECT_EQ(16, ReqInfo.Render.YOffset); break; case TEST_BPP_32: Mip4Offset = Mip1Width * GetBppValue(bpp) + Mip0Height * ExpectedPitch; EXPECT_EQ(0, ReqInfo.Render.XOffset); EXPECT_EQ(24, ReqInfo.Render.YOffset); break; case TEST_BPP_64: Mip4Offset = Mip1Width * GetBppValue(bpp) + Mip0Height * ExpectedPitch; EXPECT_EQ(0, ReqInfo.Render.XOffset); EXPECT_EQ(12, ReqInfo.Render.YOffset); break; case TEST_BPP_128: Mip4Offset = Mip1Width * GetBppValue(bpp) + (Mip0Height + Mip2Height) * ExpectedPitch; EXPECT_EQ(64, ReqInfo.Render.XOffset); EXPECT_EQ(8, ReqInfo.Render.YOffset); break; default: break; } uint32_t Mip4X = GFX_ALIGN_FLOOR(uint32_t(Mip4Offset % ExpectedPitch), TileSize[i][0]); uint32_t Mip4Y = GFX_ALIGN_FLOOR(uint32_t(Mip4Offset / ExpectedPitch), TileSize[i][1]); uint32_t Mip4RenderAlignedOffset = Mip4Y * ExpectedPitch + (Mip4X / TileSize[i][0]) * (TileSize[i][0] * TileSize[i][1]); EXPECT_EQ(Mip4RenderAlignedOffset, ReqInfo.Render.Offset64); pGmmULTClientContext->DestroyResInfoObject(ResourceInfo); } } /// @brief ULT for 2D Stencil (TileW) Mipped-array Resource TEST_F(CTestGen9Resource, Test2DStencilMippedArrayedResource) { const uint32_t HAlign = {8}; const uint32_t VAlign = {8}; const uint32_t TileSize[2] = {64, 64}; //TileW GMM_RESCREATE_PARAMS gmmParams = {}; gmmParams.Type = RESOURCE_2D; gmmParams.NoGfxMemory = 1; gmmParams.Flags.Info.TiledW = 1; gmmParams.Flags.Gpu.SeparateStencil = 1; gmmParams.MaxLod = 4; gmmParams.ArraySize = 4; //for(uint32_t i = 0; i < TEST_BPP_MAX; i++) { uint32_t AlignedWidth = 0; uint32_t AlignedHeight = 0; uint32_t ExpectedPitch = 0; // Valigned Mip Heights uint32_t Mip0Height = 0; uint32_t Mip1Height = 0; uint32_t Mip2Height = 0; // Haligned Mip Widths uint32_t Mip0Width = 0; uint32_t Mip1Width = 0; uint32_t Mip2Width = 0; TEST_BPP bpp = TEST_BPP_8; gmmParams.Format = SetResourceFormat(bpp); gmmParams.BaseWidth64 = 0x10; gmmParams.BaseHeight = 0x10; GMM_RESOURCE_INFO *ResourceInfo; ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); VerifyResourceHAlign(ResourceInfo, HAlign); VerifyResourceVAlign(ResourceInfo, VAlign); // Mip resource Aligned Width calculation Mip0Width = GMM_ULT_ALIGN(gmmParams.BaseWidth64, HAlign); Mip0Height = GMM_ULT_ALIGN(gmmParams.BaseHeight, VAlign); for(uint32_t i = 1; i <= gmmParams.MaxLod; i++) { uint32_t MipWidth = GMM_ULT_ALIGN(GMM_ULT_MAX(Mip0Width >> i, 1), HAlign); uint32_t MipHeight = GMM_ULT_ALIGN(GMM_ULT_MAX(Mip0Height >> i, 1), VAlign); if(i == 1) { Mip1Width = AlignedWidth = MipWidth; Mip1Height = MipHeight; } else if(i == 2) { AlignedWidth += MipWidth; Mip2Height = MipHeight; } else { Mip2Height += MipHeight; } } uint32_t MaxHeight = GMM_ULT_MAX(Mip1Height, Mip2Height); AlignedHeight = Mip0Height + MaxHeight; ExpectedPitch = GMM_ULT_MAX(AlignedWidth, Mip0Width) * GetBppValue(bpp); ExpectedPitch = GMM_ULT_ALIGN(ExpectedPitch, TileSize[0]); //TileW is programmed as row-interleaved.. ie doubled pitch VerifyResourcePitch(ResourceInfo, ExpectedPitch * 2); VerifyResourcePitchInTiles(ResourceInfo, static_cast(ExpectedPitch / TileSize[0])); VerifyResourceSize(ResourceInfo, GMM_ULT_ALIGN(ExpectedPitch * AlignedHeight * gmmParams.ArraySize, PAGE_SIZE)); VerifyResourceQPitch(ResourceInfo, AlignedHeight); for(uint8_t i = 0; i < gmmParams.ArraySize && gmmParams.MaxLod >= 4; i++) { uint64_t ArrayOffset = AlignedHeight * ExpectedPitch * i; // Mip 0 offsets, offset is 0,0 GMM_REQ_OFFSET_INFO ReqInfo = {0}; ReqInfo.MipLevel = 0; ReqInfo.ReqRender = 1; ReqInfo.ArrayIndex = i; ResourceInfo->GetOffset(ReqInfo); uint32_t Mip0Size = ExpectedPitch * Mip0Height; uint64_t SliceTileOffset = GFX_ALIGN_FLOOR(AlignedHeight * i, TileSize[1]) * TileSize[0]; uint32_t SliceY = (AlignedHeight * i) % TileSize[1]; EXPECT_EQ(SliceTileOffset, ReqInfo.Render.Offset64); EXPECT_EQ(0, ReqInfo.Render.XOffset); EXPECT_EQ(SliceY, ReqInfo.Render.YOffset); // Mip 1 offsets ReqInfo = {0}; ReqInfo.MipLevel = 1; ReqInfo.ReqRender = 1; ReqInfo.ArrayIndex = i; ResourceInfo->GetOffset(ReqInfo); uint32_t Mip1Offset = Mip0Size + ArrayOffset; uint32_t Mip1X = uint32_t(Mip1Offset % ExpectedPitch); uint32_t Mip1Y = uint32_t(Mip1Offset / ExpectedPitch); EXPECT_EQ(0, ReqInfo.Render.XOffset); EXPECT_EQ(Mip1Y % TileSize[1], ReqInfo.Render.YOffset); Mip1X = GFX_ALIGN_FLOOR(Mip1X, TileSize[0]); Mip1Y = GFX_ALIGN_FLOOR(Mip1Y, TileSize[1]); uint32_t Mip1RenderAlignedOffset = Mip1Y * ExpectedPitch + (Mip1X / TileSize[0]) * (TileSize[0] * TileSize[1]); EXPECT_EQ(Mip1RenderAlignedOffset, ReqInfo.Render.Offset64); // Mip 2 offset ReqInfo = {0}; ReqInfo.MipLevel = 2; ReqInfo.ReqRender = 1; ReqInfo.ArrayIndex = i; ResourceInfo->GetOffset(ReqInfo); uint32_t Mip2Offset = Mip1Width * GetBppValue(bpp) + Mip0Height * ExpectedPitch + ArrayOffset; uint32_t Mip2X = uint32_t(Mip2Offset % ExpectedPitch); uint32_t Mip2Y = uint32_t(Mip2Offset / ExpectedPitch); EXPECT_EQ(8, ReqInfo.Render.XOffset); EXPECT_EQ(Mip2Y % TileSize[1], ReqInfo.Render.YOffset); Mip2X = GFX_ALIGN_FLOOR(Mip2X, TileSize[0]); Mip2Y = GFX_ALIGN_FLOOR(Mip2Y, TileSize[1]); uint32_t Mip2RenderAlignedOffset = Mip2Y * ExpectedPitch + (Mip2X / TileSize[0]) * (TileSize[0] * TileSize[1]); EXPECT_EQ(Mip2RenderAlignedOffset, ReqInfo.Render.Offset64); // Mip 3 offset ReqInfo = {0}; ReqInfo.MipLevel = 3; ReqInfo.ReqRender = 1; ReqInfo.ArrayIndex = i; ResourceInfo->GetOffset(ReqInfo); uint32_t Mip3Offset = Mip1Width * GetBppValue(bpp) + (Mip0Height + GMM_ULT_ALIGN(Mip0Height >> 2, VAlign)) * ExpectedPitch + ArrayOffset; uint32_t Mip3X = uint32_t(Mip3Offset % ExpectedPitch); uint32_t Mip3Y = uint32_t(Mip3Offset / ExpectedPitch); EXPECT_EQ(8, ReqInfo.Render.XOffset); EXPECT_EQ(Mip3Y % TileSize[1], ReqInfo.Render.YOffset); Mip3X = GFX_ALIGN_FLOOR(Mip3X, TileSize[0]); Mip3Y = GFX_ALIGN_FLOOR(Mip3Y, TileSize[1]); uint32_t Mip3RenderAlignedOffset = Mip3Y * ExpectedPitch + (Mip3X / TileSize[0]) * (TileSize[0] * TileSize[1]); EXPECT_EQ(Mip3RenderAlignedOffset, ReqInfo.Render.Offset64); // Mip 4 offset ReqInfo = {0}; ReqInfo.MipLevel = 4; ReqInfo.ReqRender = 1; ReqInfo.ArrayIndex = i; ResourceInfo->GetOffset(ReqInfo); uint32_t Mip4Offset = 0; Mip4Offset = Mip1Width * GetBppValue(bpp) + (Mip0Height + GMM_ULT_ALIGN(Mip0Height >> 2, VAlign) + GMM_ULT_ALIGN(Mip0Height >> 3, VAlign)) * ExpectedPitch + ArrayOffset; uint32_t Mip4X = uint32_t(Mip4Offset % ExpectedPitch); uint32_t Mip4Y = uint32_t(Mip4Offset / ExpectedPitch); EXPECT_EQ(8, ReqInfo.Render.XOffset); EXPECT_EQ(Mip4Y % TileSize[1], ReqInfo.Render.YOffset); Mip4X = GFX_ALIGN_FLOOR(Mip4X, TileSize[0]); Mip4Y = GFX_ALIGN_FLOOR(Mip4Y, TileSize[1]); uint32_t Mip4RenderAlignedOffset = Mip4Y * ExpectedPitch + (Mip4X / TileSize[0]) * (TileSize[0] * TileSize[1]); EXPECT_EQ(Mip4RenderAlignedOffset, ReqInfo.Render.Offset64); } pGmmULTClientContext->DestroyResInfoObject(ResourceInfo); } } /// @brief ULT for 2D Stencil (TileW) Mipped-array Resource, and CpuBlt TEST_F(CTestGen9Resource, Test2DStencilArrayedCpuBltResource) { const uint32_t HAlign = {8}; const uint32_t VAlign = {8}; const uint32_t TileSize[2] = {64, 64}; //TileW GMM_RESCREATE_PARAMS gmmParams = {}; gmmParams.Type = RESOURCE_2D; gmmParams.NoGfxMemory = 1; gmmParams.Flags.Info.TiledW = 1; gmmParams.Flags.Gpu.SeparateStencil = 1; gmmParams.MaxLod = 0; gmmParams.ArraySize = 6; { uint32_t AlignedWidth = 0; uint32_t AlignedHeight = 0; uint32_t ExpectedPitch = 0; // Valigned Mip Heights uint32_t Mip0Height = 0; uint32_t Mip1Height = 0; uint32_t Mip2Height = 0; // Haligned Mip Widths uint32_t Mip0Width = 0; uint32_t Mip1Width = 0; uint32_t Mip2Width = 0; TEST_BPP bpp = TEST_BPP_8; gmmParams.Format = SetResourceFormat(bpp); gmmParams.BaseWidth64 = 0x4; gmmParams.BaseHeight = 0x4; GMM_RESOURCE_INFO *ResourceInfo; ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); VerifyResourceHAlign(ResourceInfo, HAlign); VerifyResourceVAlign(ResourceInfo, VAlign); // Mip resource Aligned Width calculation Mip0Width = GMM_ULT_ALIGN(gmmParams.BaseWidth64, HAlign); Mip0Height = GMM_ULT_ALIGN(gmmParams.BaseHeight, VAlign); for(uint32_t i = 1; i <= gmmParams.MaxLod; i++) { uint32_t MipWidth = GMM_ULT_ALIGN(GMM_ULT_MAX(Mip0Width >> i, 1), HAlign); uint32_t MipHeight = GMM_ULT_ALIGN(GMM_ULT_MAX(Mip0Height >> i, 1), VAlign); if(i == 1) { Mip1Width = AlignedWidth = MipWidth; Mip1Height = MipHeight; } else if(i == 2) { AlignedWidth += MipWidth; Mip2Height = MipHeight; } else { Mip2Height += MipHeight; } } uint32_t MaxHeight = GMM_ULT_MAX(Mip1Height, Mip2Height); AlignedHeight = Mip0Height + MaxHeight; ExpectedPitch = GMM_ULT_MAX(AlignedWidth, Mip0Width) * GetBppValue(bpp); ExpectedPitch = GMM_ULT_ALIGN(ExpectedPitch, TileSize[0]); //TileW is programmed as row-interleaved.. ie doubled pitch VerifyResourcePitch(ResourceInfo, ExpectedPitch * 2); VerifyResourcePitchInTiles(ResourceInfo, static_cast(ExpectedPitch / TileSize[0])); VerifyResourceSize(ResourceInfo, GMM_ULT_ALIGN(ExpectedPitch * AlignedHeight * gmmParams.ArraySize, PAGE_SIZE)); VerifyResourceQPitch(ResourceInfo, AlignedHeight); for(uint8_t i = 0; i < gmmParams.ArraySize && gmmParams.MaxLod >= 4; i++) { uint64_t ArrayOffset = AlignedHeight * ExpectedPitch * i; // Mip 0 offsets, offset is 0,0 GMM_REQ_OFFSET_INFO ReqInfo = {0}; ReqInfo.MipLevel = 0; ReqInfo.ReqRender = 1; ReqInfo.ArrayIndex = i; ResourceInfo->GetOffset(ReqInfo); uint32_t Mip0Size = ExpectedPitch * Mip0Height; uint64_t SliceTileOffset = GFX_ALIGN_FLOOR(AlignedHeight * i, TileSize[1]) * TileSize[0]; uint32_t SliceY = (AlignedHeight * i) % TileSize[1]; EXPECT_EQ(SliceTileOffset, ReqInfo.Render.Offset64); EXPECT_EQ(0, ReqInfo.Render.XOffset); EXPECT_EQ(SliceY, ReqInfo.Render.YOffset); // Mip 1 offsets ReqInfo = {0}; ReqInfo.MipLevel = 1; ReqInfo.ReqRender = 1; ReqInfo.ArrayIndex = i; ResourceInfo->GetOffset(ReqInfo); uint32_t Mip1Offset = Mip0Size + ArrayOffset; uint32_t Mip1X = uint32_t(Mip1Offset % ExpectedPitch); uint32_t Mip1Y = uint32_t(Mip1Offset / ExpectedPitch); EXPECT_EQ(0, ReqInfo.Render.XOffset); EXPECT_EQ(Mip1Y % TileSize[1], ReqInfo.Render.YOffset); Mip1X = GFX_ALIGN_FLOOR(Mip1X, TileSize[0]); Mip1Y = GFX_ALIGN_FLOOR(Mip1Y, TileSize[1]); uint32_t Mip1RenderAlignedOffset = Mip1Y * ExpectedPitch + (Mip1X / TileSize[0]) * (TileSize[0] * TileSize[1]); EXPECT_EQ(Mip1RenderAlignedOffset, ReqInfo.Render.Offset64); // Mip 2 offset ReqInfo = {0}; ReqInfo.MipLevel = 2; ReqInfo.ReqRender = 1; ReqInfo.ArrayIndex = i; ResourceInfo->GetOffset(ReqInfo); uint32_t Mip2Offset = Mip1Width * GetBppValue(bpp) + Mip0Height * ExpectedPitch + ArrayOffset; uint32_t Mip2X = uint32_t(Mip2Offset % ExpectedPitch); uint32_t Mip2Y = uint32_t(Mip2Offset / ExpectedPitch); EXPECT_EQ(8, ReqInfo.Render.XOffset); EXPECT_EQ(Mip2Y % TileSize[1], ReqInfo.Render.YOffset); Mip2X = GFX_ALIGN_FLOOR(Mip2X, TileSize[0]); Mip2Y = GFX_ALIGN_FLOOR(Mip2Y, TileSize[1]); uint32_t Mip2RenderAlignedOffset = Mip2Y * ExpectedPitch + (Mip2X / TileSize[0]) * (TileSize[0] * TileSize[1]); EXPECT_EQ(Mip2RenderAlignedOffset, ReqInfo.Render.Offset64); // Mip 3 offset ReqInfo = {0}; ReqInfo.MipLevel = 3; ReqInfo.ReqRender = 1; ReqInfo.ArrayIndex = i; ResourceInfo->GetOffset(ReqInfo); uint32_t Mip3Offset = Mip1Width * GetBppValue(bpp) + (Mip0Height + GMM_ULT_ALIGN(Mip0Height >> 2, VAlign)) * ExpectedPitch + ArrayOffset; uint32_t Mip3X = uint32_t(Mip3Offset % ExpectedPitch); uint32_t Mip3Y = uint32_t(Mip3Offset / ExpectedPitch); EXPECT_EQ(8, ReqInfo.Render.XOffset); EXPECT_EQ(Mip3Y % TileSize[1], ReqInfo.Render.YOffset); Mip3X = GFX_ALIGN_FLOOR(Mip3X, TileSize[0]); Mip3Y = GFX_ALIGN_FLOOR(Mip3Y, TileSize[1]); uint32_t Mip3RenderAlignedOffset = Mip3Y * ExpectedPitch + (Mip3X / TileSize[0]) * (TileSize[0] * TileSize[1]); EXPECT_EQ(Mip3RenderAlignedOffset, ReqInfo.Render.Offset64); // Mip 4 offset ReqInfo = {0}; ReqInfo.MipLevel = 4; ReqInfo.ReqRender = 1; ReqInfo.ArrayIndex = i; ResourceInfo->GetOffset(ReqInfo); uint32_t Mip4Offset = 0; Mip4Offset = Mip1Width * GetBppValue(bpp) + (Mip0Height + GMM_ULT_ALIGN(Mip0Height >> 2, VAlign) + GMM_ULT_ALIGN(Mip0Height >> 3, VAlign)) * ExpectedPitch + ArrayOffset; uint32_t Mip4X = uint32_t(Mip4Offset % ExpectedPitch); uint32_t Mip4Y = uint32_t(Mip4Offset / ExpectedPitch); EXPECT_EQ(8, ReqInfo.Render.XOffset); EXPECT_EQ(Mip4Y % TileSize[1], ReqInfo.Render.YOffset); Mip4X = GFX_ALIGN_FLOOR(Mip4X, TileSize[0]); Mip4Y = GFX_ALIGN_FLOOR(Mip4Y, TileSize[1]); uint32_t Mip4RenderAlignedOffset = Mip4Y * ExpectedPitch + (Mip4X / TileSize[0]) * (TileSize[0] * TileSize[1]); EXPECT_EQ(Mip4RenderAlignedOffset, ReqInfo.Render.Offset64); } //Verify CpuBlt path (uses Render offset for upload) { #ifdef _WIN32 #define ULT_ALIGNED_MALLOC(Size, alignBytes) _aligned_malloc(Size, alignBytes) #define ULT_ALIGNED_FREE(ptr) _aligned_free(ptr) #else #define ULT_ALIGNED_MALLOC(Size, alignBytes) memalign(alignBytes, Size) #define ULT_ALIGNED_FREE(ptr) free(ptr) #endif #ifdef _WIN32 void *LockVA = ULT_ALIGNED_MALLOC(ResourceInfo->GetSizeSurface(), ResourceInfo->GetBaseAlignment()); memset(LockVA, 0, ResourceInfo->GetSizeSurface()); void *Sysmem = malloc(gmmParams.BaseWidth64 * gmmParams.BaseHeight); memset(Sysmem, 0xbb, gmmParams.BaseWidth64 * gmmParams.BaseHeight); //Test Upload GMM_RES_COPY_BLT Blt = {0}; Blt.Gpu.pData = LockVA; Blt.Gpu.Slice = 4; Blt.Gpu.MipLevel = 0; Blt.Sys.BufferSize = gmmParams.BaseWidth64 * gmmParams.BaseHeight; Blt.Sys.pData = Sysmem; Blt.Sys.RowPitch = gmmParams.BaseWidth64; Blt.Sys.PixelPitch = 1; Blt.Sys.SlicePitch = Blt.Sys.BufferSize; Blt.Blt.Upload = 1; Blt.Blt.BytesPerPixel = 1; ResourceInfo->CpuBlt(&Blt); uint64_t Offset = 0x100; /*Blt.Gpu.Slice * ResourceInfo->GetQPitchInBytes();*/ // Need SwizzledOffset for(uint8_t byte = 0; byte < Blt.Sys.BufferSize; byte++) { uint8_t *Byte = ((uint8_t *)LockVA) + Offset + byte; EXPECT_EQ(Byte[0], 0xbb); } free(Sysmem); ULT_ALIGNED_FREE(LockVA); #endif } pGmmULTClientContext->DestroyResInfoObject(ResourceInfo); } } /// @brief ULT for 3D Stencil (TileW) Mipped-array Resource TEST_F(CTestGen9Resource, Test3DStencilMippedResource) { const uint32_t HAlign = {8}; const uint32_t VAlign = {8}; const uint32_t TileSize[2] = {64, 64}; //TileW GMM_RESCREATE_PARAMS gmmParams = {}; gmmParams.Type = RESOURCE_3D; gmmParams.NoGfxMemory = 1; gmmParams.Flags.Info.TiledW = 1; gmmParams.Flags.Gpu.SeparateStencil = 1; gmmParams.MaxLod = 4; { uint32_t AlignedWidth = 0; uint32_t AlignedHeight = 0; uint32_t ExpectedPitch = 0; // Valigned Mip Heights uint32_t Mip0Height = 0; uint32_t Mip1Height = 0; uint32_t Mip2Height = 0; // Haligned Mip Widths uint32_t Mip0Width = 0; uint32_t Mip1Width = 0; uint32_t Mip2Width = 0; TEST_BPP bpp = TEST_BPP_8; gmmParams.Format = SetResourceFormat(bpp); gmmParams.BaseWidth64 = 0x10; gmmParams.BaseHeight = 0x10; gmmParams.Depth = 0x10; GMM_RESOURCE_INFO *ResourceInfo; ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); VerifyResourceHAlign(ResourceInfo, HAlign); VerifyResourceVAlign(ResourceInfo, VAlign); // Mip resource Aligned Width calculation Mip0Width = GMM_ULT_ALIGN(gmmParams.BaseWidth64, HAlign); Mip0Height = GMM_ULT_ALIGN(gmmParams.BaseHeight, VAlign); for(uint32_t i = 1; i <= gmmParams.MaxLod; i++) { uint32_t MipWidth = GMM_ULT_ALIGN(Mip0Width >> i, HAlign); uint32_t MipHeight = GMM_ULT_ALIGN(Mip0Height >> i, VAlign); if(i == 1) { Mip1Width = AlignedWidth = MipWidth; Mip1Height = MipHeight; } else if(i == 2) { AlignedWidth += MipWidth; Mip2Height = MipHeight; } else { Mip2Height += MipHeight; } } uint32_t MaxHeight = GMM_ULT_MAX(Mip1Height, Mip2Height); AlignedHeight = Mip0Height + MaxHeight; ExpectedPitch = AlignedWidth * GetBppValue(bpp); ExpectedPitch = GMM_ULT_ALIGN(ExpectedPitch, TileSize[0]); //TileW is programmed as row-interleaved.. ie doubled pitch VerifyResourcePitch(ResourceInfo, ExpectedPitch * 2); VerifyResourcePitchInTiles(ResourceInfo, static_cast(ExpectedPitch / TileSize[0])); VerifyResourceSize(ResourceInfo, GMM_ULT_ALIGN(ExpectedPitch * AlignedHeight, PAGE_SIZE) * gmmParams.Depth); //3D QPitch must be aligned to Tile-height, div by 2 for Pitch is doubled // i.e. Slice-offset = Qpitch*Pitch is tile-aligned. AlignedHeight = GMM_ULT_ALIGN(AlignedHeight, TileSize[1]); VerifyResourceQPitch(ResourceInfo, AlignedHeight / 2); for(uint8_t i = 0; i < gmmParams.Depth; i++) { uint64_t SliceOffset = AlignedHeight * ExpectedPitch; // Mip 0 offsets, offset is 0,0 GMM_REQ_OFFSET_INFO ReqInfo = {0}; ReqInfo.MipLevel = 0; ReqInfo.ReqRender = 1; ReqInfo.Slice = i; ResourceInfo->GetOffset(ReqInfo); uint32_t Mip0Size = ExpectedPitch * Mip0Height; EXPECT_EQ((0 + SliceOffset * i), ReqInfo.Render.Offset64); EXPECT_EQ(0, ReqInfo.Render.XOffset); EXPECT_EQ(0, ReqInfo.Render.YOffset); // Mip 1 offsets -- uses 2d mip layout ReqInfo = {0}; ReqInfo.MipLevel = 1; ReqInfo.ReqRender = 1; ReqInfo.Slice = i; ResourceInfo->GetOffset(ReqInfo); uint32_t Mip1Offset = Mip0Size; uint32_t Mip1X = GFX_ALIGN_FLOOR(uint32_t(Mip1Offset % ExpectedPitch), TileSize[0]); uint32_t Mip1Y = GFX_ALIGN_FLOOR(uint32_t(Mip1Offset / ExpectedPitch), TileSize[1]); uint32_t Mip1RenderAlignedOffset = Mip1Y * ExpectedPitch + (Mip1X / TileSize[0]) * (TileSize[0] * TileSize[1]) + SliceOffset * i; EXPECT_EQ(0, ReqInfo.Render.XOffset); EXPECT_EQ(16, ReqInfo.Render.YOffset); EXPECT_EQ(Mip1RenderAlignedOffset, ReqInfo.Render.Offset64); // Mip 2 offset ReqInfo = {0}; ReqInfo.MipLevel = 2; ReqInfo.ReqRender = 1; ReqInfo.Slice = i; ResourceInfo->GetOffset(ReqInfo); uint32_t Mip2Offset = Mip1Width * GetBppValue(bpp) + (Mip0Height * ExpectedPitch) + SliceOffset * i; EXPECT_EQ(8, ReqInfo.Render.XOffset); EXPECT_EQ(16, ReqInfo.Render.YOffset); uint32_t Mip2X = GFX_ALIGN_FLOOR(uint32_t(Mip2Offset % ExpectedPitch), TileSize[0]); uint32_t Mip2Y = GFX_ALIGN_FLOOR(uint32_t(Mip2Offset / ExpectedPitch), TileSize[1]); uint32_t Mip2RenderAlignedOffset = Mip2Y * ExpectedPitch + (Mip2X / TileSize[0]) * (TileSize[0] * TileSize[1]); EXPECT_EQ(Mip2RenderAlignedOffset, ReqInfo.Render.Offset64); // Mip 3 offset ReqInfo = {0}; ReqInfo.MipLevel = 3; ReqInfo.ReqRender = 1; ReqInfo.Slice = i; ResourceInfo->GetOffset(ReqInfo); uint32_t Mip3Offset = 0; Mip3Offset = Mip1Width * GetBppValue(bpp) + Mip0Height * ExpectedPitch; EXPECT_EQ(8, ReqInfo.Render.XOffset); EXPECT_EQ(24, ReqInfo.Render.YOffset); uint32_t Mip3X = GFX_ALIGN_FLOOR(uint32_t(Mip3Offset % ExpectedPitch), TileSize[0]); uint32_t Mip3Y = GFX_ALIGN_FLOOR(uint32_t(Mip3Offset / ExpectedPitch), TileSize[1]); uint32_t Mip3RenderAlignedOffset = Mip3Y * ExpectedPitch + (Mip3X / TileSize[0]) * (TileSize[0] * TileSize[1]) + SliceOffset * i; EXPECT_EQ(Mip3RenderAlignedOffset, ReqInfo.Render.Offset64); // Mip 4 offset ReqInfo = {0}; ReqInfo.MipLevel = 4; ReqInfo.ReqRender = 1; ReqInfo.Slice = i; ResourceInfo->GetOffset(ReqInfo); uint32_t Mip4Offset = 0; Mip4Offset = Mip1Width * GetBppValue(bpp) + Mip0Height * ExpectedPitch; EXPECT_EQ(8, ReqInfo.Render.XOffset); EXPECT_EQ(32, ReqInfo.Render.YOffset); uint32_t Mip4X = GFX_ALIGN_FLOOR(uint32_t(Mip4Offset % ExpectedPitch), TileSize[0]); uint32_t Mip4Y = GFX_ALIGN_FLOOR(uint32_t(Mip4Offset / ExpectedPitch), TileSize[1]); uint32_t Mip4RenderAlignedOffset = Mip4Y * ExpectedPitch + (Mip4X / TileSize[0]) * (TileSize[0] * TileSize[1]) + SliceOffset * i; EXPECT_EQ(Mip4RenderAlignedOffset, ReqInfo.Render.Offset64); } pGmmULTClientContext->DestroyResInfoObject(ResourceInfo); } } // ********************************************************************************// /// @brief ULT for 3D Linear Resource TEST_F(CTestGen9Resource, Test3DLinearResource) { // Horizontal/Vertical pixel alignment const uint32_t HAlign = 16; const uint32_t VAlign = 4; GMM_RESCREATE_PARAMS gmmParams = {}; gmmParams.Type = RESOURCE_3D; gmmParams.NoGfxMemory = 1; gmmParams.Flags.Info.Linear = 1; gmmParams.Flags.Gpu.Texture = 1; // Allocate 1x1x1 surface for(uint32_t i = 0; i < TEST_BPP_MAX; i++) { TEST_BPP bpp = static_cast(i); gmmParams.Format = SetResourceFormat(bpp); gmmParams.BaseWidth64 = 0x1; gmmParams.BaseHeight = 0x1; gmmParams.Depth = 0x1; const uint32_t MinPitch = 32; const uint32_t PitchAlignment = 32; GMM_RESOURCE_INFO *ResourceInfo; ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); const uint32_t AlignedWidth = GMM_ULT_ALIGN(gmmParams.BaseWidth64, HAlign); const uint32_t AlignedHeight = GMM_ULT_ALIGN(gmmParams.BaseHeight, VAlign); uint32_t PitchInBytes = AlignedWidth * GetBppValue(bpp); PitchInBytes = GMM_ULT_MAX(PitchInBytes, MinPitch); PitchInBytes = GMM_ULT_ALIGN(PitchInBytes, PitchAlignment); const uint32_t AlignedSize = GMM_ULT_ALIGN(PitchInBytes * AlignedHeight, PAGE_SIZE); VerifyResourceHAlign(ResourceInfo, HAlign); VerifyResourceVAlign(ResourceInfo, VAlign); VerifyResourcePitch(ResourceInfo, PitchInBytes); VerifyResourceSize(ResourceInfo, AlignedSize); VerifyResourceQPitch(ResourceInfo, AlignedHeight); pGmmULTClientContext->DestroyResInfoObject(ResourceInfo); } // Allocate 256 x 256 x 256 for(uint32_t i = 0; i < TEST_BPP_MAX; i++) { TEST_BPP bpp = static_cast(i); gmmParams.Format = SetResourceFormat(bpp); gmmParams.BaseWidth64 = 256; gmmParams.BaseHeight = 256; gmmParams.Depth = 256; const uint32_t MinPitch = 32; const uint32_t PitchAlignment = 32; GMM_RESOURCE_INFO *ResourceInfo; ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); const uint32_t AlignedWidth = GMM_ULT_ALIGN(gmmParams.BaseWidth64, HAlign); const uint32_t AlignedHeight = GMM_ULT_ALIGN(gmmParams.BaseHeight, VAlign); uint32_t PitchInBytes = AlignedWidth * GetBppValue(bpp); PitchInBytes = GFX_MAX(PitchInBytes, MinPitch); PitchInBytes = GMM_ULT_ALIGN(PitchInBytes, PitchAlignment); const uint32_t AlignedSize = GMM_ULT_ALIGN(PitchInBytes * AlignedHeight * gmmParams.Depth, PAGE_SIZE); VerifyResourceHAlign(ResourceInfo, HAlign); VerifyResourceVAlign(ResourceInfo, VAlign); VerifyResourcePitch(ResourceInfo, PitchInBytes); VerifyResourceSize(ResourceInfo, AlignedSize); VerifyResourceQPitch(ResourceInfo, AlignedHeight); pGmmULTClientContext->DestroyResInfoObject(ResourceInfo); } } /// @brief ULT for 3D TileX Resource TEST_F(CTestGen9Resource, Test3DTileXResource) { // Horizontal/Vertical pixel alignment const uint32_t HAlign = 16; const uint32_t VAlign = 4; const uint32_t TileSize[TEST_BPP_MAX][3] = {{512, 8, 1}, {512, 8, 1}, {512, 8, 1}, {512, 8, 1}, {512, 8, 1}}; GMM_RESCREATE_PARAMS gmmParams = {}; gmmParams.Type = RESOURCE_3D; gmmParams.NoGfxMemory = 1; gmmParams.Flags.Info.TiledX = 1; gmmParams.Flags.Gpu.Texture = 1; // Allocate 1x1x1 surface for(uint32_t i = 0; i < TEST_BPP_MAX; i++) { TEST_BPP bpp = static_cast(i); gmmParams.Format = SetResourceFormat(bpp); gmmParams.BaseWidth64 = 0x1; gmmParams.BaseHeight = 0x1; gmmParams.Depth = 0x1; GMM_RESOURCE_INFO *ResourceInfo; ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); VerifyResourceHAlign(ResourceInfo, HAlign); VerifyResourceVAlign(ResourceInfo, VAlign); VerifyResourcePitch(ResourceInfo, TileSize[i][0]); VerifyResourcePitchInTiles(ResourceInfo, 1); VerifyResourceSize(ResourceInfo, GMM_KBYTE(4)); VerifyResourceQPitch(ResourceInfo, TileSize[i][1]); pGmmULTClientContext->DestroyResInfoObject(ResourceInfo); } // Allocate 2 tiles in X dimension for(uint32_t i = 0; i < TEST_BPP_MAX; i++) { TEST_BPP bpp = static_cast(i); gmmParams.Format = SetResourceFormat(bpp); gmmParams.BaseWidth64 = (TileSize[i][0] / GetBppValue(bpp)) + 1; gmmParams.BaseHeight = 0x1; gmmParams.Depth = 0x1; GMM_RESOURCE_INFO *ResourceInfo; ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); VerifyResourceHAlign(ResourceInfo, HAlign); VerifyResourceVAlign(ResourceInfo, VAlign); VerifyResourcePitch(ResourceInfo, 2 * TileSize[i][0]); VerifyResourcePitchInTiles(ResourceInfo, 2); VerifyResourceSize(ResourceInfo, 2 * GMM_KBYTE(4)); VerifyResourceQPitch(ResourceInfo, TileSize[i][1]); pGmmULTClientContext->DestroyResInfoObject(ResourceInfo); } // Allocate 2 tiles in X/Y dimension for(uint32_t i = 0; i < TEST_BPP_MAX; i++) { TEST_BPP bpp = static_cast(i); gmmParams.Format = SetResourceFormat(bpp); gmmParams.BaseWidth64 = (TileSize[i][0] / GetBppValue(bpp)) + 1; gmmParams.BaseHeight = TileSize[i][1] + 1; gmmParams.Depth = 0x1; GMM_RESOURCE_INFO *ResourceInfo; ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); VerifyResourceHAlign(ResourceInfo, HAlign); VerifyResourceVAlign(ResourceInfo, VAlign); VerifyResourcePitch(ResourceInfo, 2 * TileSize[i][0]); VerifyResourcePitchInTiles(ResourceInfo, 2); VerifyResourceSize(ResourceInfo, 2 * 2 * GMM_KBYTE(4)); VerifyResourceQPitch(ResourceInfo, 2 * TileSize[i][1]); pGmmULTClientContext->DestroyResInfoObject(ResourceInfo); } // Allocate 2 tiles in X/Y/Z dimension for(uint32_t i = 0; i < TEST_BPP_MAX; i++) { TEST_BPP bpp = static_cast(i); gmmParams.Format = SetResourceFormat(bpp); gmmParams.BaseWidth64 = (TileSize[i][0] / GetBppValue(bpp)) + 1; gmmParams.BaseHeight = TileSize[i][1] + 1; gmmParams.Depth = TileSize[i][2] + 1; GMM_RESOURCE_INFO *ResourceInfo; ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); VerifyResourceHAlign(ResourceInfo, HAlign); VerifyResourceVAlign(ResourceInfo, VAlign); VerifyResourcePitch(ResourceInfo, 2 * TileSize[i][0]); VerifyResourcePitchInTiles(ResourceInfo, 2); VerifyResourceSize(ResourceInfo, 2 * 2 * 2 * GMM_KBYTE(4)); VerifyResourceQPitch(ResourceInfo, 2 * TileSize[i][1]); pGmmULTClientContext->DestroyResInfoObject(ResourceInfo); } } /// @brief ULT for 3D TileY Resource TEST_F(CTestGen9Resource, Test3DTileYResource) { // Horizontal/Vertical pixel alignment const uint32_t HAlign = 16; const uint32_t VAlign = 4; const uint32_t TileSize[TEST_BPP_MAX][3] = {{128, 32, 1}, {128, 32, 1}, {128, 32, 1}, {128, 32, 1}, {128, 32, 1}}; GMM_RESCREATE_PARAMS gmmParams = {}; gmmParams.Type = RESOURCE_3D; gmmParams.NoGfxMemory = 1; gmmParams.Flags.Info.TiledY = 1; gmmParams.Flags.Gpu.Texture = 1; // Allocate 1x1x1 surface for(uint32_t i = 0; i < TEST_BPP_MAX; i++) { TEST_BPP bpp = static_cast(i); gmmParams.Format = SetResourceFormat(bpp); gmmParams.BaseWidth64 = 0x1; gmmParams.BaseHeight = 0x1; gmmParams.Depth = 0x1; const uint32_t MinPitch = 32; const uint32_t PitchAlignment = 32; GMM_RESOURCE_INFO *ResourceInfo; ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); const uint32_t AlignedWidth = GMM_ULT_ALIGN(gmmParams.BaseWidth64, HAlign); uint32_t PitchInBytes = AlignedWidth * GetBppValue(bpp); PitchInBytes = GFX_MAX(PitchInBytes, MinPitch); PitchInBytes = GMM_ULT_ALIGN(PitchInBytes, PitchAlignment); PitchInBytes = GMM_ULT_ALIGN(PitchInBytes, TileSize[i][0]); VerifyResourceHAlign(ResourceInfo, HAlign); VerifyResourceVAlign(ResourceInfo, VAlign); VerifyResourcePitch(ResourceInfo, PitchInBytes); VerifyResourcePitchInTiles(ResourceInfo, PitchInBytes / TileSize[i][0]); VerifyResourceSize(ResourceInfo, PitchInBytes / TileSize[i][0] * GMM_KBYTE(4)); VerifyResourceQPitch(ResourceInfo, TileSize[i][1]); pGmmULTClientContext->DestroyResInfoObject(ResourceInfo); } // Allocate 2 tiles in X dimension for(uint32_t i = 0; i < TEST_BPP_MAX; i++) { TEST_BPP bpp = static_cast(i); gmmParams.Format = SetResourceFormat(bpp); gmmParams.BaseWidth64 = (TileSize[i][0] / GetBppValue(bpp)) + 1; gmmParams.BaseHeight = 0x1; gmmParams.Depth = 0x1; const uint32_t MinPitch = 32; const uint32_t PitchAlignment = 32; GMM_RESOURCE_INFO *ResourceInfo; ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); const uint32_t AlignedWidth = GMM_ULT_ALIGN(gmmParams.BaseWidth64, HAlign); uint32_t PitchInBytes = AlignedWidth * GetBppValue(bpp); PitchInBytes = GFX_MAX(PitchInBytes, MinPitch); PitchInBytes = GMM_ULT_ALIGN(PitchInBytes, PitchAlignment); PitchInBytes = GMM_ULT_ALIGN(PitchInBytes, TileSize[i][0]); VerifyResourceHAlign(ResourceInfo, HAlign); VerifyResourceVAlign(ResourceInfo, VAlign); VerifyResourcePitch(ResourceInfo, PitchInBytes); VerifyResourcePitchInTiles(ResourceInfo, PitchInBytes / TileSize[i][0]); VerifyResourceSize(ResourceInfo, PitchInBytes / TileSize[i][0] * GMM_KBYTE(4)); VerifyResourceQPitch(ResourceInfo, TileSize[i][1]); pGmmULTClientContext->DestroyResInfoObject(ResourceInfo); } // Allocate 2 tiles in X/Y dimension for(uint32_t i = 0; i < TEST_BPP_MAX; i++) { TEST_BPP bpp = static_cast(i); gmmParams.Format = SetResourceFormat(bpp); gmmParams.BaseWidth64 = (TileSize[i][0] / GetBppValue(bpp)) + 1; gmmParams.BaseHeight = TileSize[i][1] + 1; gmmParams.Depth = 0x1; const uint32_t MinPitch = 32; const uint32_t PitchAlignment = 32; GMM_RESOURCE_INFO *ResourceInfo; ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); const uint32_t AlignedWidth = GMM_ULT_ALIGN(gmmParams.BaseWidth64, HAlign); uint32_t PitchInBytes = AlignedWidth * GetBppValue(bpp); PitchInBytes = GFX_MAX(PitchInBytes, MinPitch); PitchInBytes = GMM_ULT_ALIGN(PitchInBytes, PitchAlignment); PitchInBytes = GMM_ULT_ALIGN(PitchInBytes, TileSize[i][0]); VerifyResourceHAlign(ResourceInfo, HAlign); VerifyResourceVAlign(ResourceInfo, VAlign); VerifyResourcePitch(ResourceInfo, PitchInBytes); VerifyResourcePitchInTiles(ResourceInfo, PitchInBytes / TileSize[i][0]); VerifyResourceSize(ResourceInfo, PitchInBytes / TileSize[i][0] * 2 * GMM_KBYTE(4)); VerifyResourceQPitch(ResourceInfo, TileSize[i][1] * 2); pGmmULTClientContext->DestroyResInfoObject(ResourceInfo); } // Allocate 2 tiles in X/Y/Z dimension for(uint32_t i = 0; i < TEST_BPP_MAX; i++) { TEST_BPP bpp = static_cast(i); gmmParams.Format = SetResourceFormat(bpp); gmmParams.BaseWidth64 = (TileSize[i][0] / GetBppValue(bpp)) + 1; gmmParams.BaseHeight = TileSize[i][1] + 1; gmmParams.Depth = TileSize[i][2] + 1; const uint32_t MinPitch = 32; const uint32_t PitchAlignment = 32; GMM_RESOURCE_INFO *ResourceInfo; ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); const uint32_t AlignedWidth = GMM_ULT_ALIGN(gmmParams.BaseWidth64, HAlign); uint32_t PitchInBytes = AlignedWidth * GetBppValue(bpp); PitchInBytes = GFX_MAX(PitchInBytes, MinPitch); PitchInBytes = GMM_ULT_ALIGN(PitchInBytes, PitchAlignment); PitchInBytes = GMM_ULT_ALIGN(PitchInBytes, TileSize[i][0]); VerifyResourceHAlign(ResourceInfo, HAlign); VerifyResourceVAlign(ResourceInfo, VAlign); VerifyResourcePitch(ResourceInfo, PitchInBytes); VerifyResourcePitchInTiles(ResourceInfo, PitchInBytes / TileSize[i][0]); VerifyResourceSize(ResourceInfo, PitchInBytes / TileSize[i][0] * 2 * 2 * GMM_KBYTE(4)); VerifyResourceQPitch(ResourceInfo, TileSize[i][1] * 2); pGmmULTClientContext->DestroyResInfoObject(ResourceInfo); } } /// @brief ULT for 3D TileYs Resource TEST_F(CTestGen9Resource, Test3DTileYsResource) { // Horizontal/Vertical pixel alignment const uint32_t HAlign[TEST_BPP_MAX] = {64, 32, 32, 32, 16}; const uint32_t VAlign[TEST_BPP_MAX] = {32, 32, 32, 16, 16}; const uint32_t TileSize[TEST_BPP_MAX][3] = {{64, 32, 32}, {64, 32, 32}, {128, 32, 16}, {256, 16, 16}, {256, 16, 16}}; GMM_RESCREATE_PARAMS gmmParams = {}; gmmParams.Type = RESOURCE_3D; gmmParams.NoGfxMemory = 1; gmmParams.Flags.Info.TiledY = 1; gmmParams.Flags.Info.TiledYs = 1; gmmParams.Flags.Gpu.Texture = 1; // Allocate 1x1x1 surface for(uint32_t i = 0; i < TEST_BPP_MAX; i++) { TEST_BPP bpp = static_cast(i); gmmParams.Format = SetResourceFormat(bpp); gmmParams.BaseWidth64 = 0x1; gmmParams.BaseHeight = 0x1; gmmParams.Depth = 0x1; GMM_RESOURCE_INFO *ResourceInfo; ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); VerifyResourceHAlign(ResourceInfo, HAlign[i]); VerifyResourceVAlign(ResourceInfo, VAlign[i]); VerifyResourcePitch(ResourceInfo, TileSize[i][0]); // As wide as 1 tile VerifyResourcePitchInTiles(ResourceInfo, 1); // 1 tile wide VerifyResourceSize(ResourceInfo, GMM_KBYTE(64)); // 1 tile big VerifyResourceQPitch(ResourceInfo, 0); // Not tested pGmmULTClientContext->DestroyResInfoObject(ResourceInfo); } // Allocate 2 tiles in X dimension for(uint32_t i = 0; i < TEST_BPP_MAX; i++) { TEST_BPP bpp = static_cast(i); gmmParams.Format = SetResourceFormat(bpp); gmmParams.BaseWidth64 = (TileSize[i][0] / GetBppValue(bpp)) + 1; // 1 pixel larger than 1 tile width gmmParams.BaseHeight = 0x1; gmmParams.Depth = 0x1; GMM_RESOURCE_INFO *ResourceInfo; ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); VerifyResourceHAlign(ResourceInfo, HAlign[i]); VerifyResourceVAlign(ResourceInfo, VAlign[i]); VerifyResourcePitch(ResourceInfo, TileSize[i][0] * 2); // As wide as 2 tile VerifyResourcePitchInTiles(ResourceInfo, 2); // 2 tile wide VerifyResourceSize(ResourceInfo, GMM_KBYTE(64) * 2); // 2 tile big VerifyResourceQPitch(ResourceInfo, 0); // Not tested pGmmULTClientContext->DestroyResInfoObject(ResourceInfo); } // Allocate 2 tiles in X/Y dimension for(uint32_t i = 0; i < TEST_BPP_MAX; i++) { TEST_BPP bpp = static_cast(i); gmmParams.Format = SetResourceFormat(bpp); gmmParams.BaseWidth64 = (TileSize[i][0] / GetBppValue(bpp)) + 1; // 1 pixel larger than 1 tile width gmmParams.BaseHeight = TileSize[i][1] + 1; // 1 row larger than 1 tile height gmmParams.Depth = 0x1; GMM_RESOURCE_INFO *ResourceInfo; ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); VerifyResourceHAlign(ResourceInfo, HAlign[i]); VerifyResourceVAlign(ResourceInfo, VAlign[i]); VerifyResourcePitch(ResourceInfo, TileSize[i][0] * 2); // As wide as 2 tile VerifyResourcePitchInTiles(ResourceInfo, 2); // 2 tile wide VerifyResourceSize(ResourceInfo, GMM_KBYTE(64) * 4); // 4 tile big VerifyResourceQPitch(ResourceInfo, 0); // Not tested pGmmULTClientContext->DestroyResInfoObject(ResourceInfo); } // Allocate 2 tiles in X/Y/Z dimension for(uint32_t i = 0; i < TEST_BPP_MAX; i++) { TEST_BPP bpp = static_cast(i); gmmParams.Format = SetResourceFormat(bpp); gmmParams.BaseWidth64 = (TileSize[i][0] / GetBppValue(bpp)) + 1; // 1 pixel larger than 1 tile width gmmParams.BaseHeight = TileSize[i][1] + 1; // 1 row larger than 1 tile height gmmParams.Depth = TileSize[i][2] + 1; // 1 plane larger than 1 tile depth GMM_RESOURCE_INFO *ResourceInfo; ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); VerifyResourceHAlign(ResourceInfo, HAlign[i]); VerifyResourceVAlign(ResourceInfo, VAlign[i]); VerifyResourcePitch(ResourceInfo, TileSize[i][0] * 2); // As wide as 2 tile VerifyResourcePitchInTiles(ResourceInfo, 2); // 2 tile wide VerifyResourceSize(ResourceInfo, GMM_KBYTE(64) * 8); // 8 tile big VerifyResourceQPitch(ResourceInfo, 0); // Not tested pGmmULTClientContext->DestroyResInfoObject(ResourceInfo); } } /// @brief ULT for 3D TileYs Mipped Resource TEST_F(CTestGen9Resource, Test3DTileYsMippedResource) { // Horizontal/Vertical pixel alignment const uint32_t HAlign[TEST_BPP_MAX] = {64, 32, 32, 32, 16}; const uint32_t VAlign[TEST_BPP_MAX] = {32, 32, 32, 16, 16}; const uint32_t TileSize[TEST_BPP_MAX][3] = {{64, 32, 32}, {64, 32, 32}, {128, 32, 16}, {256, 16, 16}, {256, 16, 16}}; for(uint32_t i = 0; i < TEST_BPP_MAX; i++) { const uint32_t ResourceWidth = 0x100; const uint32_t ResourceHeight = 0x100; const uint32_t ResourceDepth = 0x100; const uint32_t MaxLod = 0x5; TEST_BPP bpp = static_cast(i); GMM_RESCREATE_PARAMS gmmParams = {}; gmmParams.Type = RESOURCE_3D; gmmParams.Flags.Info.TiledY = 1; gmmParams.Flags.Info.TiledYs = 1; gmmParams.NoGfxMemory = 1; gmmParams.Flags.Gpu.Texture = 1; gmmParams.BaseWidth64 = ResourceWidth; gmmParams.BaseHeight = ResourceHeight; gmmParams.Depth = ResourceDepth; gmmParams.MaxLod = MaxLod; gmmParams.Format = SetResourceFormat(bpp); GMM_RESOURCE_INFO *ResourceInfo; ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); const uint32_t Pitch = ResourceWidth * GetBppValue(bpp); const uint32_t Mip0Height = ResourceHeight; // Mip0 GMM_REQ_OFFSET_INFO OffsetInfo = {}; OffsetInfo.ReqRender = 1; OffsetInfo.MipLevel = 0; ResourceInfo->GetOffset(OffsetInfo); EXPECT_EQ(0, OffsetInfo.Render.Offset64); EXPECT_EQ(0, OffsetInfo.Render.XOffset); EXPECT_EQ(0, OffsetInfo.Render.YOffset); EXPECT_EQ(0, OffsetInfo.Render.ZOffset); // Mip1 OffsetInfo = {}; OffsetInfo.ReqRender = 1; OffsetInfo.MipLevel = 1; ResourceInfo->GetOffset(OffsetInfo); const uint32_t SizeOfMip0 = Pitch * ResourceHeight * TileSize[i][2]; const uint32_t Mip1Offset = SizeOfMip0; const uint32_t Mip1Width = ResourceWidth >> 1; const uint32_t Mip1Height = ResourceHeight >> 1; EXPECT_EQ(Mip1Offset, OffsetInfo.Render.Offset64); EXPECT_EQ(0, OffsetInfo.Render.XOffset); EXPECT_EQ(0, OffsetInfo.Render.YOffset); EXPECT_EQ(0, OffsetInfo.Render.ZOffset); // Mip2 OffsetInfo = {}; OffsetInfo.ReqRender = 1; OffsetInfo.MipLevel = 2; ResourceInfo->GetOffset(OffsetInfo); const uint32_t Mip2Height = ResourceHeight >> 2; const uint32_t Mip2Offset = Mip1Offset + Mip1Width * GetBppValue(bpp) / TileSize[i][0] * GMM_KBYTE(64); EXPECT_EQ(Mip2Offset, OffsetInfo.Render.Offset64); EXPECT_EQ(0, OffsetInfo.Render.XOffset); EXPECT_EQ(0, OffsetInfo.Render.YOffset); EXPECT_EQ(0, OffsetInfo.Render.ZOffset); // Mip3 OffsetInfo = {}; OffsetInfo.ReqRender = 1; OffsetInfo.MipLevel = 3; ResourceInfo->GetOffset(OffsetInfo); const uint32_t Mip3Y = (Mip0Height + Mip2Height) * TileSize[i][2]; const uint32_t Mip3X = Mip1Width; const uint32_t Mip3Offset = Mip3Y * Pitch + Mip3X * GetBppValue(bpp) / TileSize[i][0] * GMM_KBYTE(64); EXPECT_EQ(Mip3Offset, OffsetInfo.Render.Offset64); EXPECT_EQ(bpp == TEST_BPP_8 ? 32 : 0, OffsetInfo.Render.XOffset); EXPECT_EQ(0, OffsetInfo.Render.YOffset); EXPECT_EQ(0, OffsetInfo.Render.ZOffset); // Mip4 OffsetInfo = {}; OffsetInfo.ReqRender = 1; OffsetInfo.MipLevel = 4; ResourceInfo->GetOffset(OffsetInfo); const uint32_t Mip3Height = ResourceHeight >> 3; const uint32_t Mip4Y = (Mip0Height + Mip2Height + Mip3Height) * TileSize[i][2]; const uint32_t Mip4X = Mip1Width; const uint32_t Mip4Offset = Mip4Y * Pitch + Mip4X * GetBppValue(bpp) / TileSize[i][0] * GMM_KBYTE(64); switch(bpp) { case TEST_BPP_8: EXPECT_EQ(Mip3Offset, OffsetInfo.Render.Offset64); EXPECT_EQ(0, OffsetInfo.Render.XOffset); EXPECT_EQ(16, OffsetInfo.Render.YOffset); EXPECT_EQ(0, OffsetInfo.Render.ZOffset); break; case TEST_BPP_16: EXPECT_EQ(Mip4Offset, OffsetInfo.Render.Offset64); EXPECT_EQ(32, OffsetInfo.Render.XOffset); EXPECT_EQ(0, OffsetInfo.Render.YOffset); EXPECT_EQ(0, OffsetInfo.Render.ZOffset); break; case TEST_BPP_32: EXPECT_EQ(Mip4Offset, OffsetInfo.Render.Offset64); EXPECT_EQ(64, OffsetInfo.Render.XOffset); EXPECT_EQ(0, OffsetInfo.Render.YOffset); EXPECT_EQ(0, OffsetInfo.Render.ZOffset); break; case TEST_BPP_64: EXPECT_EQ(Mip4Offset, OffsetInfo.Render.Offset64); EXPECT_EQ(128, OffsetInfo.Render.XOffset); EXPECT_EQ(0, OffsetInfo.Render.YOffset); EXPECT_EQ(0, OffsetInfo.Render.ZOffset); break; case TEST_BPP_128: EXPECT_EQ(Mip4Offset, OffsetInfo.Render.Offset64); EXPECT_EQ(0, OffsetInfo.Render.XOffset); EXPECT_EQ(0, OffsetInfo.Render.YOffset); EXPECT_EQ(0, OffsetInfo.Render.ZOffset); break; default: break; } // Mip5 OffsetInfo = {}; OffsetInfo.ReqRender = 1; OffsetInfo.MipLevel = 5; ResourceInfo->GetOffset(OffsetInfo); const uint32_t Mip4Height = ResourceHeight >> 4; const uint32_t Mip5Y = (Mip0Height + Mip2Height + Mip3Height + Mip4Height) * TileSize[i][2]; const uint32_t Mip5X = Mip1Width; const uint32_t Mip5Offset = Mip5Y * Pitch + Mip4X * GetBppValue(bpp) / TileSize[i][0] * GMM_KBYTE(64); switch(bpp) { case TEST_BPP_8: EXPECT_EQ(Mip3Offset, OffsetInfo.Render.Offset64); EXPECT_EQ(0, OffsetInfo.Render.XOffset); EXPECT_EQ(0, OffsetInfo.Render.YOffset); EXPECT_EQ(16, OffsetInfo.Render.ZOffset); break; case TEST_BPP_16: EXPECT_EQ(Mip4Offset, OffsetInfo.Render.Offset64); EXPECT_EQ(0, OffsetInfo.Render.XOffset); EXPECT_EQ(16, OffsetInfo.Render.YOffset); EXPECT_EQ(0, OffsetInfo.Render.ZOffset); break; case TEST_BPP_32: EXPECT_EQ(Mip4Offset, OffsetInfo.Render.Offset64); EXPECT_EQ(0, OffsetInfo.Render.XOffset); EXPECT_EQ(16, OffsetInfo.Render.YOffset); EXPECT_EQ(0, OffsetInfo.Render.ZOffset); break; case TEST_BPP_64: EXPECT_EQ(Mip4Offset, OffsetInfo.Render.Offset64); EXPECT_EQ(0, OffsetInfo.Render.XOffset); EXPECT_EQ(8, OffsetInfo.Render.YOffset); EXPECT_EQ(0, OffsetInfo.Render.ZOffset); break; case TEST_BPP_128: EXPECT_EQ(Mip5Offset, OffsetInfo.Render.Offset64); EXPECT_EQ(128, OffsetInfo.Render.XOffset); EXPECT_EQ(0, OffsetInfo.Render.YOffset); EXPECT_EQ(0, OffsetInfo.Render.ZOffset); break; default: break; } pGmmULTClientContext->DestroyResInfoObject(ResourceInfo); } } /// @brief ULT for 3D TileYf Resource TEST_F(CTestGen9Resource, Test3DTileYfResource) { // Horizontal/Vertical pixel alignment const uint32_t HAlign[TEST_BPP_MAX] = {16, 8, 8, 8, 4}; const uint32_t VAlign[TEST_BPP_MAX] = {16, 16, 16, 8, 8}; const uint32_t TileSize[TEST_BPP_MAX][3] = {{16, 16, 16}, {16, 16, 16}, {32, 16, 8}, {64, 8, 8}, {64, 8, 8}}; GMM_RESCREATE_PARAMS gmmParams = {}; gmmParams.Type = RESOURCE_3D; gmmParams.NoGfxMemory = 1; gmmParams.Flags.Info.TiledYf = 1; gmmParams.Flags.Gpu.Texture = 1; // Allocate 1x1x1 surface for(uint32_t i = 0; i < TEST_BPP_MAX; i++) { TEST_BPP bpp = static_cast(i); gmmParams.Format = SetResourceFormat(bpp); gmmParams.BaseWidth64 = 0x1; gmmParams.BaseHeight = 0x1; gmmParams.Depth = 0x1; const uint32_t PitchAlignment = 32; GMM_RESOURCE_INFO *ResourceInfo; ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); VerifyResourceHAlign(ResourceInfo, HAlign[i]); VerifyResourceVAlign(ResourceInfo, VAlign[i]); VerifyResourcePitch(ResourceInfo, GMM_ULT_ALIGN(TileSize[i][0], PitchAlignment)); VerifyResourcePitchInTiles(ResourceInfo, GMM_ULT_ALIGN(TileSize[i][0], PitchAlignment) / TileSize[i][0]); VerifyResourceSize(ResourceInfo, GMM_ULT_ALIGN(TileSize[i][0], PitchAlignment) / TileSize[i][0] * GMM_KBYTE(4)); VerifyResourceQPitch(ResourceInfo, TileSize[i][1]); pGmmULTClientContext->DestroyResInfoObject(ResourceInfo); } // Allocate 2 tiles in X dimension for(uint32_t i = 0; i < TEST_BPP_MAX; i++) { TEST_BPP bpp = static_cast(i); gmmParams.Format = SetResourceFormat(bpp); gmmParams.BaseWidth64 = (TileSize[i][0] / GetBppValue(bpp)) + 1; gmmParams.BaseHeight = 0x1; gmmParams.Depth = 0x1; const uint32_t PitchAlignment = 32; GMM_RESOURCE_INFO *ResourceInfo; ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); VerifyResourceHAlign(ResourceInfo, HAlign[i]); VerifyResourceVAlign(ResourceInfo, VAlign[i]); VerifyResourcePitch(ResourceInfo, GMM_ULT_ALIGN(TileSize[i][0] * 2, PitchAlignment)); VerifyResourcePitchInTiles(ResourceInfo, GMM_ULT_ALIGN(TileSize[i][0] * 2, PitchAlignment) / TileSize[i][0]); VerifyResourceSize(ResourceInfo, GMM_ULT_ALIGN(TileSize[i][0] * 2, PitchAlignment) / TileSize[i][0] * GMM_KBYTE(4)); VerifyResourceQPitch(ResourceInfo, TileSize[i][1]); pGmmULTClientContext->DestroyResInfoObject(ResourceInfo); } // Allocate 2 tiles in X/Y dimension for(uint32_t i = 0; i < TEST_BPP_MAX; i++) { TEST_BPP bpp = static_cast(i); gmmParams.Format = SetResourceFormat(bpp); gmmParams.BaseWidth64 = (TileSize[i][0] / GetBppValue(bpp)) + 1; gmmParams.BaseHeight = TileSize[i][1] + 1; gmmParams.Depth = 0x1; const uint32_t PitchAlignment = 32; GMM_RESOURCE_INFO *ResourceInfo; ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); VerifyResourceHAlign(ResourceInfo, HAlign[i]); VerifyResourceVAlign(ResourceInfo, VAlign[i]); VerifyResourcePitch(ResourceInfo, GMM_ULT_ALIGN(TileSize[i][0] * 2, PitchAlignment)); VerifyResourcePitchInTiles(ResourceInfo, GMM_ULT_ALIGN(TileSize[i][0] * 2, PitchAlignment) / TileSize[i][0]); VerifyResourceSize(ResourceInfo, GMM_ULT_ALIGN(TileSize[i][0] * 2, PitchAlignment) / TileSize[i][0] * 2 * GMM_KBYTE(4)); VerifyResourceQPitch(ResourceInfo, TileSize[i][1] * 2); pGmmULTClientContext->DestroyResInfoObject(ResourceInfo); } // Allocate 2 tiles in X/Y/Z dimension for(uint32_t i = 0; i < TEST_BPP_MAX; i++) { TEST_BPP bpp = static_cast(i); gmmParams.Format = SetResourceFormat(bpp); gmmParams.BaseWidth64 = (TileSize[i][0] / GetBppValue(bpp)) + 1; gmmParams.BaseHeight = TileSize[i][1] + 1; gmmParams.Depth = TileSize[i][2] + 1; const uint32_t PitchAlignment = 32; GMM_RESOURCE_INFO *ResourceInfo; ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); VerifyResourceHAlign(ResourceInfo, HAlign[i]); VerifyResourceVAlign(ResourceInfo, VAlign[i]); VerifyResourcePitch(ResourceInfo, GMM_ULT_ALIGN(TileSize[i][0] * 2, PitchAlignment)); VerifyResourcePitchInTiles(ResourceInfo, GMM_ULT_ALIGN(TileSize[i][0] * 2, PitchAlignment) / TileSize[i][0]); VerifyResourceSize(ResourceInfo, GMM_ULT_ALIGN(TileSize[i][0] * 2, PitchAlignment) / TileSize[i][0] * 2 * 2 * GMM_KBYTE(4)); VerifyResourceQPitch(ResourceInfo, TileSize[i][1] * 2); pGmmULTClientContext->DestroyResInfoObject(ResourceInfo); } } /// @brief ULT for Cube Linear Resource TEST_F(CTestGen9Resource, TestCubeLinearResource) { const uint32_t HAlign = 16; const uint32_t VAlign = 4; GMM_RESCREATE_PARAMS gmmParams = {}; gmmParams.Type = RESOURCE_CUBE; gmmParams.NoGfxMemory = 1; gmmParams.Flags.Info.Linear = 1; gmmParams.Flags.Gpu.Texture = 1; // Allocate 1x1 for(uint32_t i = 0; i < TEST_BPP_MAX; i++) { TEST_BPP bpp = static_cast(i); gmmParams.Format = SetResourceFormat(bpp); gmmParams.BaseWidth64 = 0x1; gmmParams.BaseHeight = 0x1; gmmParams.Depth = 0x1; GMM_RESOURCE_INFO *ResourceInfo; ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); VerifyResourceHAlign(ResourceInfo, HAlign); VerifyResourceVAlign(ResourceInfo, VAlign); uint32_t ExpectedPitch = GMM_ULT_MAX(GMM_BYTES(32), HAlign * GetBppValue(bpp)); // Min Pitch = 32 bytes VerifyResourcePitch(ResourceInfo, ExpectedPitch); // As wide as 1 tile VerifyResourcePitchInTiles(ResourceInfo, 1); // not applicable uint32_t ExpectedQPitch = VAlign; VerifyResourceQPitch(ResourceInfo, ExpectedQPitch); // Each face should be VAlign rows apart within a tile VerifyResourceSize(ResourceInfo, // PitchInBytes * Rows where Rows = __GMM_MAX_CUBE_FACE x QPitch, then aligned PAGE_SIZE GMM_ULT_ALIGN(ExpectedPitch * __GMM_MAX_CUBE_FACE * ExpectedQPitch, PAGE_SIZE)); for(uint32_t CubeFaceIndex = 0; CubeFaceIndex < __GMM_MAX_CUBE_FACE; CubeFaceIndex++) { GMM_REQ_OFFSET_INFO OffsetInfo = {}; OffsetInfo.ReqRender = 1; OffsetInfo.CubeFace = static_cast(CubeFaceIndex); ResourceInfo->GetOffset(OffsetInfo); EXPECT_EQ(CubeFaceIndex * ExpectedQPitch * ExpectedPitch, OffsetInfo.Render.Offset64); // Render offset is tile's base address on which cube face begins. EXPECT_EQ(0, OffsetInfo.Render.XOffset); // X Offset should be 0 EXPECT_EQ(0, OffsetInfo.Render.YOffset); // Y Offset should be 0 EXPECT_EQ(0, OffsetInfo.Render.ZOffset); // Z offset N/A should be 0 } pGmmULTClientContext->DestroyResInfoObject(ResourceInfo); } // Allocate arbitrary size (X/Y dimension not applicable as linear surface) // Width and Height must be equal for(uint32_t i = 0; i < TEST_BPP_MAX; i++) { TEST_BPP bpp = static_cast(i); gmmParams.Format = SetResourceFormat(bpp); gmmParams.BaseWidth64 = 0x201; // 512 + 1, help ult HAlign/VAlign/Pitch alignment logic as well. gmmParams.BaseHeight = gmmParams.BaseWidth64; // Heigth must be equal to width. gmmParams.Depth = 0x1; GMM_RESOURCE_INFO *ResourceInfo; ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); VerifyResourceHAlign(ResourceInfo, HAlign); VerifyResourceVAlign(ResourceInfo, VAlign); uint32_t ExpectedPitch = GMM_ULT_ALIGN(gmmParams.BaseWidth64, HAlign) * GetBppValue(bpp); // HAligned-width in bytes. ExpectedPitch = GMM_ULT_ALIGN(ExpectedPitch, GMM_BYTES(32)); VerifyResourcePitch(ResourceInfo, ExpectedPitch); VerifyResourcePitchInTiles(ResourceInfo, 2); // not applicable uint32_t ExpectedQPitch = GMM_ULT_ALIGN(gmmParams.BaseHeight, VAlign); VerifyResourceQPitch(ResourceInfo, ExpectedQPitch); // Each face should be Valigned-BaseHeight rows apart VerifyResourceSize(ResourceInfo, // PitchInBytes * Rows where Rows = __GMM_MAX_CUBE_FACE x QPitch, then aligned PAGE_SIZE GMM_ULT_ALIGN(ExpectedPitch * __GMM_MAX_CUBE_FACE * ExpectedQPitch, PAGE_SIZE)); for(uint32_t CubeFaceIndex = 0; CubeFaceIndex < __GMM_MAX_CUBE_FACE; CubeFaceIndex++) { GMM_REQ_OFFSET_INFO OffsetInfo = {}; OffsetInfo.ReqRender = 1; OffsetInfo.CubeFace = static_cast(CubeFaceIndex); ResourceInfo->GetOffset(OffsetInfo); EXPECT_EQ(CubeFaceIndex * ExpectedQPitch * ExpectedPitch, OffsetInfo.Render.Offset64); // Render offset is tile's base address on which cube face begins. EXPECT_EQ(0, OffsetInfo.Render.XOffset); // X Offset should be 0 EXPECT_EQ(0, OffsetInfo.Render.YOffset); // Y Offset should be 0 EXPECT_EQ(0, OffsetInfo.Render.ZOffset); // Z offset N/A should be 0 } pGmmULTClientContext->DestroyResInfoObject(ResourceInfo); } } /// @brief ULT for Cube Linear Mipped Resource Array TEST_F(CTestGen9Resource, TestCubeLinearMippedResourceArray) { const uint32_t HAlign = 16; const uint32_t VAlign = 4; const uint32_t MaxLod = 9; const uint32_t ResWidth = 0x401; const uint32_t MaxArraySize = 0x10; GMM_RESCREATE_PARAMS gmmParams = {}; gmmParams.Type = RESOURCE_CUBE; gmmParams.NoGfxMemory = 1; gmmParams.Flags.Info.Linear = 1; gmmParams.Flags.Gpu.Texture = 1; gmmParams.MaxLod = MaxLod; gmmParams.ArraySize = MaxArraySize; // Allocate arbitrary size (X/Y dimension not applicable as linear surface) // Width and Height must be equal for(uint32_t i = 0; i < TEST_BPP_MAX; i++) { struct //Cache the value for verifying array elements/Cube face offset/Mip Offset { uint64_t Offset; // Note : absolute mip offset } RenderOffset[GMM_ULT_MAX_MIPMAP] = {}; TEST_BPP bpp = static_cast(i); gmmParams.Format = SetResourceFormat(bpp); gmmParams.BaseWidth64 = ResWidth; // 1024 + 1, help ult HAlign/VAlign/Pitch alignment logic as well. gmmParams.BaseHeight = gmmParams.BaseWidth64; // Heigth must be equal to width. gmmParams.Depth = 0x1; GMM_RESOURCE_INFO *ResourceInfo; ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); VerifyResourceHAlign(ResourceInfo, HAlign); VerifyResourceVAlign(ResourceInfo, VAlign); //------------------------------| // | // LOD0 | // | // | //------------------------------| // LOD1 | LOD2 | // |----------| // | LOD3 | //-------------| LOD4 .. so on // Mip 0 // Mip 0 decides the pitch of the entire surface const uint32_t AlignedWidthMip0 = GMM_ULT_ALIGN(ResWidth, HAlign); // HAlign width in pixel const uint32_t AlignedHeightMip0 = GMM_ULT_ALIGN(ResWidth, VAlign); uint32_t ExpectedPitch = GMM_ULT_ALIGN(gmmParams.BaseWidth64, HAlign) * GetBppValue(bpp); // HAligned-width in bytes. ExpectedPitch = GMM_ULT_ALIGN(ExpectedPitch, GMM_BYTES(32)); VerifyResourcePitch(ResourceInfo, ExpectedPitch); VerifyResourcePitchInTiles(ResourceInfo, 2); // Not applicable // Mip0 should be at offset 0 and tile aligned GMM_REQ_OFFSET_INFO OffsetInfo = {}; OffsetInfo.ReqRender = 1; OffsetInfo.MipLevel = 0; //Mip 0 ResourceInfo->GetOffset(OffsetInfo); EXPECT_EQ(0, OffsetInfo.Render.Offset64); EXPECT_EQ(0, OffsetInfo.Render.XOffset); EXPECT_EQ(0, OffsetInfo.Render.YOffset); EXPECT_EQ(0, OffsetInfo.Render.ZOffset); //cache Mip 0 offset RenderOffset[0].Offset = 0; // Mip 1 should be under mip 0 OffsetInfo = {}; OffsetInfo.ReqRender = 1; OffsetInfo.MipLevel = 1; //Mip 1 ResourceInfo->GetOffset(OffsetInfo); EXPECT_EQ(AlignedHeightMip0 * ExpectedPitch, // Render offset is the absolute address at which the mip begins OffsetInfo.Render.Offset64); EXPECT_EQ(0, OffsetInfo.Render.XOffset); // Not applicable for linear surface EXPECT_EQ(0, OffsetInfo.Render.YOffset); // Not applicable for linear surface EXPECT_EQ(0, OffsetInfo.Render.ZOffset); // n/a //cache Mip 1 offset RenderOffset[1].Offset = AlignedHeightMip0 * ExpectedPitch; //Absolute base const uint32_t AlignedWidthMip1 = GMM_ULT_ALIGN(ResWidth >> 1, HAlign); // Align width in pixel to HAlign const uint32_t AlignedHeightMip1 = GMM_ULT_ALIGN(ResWidth >> 1, VAlign); uint32_t HeightOfMip; uint32_t HeightLinesLevel2 = 0; // Mips 2-9 should be stacked on the right of Mip1 as shown in figure above. for(int i = 2; i <= MaxLod; i++) { OffsetInfo = {}; OffsetInfo.ReqRender = 1; OffsetInfo.MipLevel = i; ResourceInfo->GetOffset(OffsetInfo); HeightOfMip = GMM_ULT_ALIGN(ResWidth >> i, VAlign); EXPECT_EQ((AlignedHeightMip0 + HeightLinesLevel2) * ExpectedPitch + // Render offset is tile's base address on which mip begins (AlignedWidthMip1 * GetBppValue(bpp)), OffsetInfo.Render.Offset64); EXPECT_EQ(0, OffsetInfo.Render.XOffset); // Not applicable for linear surface EXPECT_EQ(0, OffsetInfo.Render.YOffset); // Not applicable for linear surface EXPECT_EQ(0, OffsetInfo.Render.ZOffset); //cache Mip i'th offset RenderOffset[i].Offset = (AlignedHeightMip0 + HeightLinesLevel2) * ExpectedPitch + (AlignedWidthMip1 * GetBppValue(bpp)); HeightLinesLevel2 += HeightOfMip; } uint32_t Max2DHeight = GMM_ULT_MAX(AlignedHeightMip1, HeightLinesLevel2); uint32_t ExpectedQPitch = GFX_ALIGN_NP2(AlignedHeightMip0 + Max2DHeight, VAlign); VerifyResourceQPitch(ResourceInfo, ExpectedQPitch); // Each face should be Valigned-BaseHeight rows apart VerifyResourceSize(ResourceInfo, // PitchInBytes * Rows where Rows = __GMM_MAX_CUBE_FACE x QPitch, then aligned to tile boundary GMM_ULT_ALIGN(ExpectedPitch * MaxArraySize * __GMM_MAX_CUBE_FACE * ExpectedQPitch, PAGE_SIZE)); // Verify each array element's Mip offset, Cube face offset etc. for(uint32_t ArrayIndex = 0; ArrayIndex < __GMM_MAX_CUBE_FACE; ArrayIndex++) { for(uint32_t CubeFaceIndex = 0; CubeFaceIndex < __GMM_MAX_CUBE_FACE; CubeFaceIndex++) { GMM_REQ_OFFSET_INFO OffsetInfo = {}; OffsetInfo.ReqRender = 1; OffsetInfo.ArrayIndex = ArrayIndex; OffsetInfo.CubeFace = static_cast(CubeFaceIndex); ResourceInfo->GetOffset(OffsetInfo); //Verify cube face offsets EXPECT_EQ(((6 * ArrayIndex) + CubeFaceIndex) * ExpectedQPitch * ExpectedPitch, OffsetInfo.Render.Offset64); // Render offset is tile's base address on which cube face begins. EXPECT_EQ(0, OffsetInfo.Render.XOffset); // X Offset should be 0 as linear surf EXPECT_EQ(0, OffsetInfo.Render.YOffset); // Y Offset should be 0 as linear surf EXPECT_EQ(0, OffsetInfo.Render.ZOffset); // Z offset N/A should be 0 uint32_t CubeFaceBaseOffset = ((6 * ArrayIndex) + CubeFaceIndex) * (ExpectedQPitch * ExpectedPitch); //Verify mip offsets in each cube face for(uint32_t Lod = 0; Lod <= MaxLod; Lod++) { OffsetInfo.MipLevel = Lod; ResourceInfo->GetOffset(OffsetInfo); uint32_t MipOffset = CubeFaceBaseOffset + RenderOffset[Lod].Offset; uint32_t OffsetX = MipOffset % ExpectedPitch; uint32_t OffsetY = MipOffset / ExpectedPitch; uint32_t RenderAlignOffset = OffsetY * ExpectedPitch + OffsetX; EXPECT_EQ(RenderAlignOffset, OffsetInfo.Render.Offset64); // Render offset absolute address on which cube face begins. EXPECT_EQ(0, OffsetInfo.Render.XOffset); // X Offset should be 0 as linear surf EXPECT_EQ(0, OffsetInfo.Render.YOffset); // Y Offset should be 0 as linear surf EXPECT_EQ(0, OffsetInfo.Render.ZOffset); // Z offset N/A should be 0 } } } pGmmULTClientContext->DestroyResInfoObject(ResourceInfo); } } /// @brief ULT for Cube TileX Resource TEST_F(CTestGen9Resource, TestCubeTileXResource) { // Cube is allocated as an array of 6 2D surface representing each cube face below //=============================== // q coordinate | face | // 0 | + x | // 1 | - x | // 2 | + y | // 3 | - y | // 4 | + z | // 5 | - z | //=============================== const uint32_t HAlign = 16; const uint32_t VAlign = 4; const uint32_t TileSize[1][2] = {512, 8}; GMM_RESCREATE_PARAMS gmmParams = {}; gmmParams.Type = RESOURCE_CUBE; gmmParams.NoGfxMemory = 1; gmmParams.Flags.Info.TiledX = 1; gmmParams.Flags.Gpu.Texture = 1; // Allocate 1x1 surface so that it occupies 1 Tile in X dimension for(uint32_t i = 0; i < TEST_BPP_MAX; i++) { TEST_BPP bpp = static_cast(i); gmmParams.Format = SetResourceFormat(bpp); gmmParams.BaseWidth64 = 0x1; gmmParams.BaseHeight = 0x1; gmmParams.Depth = 0x1; GMM_RESOURCE_INFO *ResourceInfo; ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); VerifyResourceHAlign(ResourceInfo, HAlign); VerifyResourceVAlign(ResourceInfo, VAlign); uint32_t ExpectedPitch = TileSize[0][0]; VerifyResourcePitch(ResourceInfo, ExpectedPitch); // As wide as 1 tile VerifyResourcePitchInTiles(ResourceInfo, 1); // 1 tile wide uint32_t ExpectedQPitch = VAlign; VerifyResourceQPitch(ResourceInfo, ExpectedQPitch); // Each face should be VAlign rows apart within a tile VerifyResourceSize(ResourceInfo, // PitchInBytes * Rows where Rows = __GMM_MAX_CUBE_FACE x QPitch, then aligned to tile boundary ExpectedPitch * GMM_ULT_ALIGN(__GMM_MAX_CUBE_FACE * ExpectedQPitch, TileSize[0][1])); for(uint32_t CubeFaceIndex = 0; CubeFaceIndex < __GMM_MAX_CUBE_FACE; CubeFaceIndex++) { GMM_REQ_OFFSET_INFO OffsetInfo = {}; OffsetInfo.ReqRender = 1; OffsetInfo.CubeFace = static_cast(CubeFaceIndex); ResourceInfo->GetOffset(OffsetInfo); EXPECT_EQ(GMM_ULT_ALIGN_FLOOR(CubeFaceIndex * ExpectedQPitch, TileSize[0][1]) * ExpectedPitch, OffsetInfo.Render.Offset64); // Render offset is tile's base address on which cube face begins. EXPECT_EQ(0, OffsetInfo.Render.XOffset); // X Offset should be 0 EXPECT_EQ((CubeFaceIndex * ExpectedQPitch) % TileSize[0][1], OffsetInfo.Render.YOffset); // Y Offset should be (CubeFaceIndex * QPitch) % TileHeight EXPECT_EQ(0, OffsetInfo.Render.ZOffset); // Z offset N/A should be 0 } pGmmULTClientContext->DestroyResInfoObject(ResourceInfo); } // Allocate 2 tiles in X dimension. // Width and Height must be equal for(uint32_t i = 0; i < TEST_BPP_MAX; i++) { TEST_BPP bpp = static_cast(i); gmmParams.Format = SetResourceFormat(bpp); gmmParams.BaseWidth64 = (TileSize[0][0] / GetBppValue(bpp)) + 1; // 1 pixel larger than 1 tile width gmmParams.BaseHeight = gmmParams.BaseWidth64; // Heigth must be equal to width. gmmParams.Depth = 0x1; GMM_RESOURCE_INFO *ResourceInfo; ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); VerifyResourceHAlign(ResourceInfo, HAlign); VerifyResourceVAlign(ResourceInfo, VAlign); uint32_t ExpectedPitch = TileSize[0][0] * 2; // As wide as 2 tile VerifyResourcePitch(ResourceInfo, ExpectedPitch); VerifyResourcePitchInTiles(ResourceInfo, 2); // 2 tile wide uint32_t ExpectedQPitch = GMM_ULT_ALIGN(gmmParams.BaseHeight, VAlign); VerifyResourceQPitch(ResourceInfo, ExpectedQPitch); // Each face should be Valigned-BaseHeight rows apart VerifyResourceSize(ResourceInfo, // PitchInBytes * Rows where Rows = __GMM_MAX_CUBE_FACE x QPitch, then aligned to tile boundary ExpectedPitch * GMM_ULT_ALIGN(__GMM_MAX_CUBE_FACE * ExpectedQPitch, TileSize[0][1])); for(uint32_t CubeFaceIndex = 0; CubeFaceIndex < __GMM_MAX_CUBE_FACE; CubeFaceIndex++) { GMM_REQ_OFFSET_INFO OffsetInfo = {}; OffsetInfo.ReqRender = 1; OffsetInfo.CubeFace = static_cast(CubeFaceIndex); ResourceInfo->GetOffset(OffsetInfo); EXPECT_EQ(GMM_ULT_ALIGN_FLOOR(CubeFaceIndex * ExpectedQPitch, TileSize[0][1]) * ExpectedPitch, OffsetInfo.Render.Offset64); // Render offset is tile's base address on which cube face begins. EXPECT_EQ(0, OffsetInfo.Render.XOffset); // X Offset should be 0 EXPECT_EQ((CubeFaceIndex * ExpectedQPitch) % TileSize[0][1], OffsetInfo.Render.YOffset); // Y Offset should be (CubeFaceIndex * QPitch) % TileHeight EXPECT_EQ(0, OffsetInfo.Render.ZOffset); // Z offset N/A should be 0 } pGmmULTClientContext->DestroyResInfoObject(ResourceInfo); } } /// @brief ULT for Cube TileY Resource TEST_F(CTestGen9Resource, TestCubeTileYResource) { // Cube is allocated as an array of 6 2D surface representing each cube face below //=============================== // �q� coordinate | face | // 0 | + x | // 1 | - x | // 2 | + y | // 3 | - y | // 4 | + z | // 5 | - z | //=============================== const uint32_t HAlign = 16; const uint32_t VAlign = 4; const uint32_t TileSize[1][2] = {128, 32}; GMM_RESCREATE_PARAMS gmmParams = {}; gmmParams.Type = RESOURCE_CUBE; gmmParams.NoGfxMemory = 1; gmmParams.Flags.Info.TiledY = 1; gmmParams.Flags.Gpu.Texture = 1; // Allocate 1x1 surface within a tile. for(uint32_t i = 0; i < TEST_BPP_128; i++) //TEST_BPP_128 cannot fit in a tile as HAlign = 16 { TEST_BPP bpp = static_cast(i); gmmParams.Format = SetResourceFormat(bpp); gmmParams.BaseWidth64 = 0x1; gmmParams.BaseHeight = 0x1; gmmParams.Depth = 0x1; GMM_RESOURCE_INFO *ResourceInfo; ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); VerifyResourceHAlign(ResourceInfo, HAlign); VerifyResourceVAlign(ResourceInfo, VAlign); VerifyResourcePitch(ResourceInfo, TileSize[0][0]); // As wide as 1 tile VerifyResourcePitchInTiles(ResourceInfo, 1); // 1 tile wide VerifyResourceSize(ResourceInfo, GMM_KBYTE(4)); // All 6 faces should be accomated in a tile. VerifyResourceQPitch(ResourceInfo, VAlign); // Each face should be VAlign rows apart within a tile for(uint32_t CubeFaceIndex = 0; CubeFaceIndex < __GMM_MAX_CUBE_FACE; CubeFaceIndex++) { GMM_REQ_OFFSET_INFO OffsetInfo = {}; OffsetInfo.ReqRender = 1; OffsetInfo.CubeFace = static_cast(CubeFaceIndex); ResourceInfo->GetOffset(OffsetInfo); EXPECT_EQ(0, OffsetInfo.Render.Offset64); // Render offset should be 0 as its on single tile. EXPECT_EQ(0, OffsetInfo.Render.XOffset); // X Offset should be 0 EXPECT_EQ(CubeFaceIndex * VAlign, OffsetInfo.Render.YOffset); // Y Offset should be VALIGN * CubeFace Index EXPECT_EQ(0, OffsetInfo.Render.ZOffset); } pGmmULTClientContext->DestroyResInfoObject(ResourceInfo); } // Allocate 2 tiles in X dimension. // Width and Height of Cube must be equal for(uint32_t i = 0; i < TEST_BPP_MAX; i++) { TEST_BPP bpp = static_cast(i); gmmParams.Format = SetResourceFormat(bpp); gmmParams.BaseWidth64 = (TileSize[0][0] / GetBppValue(bpp)) + 1; // 1 pixel larger than 1 tile width gmmParams.BaseHeight = gmmParams.BaseWidth64; // Heigth must be equal to width. gmmParams.Depth = 0x1; GMM_RESOURCE_INFO *ResourceInfo; ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); VerifyResourceHAlign(ResourceInfo, HAlign); VerifyResourceVAlign(ResourceInfo, VAlign); uint32_t ExpectedPitch = TileSize[0][0] * 2; // As wide as 2 tile VerifyResourcePitch(ResourceInfo, ExpectedPitch); VerifyResourcePitchInTiles(ResourceInfo, 2); // 2 tile wide uint32_t ExpectedQPitch = GMM_ULT_ALIGN(gmmParams.BaseHeight, VAlign); VerifyResourceQPitch(ResourceInfo, ExpectedQPitch); // Each face should be Valigned-BaseHeight rows apart VerifyResourceSize(ResourceInfo, // PitchInBytes * Rows where Rows = __GMM_MAX_CUBE_FACE x QPitch, then aligned to tile boundary ExpectedPitch * GMM_ULT_ALIGN(__GMM_MAX_CUBE_FACE * ExpectedQPitch, TileSize[0][1])); for(uint32_t CubeFaceIndex = 0; CubeFaceIndex < __GMM_MAX_CUBE_FACE; CubeFaceIndex++) { GMM_REQ_OFFSET_INFO OffsetInfo = {}; OffsetInfo.ReqRender = 1; OffsetInfo.CubeFace = static_cast(CubeFaceIndex); ResourceInfo->GetOffset(OffsetInfo); EXPECT_EQ(GMM_ULT_ALIGN_FLOOR(CubeFaceIndex * ExpectedQPitch, TileSize[0][1]) * ExpectedPitch, OffsetInfo.Render.Offset64); // Render offset is tile's base address on which cube face begins. EXPECT_EQ(0, OffsetInfo.Render.XOffset); // X Offset should be 0 EXPECT_EQ((CubeFaceIndex * ExpectedQPitch) % TileSize[0][1], OffsetInfo.Render.YOffset); // Y Offset should be (CubeFaceIndex * QPitch) % TileHeight EXPECT_EQ(0, OffsetInfo.Render.ZOffset); // Z offset N/A should be 0 } pGmmULTClientContext->DestroyResInfoObject(ResourceInfo); } } /// @brief ULT for Cube TileYs Resource TEST_F(CTestGen9Resource, TestCubeTileYsResource) { // Cube is allocated as an array of 6 2D surface representing each cube face below //=============================== // �q� coordinate | face | // 0 | + x | // 1 | - x | // 2 | + y | // 3 | - y | // 4 | + z | // 5 | - z | //=============================== const uint32_t HAlign[TEST_BPP_MAX] = {256, 256, 128, 128, 64}; const uint32_t VAlign[TEST_BPP_MAX] = {256, 128, 128, 64, 64}; const uint32_t TileSize[TEST_BPP_MAX][2] = {{256, 256}, {512, 128}, {512, 128}, {1024, 64}, {1024, 64}}; GMM_RESCREATE_PARAMS gmmParams = {}; gmmParams.Type = RESOURCE_CUBE; gmmParams.NoGfxMemory = 1; gmmParams.Flags.Info.TiledY = 1; gmmParams.Flags.Info.TiledYs = 1; gmmParams.Flags.Gpu.Texture = 1; // Allocate 1x1 surface so that it occupies 1 Tile in X dimension for(uint32_t i = 0; i < TEST_BPP_MAX; i++) { TEST_BPP bpp = static_cast(i); gmmParams.Format = SetResourceFormat(bpp); gmmParams.BaseWidth64 = 0x1; gmmParams.BaseHeight = 0x1; gmmParams.Depth = 0x1; GMM_RESOURCE_INFO *ResourceInfo; ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); VerifyResourceHAlign(ResourceInfo, HAlign[i]); VerifyResourceVAlign(ResourceInfo, VAlign[i]); uint32_t ExpectedPitch = TileSize[i][0]; VerifyResourcePitch(ResourceInfo, ExpectedPitch); // As wide as 1 tile VerifyResourcePitchInTiles(ResourceInfo, 1); // 1 tile wide uint32_t ExpectedQPitch = VAlign[i]; VerifyResourceQPitch(ResourceInfo, ExpectedQPitch); // Each face should be VAlign rows apart within a tile VerifyResourceSize(ResourceInfo, // PitchInBytes * Rows where Rows = __GMM_MAX_CUBE_FACE x QPitch, then aligned to tile boundary ExpectedPitch * __GMM_MAX_CUBE_FACE * ExpectedQPitch); for(uint32_t CubeFaceIndex = 0; CubeFaceIndex < __GMM_MAX_CUBE_FACE; CubeFaceIndex++) { GMM_REQ_OFFSET_INFO OffsetInfo = {}; OffsetInfo.ReqRender = 1; OffsetInfo.CubeFace = static_cast(CubeFaceIndex); ResourceInfo->GetOffset(OffsetInfo); EXPECT_EQ((CubeFaceIndex * ExpectedQPitch) * ExpectedPitch, OffsetInfo.Render.Offset64); // Render offset is tile's base address on which cube face begins. EXPECT_EQ(0, OffsetInfo.Render.XOffset); // X Offset should be 0 as cube face starts on tile boundary EXPECT_EQ(0, OffsetInfo.Render.YOffset); // Y Offset should be 0 as cube face starts on tile boundary EXPECT_EQ(0, OffsetInfo.Render.ZOffset); // Z offset N/A should be 0 } pGmmULTClientContext->DestroyResInfoObject(ResourceInfo); } // Allocate 2 tiles in X dimension. // Width and Height must be equal for(uint32_t i = 0; i < TEST_BPP_MAX; i++) { TEST_BPP bpp = static_cast(i); gmmParams.Format = SetResourceFormat(bpp); gmmParams.BaseWidth64 = (TileSize[i][0] / GetBppValue(bpp)) + 1; // 1 pixel larger than 1 tile width gmmParams.BaseHeight = gmmParams.BaseWidth64; // Heigth must be equal to width. gmmParams.Depth = 0x1; GMM_RESOURCE_INFO *ResourceInfo; ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); VerifyResourceHAlign(ResourceInfo, HAlign[i]); VerifyResourceVAlign(ResourceInfo, VAlign[i]); uint32_t ExpectedPitch = TileSize[i][0] * 2; // As wide as 2 tile VerifyResourcePitch(ResourceInfo, ExpectedPitch); VerifyResourcePitchInTiles(ResourceInfo, 2); // 2 tile wide uint32_t ExpectedQPitch = GMM_ULT_ALIGN(gmmParams.BaseHeight, VAlign[i]); VerifyResourceQPitch(ResourceInfo, ExpectedQPitch); // Each face should be Valigned-BaseHeight rows apart VerifyResourceSize(ResourceInfo, // PitchInBytes * Rows where Rows = __GMM_MAX_CUBE_FACE x QPitch, then aligned to tile boundary ExpectedPitch * __GMM_MAX_CUBE_FACE * ExpectedQPitch); for(uint32_t CubeFaceIndex = 0; CubeFaceIndex < __GMM_MAX_CUBE_FACE; CubeFaceIndex++) { GMM_REQ_OFFSET_INFO OffsetInfo = {}; OffsetInfo.ReqRender = 1; OffsetInfo.CubeFace = static_cast(CubeFaceIndex); ResourceInfo->GetOffset(OffsetInfo); EXPECT_EQ((CubeFaceIndex * ExpectedQPitch) * ExpectedPitch, OffsetInfo.Render.Offset64); // Render offset is tile's base address on which cube face begins. EXPECT_EQ(0, OffsetInfo.Render.XOffset); // X Offset should be 0 as cube face starts on tile boundary EXPECT_EQ(0, OffsetInfo.Render.YOffset); // Y Offset should be 0 as cube face starts on tile boundary EXPECT_EQ(0, OffsetInfo.Render.ZOffset); // Z offset N/A should be 0 } pGmmULTClientContext->DestroyResInfoObject(ResourceInfo); } } /// @brief ULT for Cube TileYf Resource TEST_F(CTestGen9Resource, TestCubeTileYfResource) { // Cube is allocated as an array of 6 2D surface representing each cube face below //=============================== // �q� coordinate | face | // 0 | + x | // 1 | - x | // 2 | + y | // 3 | - y | // 4 | + z | // 5 | - z | //=============================== const uint32_t HAlign[TEST_BPP_MAX] = {64, 64, 32, 32, 16}; const uint32_t VAlign[TEST_BPP_MAX] = {64, 32, 32, 16, 16}; const uint32_t TileSize[TEST_BPP_MAX][2] = {{64, 64}, {128, 32}, {128, 32}, {256, 16}, {256, 16}}; GMM_RESCREATE_PARAMS gmmParams = {}; gmmParams.Type = RESOURCE_CUBE; gmmParams.NoGfxMemory = 1; gmmParams.Flags.Info.TiledY = 1; gmmParams.Flags.Info.TiledYf = 1; gmmParams.Flags.Gpu.Texture = 1; // Allocate 1x1 surface so that it occupies 1 Tile in X dimension for(uint32_t i = 0; i < TEST_BPP_MAX; i++) { TEST_BPP bpp = static_cast(i); gmmParams.Format = SetResourceFormat(bpp); gmmParams.BaseWidth64 = 0x1; gmmParams.BaseHeight = 0x1; gmmParams.Depth = 0x1; GMM_RESOURCE_INFO *ResourceInfo; ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); VerifyResourceHAlign(ResourceInfo, HAlign[i]); VerifyResourceVAlign(ResourceInfo, VAlign[i]); uint32_t ExpectedPitch = TileSize[i][0]; VerifyResourcePitch(ResourceInfo, ExpectedPitch); // As wide as 1 tile VerifyResourcePitchInTiles(ResourceInfo, 1); // 1 tile wide uint32_t ExpectedQPitch = VAlign[i]; VerifyResourceQPitch(ResourceInfo, ExpectedQPitch); // Each face should be VAlign rows apart within a tile VerifyResourceSize(ResourceInfo, // PitchInBytes * Rows where Rows = __GMM_MAX_CUBE_FACE x QPitch, then aligned to tile boundary ExpectedPitch * __GMM_MAX_CUBE_FACE * ExpectedQPitch); for(uint32_t CubeFaceIndex = 0; CubeFaceIndex < __GMM_MAX_CUBE_FACE; CubeFaceIndex++) { GMM_REQ_OFFSET_INFO OffsetInfo = {}; OffsetInfo.ReqRender = 1; OffsetInfo.CubeFace = static_cast(CubeFaceIndex); ResourceInfo->GetOffset(OffsetInfo); EXPECT_EQ((CubeFaceIndex * ExpectedQPitch) * ExpectedPitch, OffsetInfo.Render.Offset64); // Render offset is tile's base address on which cube face begins. EXPECT_EQ(0, OffsetInfo.Render.XOffset); // X Offset should be 0 as cube face starts on tile boundary EXPECT_EQ(0, OffsetInfo.Render.YOffset); // Y Offset should be 0 as cube face starts on tile boundary EXPECT_EQ(0, OffsetInfo.Render.ZOffset); // Z offset N/A should be 0 } pGmmULTClientContext->DestroyResInfoObject(ResourceInfo); } // Allocate 2 tiles in X dimension. // Width and Height must be equal for(uint32_t i = 0; i < TEST_BPP_MAX; i++) { TEST_BPP bpp = static_cast(i); gmmParams.Format = SetResourceFormat(bpp); gmmParams.BaseWidth64 = (TileSize[i][0] / GetBppValue(bpp)) + 1; // 1 pixel larger than 1 tile width gmmParams.BaseHeight = gmmParams.BaseWidth64; // Heigth must be equal to width. gmmParams.Depth = 0x1; GMM_RESOURCE_INFO *ResourceInfo; ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); VerifyResourceHAlign(ResourceInfo, HAlign[i]); VerifyResourceVAlign(ResourceInfo, VAlign[i]); uint32_t ExpectedPitch = TileSize[i][0] * 2; // As wide as 2 tile VerifyResourcePitch(ResourceInfo, ExpectedPitch); VerifyResourcePitchInTiles(ResourceInfo, 2); // 2 tile wide uint32_t ExpectedQPitch = GMM_ULT_ALIGN(gmmParams.BaseHeight, VAlign[i]); VerifyResourceQPitch(ResourceInfo, ExpectedQPitch); // Each face should be Valigned-BaseHeight rows apart VerifyResourceSize(ResourceInfo, // PitchInBytes * Rows where Rows = __GMM_MAX_CUBE_FACE x QPitch, then aligned to tile boundary ExpectedPitch * __GMM_MAX_CUBE_FACE * ExpectedQPitch); for(uint32_t CubeFaceIndex = 0; CubeFaceIndex < __GMM_MAX_CUBE_FACE; CubeFaceIndex++) { GMM_REQ_OFFSET_INFO OffsetInfo = {}; OffsetInfo.ReqRender = 1; OffsetInfo.CubeFace = static_cast(CubeFaceIndex); ResourceInfo->GetOffset(OffsetInfo); EXPECT_EQ((CubeFaceIndex * ExpectedQPitch) * ExpectedPitch, OffsetInfo.Render.Offset64); // Render offset is tile's base address on which cube face begins. EXPECT_EQ(0, OffsetInfo.Render.XOffset); // X Offset should be 0 as cube face starts on tile boundary EXPECT_EQ(0, OffsetInfo.Render.YOffset); // Y Offset should be 0 as cube face starts on tile boundary EXPECT_EQ(0, OffsetInfo.Render.ZOffset); // Z offset N/A should be 0 } pGmmULTClientContext->DestroyResInfoObject(ResourceInfo); } } /// @brief ULT for Cube TileY Mipped Resource Array TEST_F(CTestGen9Resource, TestCubeTileYMippedResourceArray) { const uint32_t HAlign = 16; const uint32_t VAlign = 4; const uint32_t TileSize[2] = {128, 32}; enum Coords { X = 0, Y = 1 }; GMM_RESCREATE_PARAMS gmmParams = {}; gmmParams.Type = RESOURCE_CUBE; gmmParams.NoGfxMemory = 1; gmmParams.Flags.Info.TiledY = 1; gmmParams.Flags.Gpu.Texture = 1; // Allocate CUBE surface for(uint32_t i = 0; i < TEST_BPP_MAX; i++) { const uint32_t ResWidth = 0x201; const uint32_t MaxLod = 0x9; const uint32_t MaxArraySize = 0x10; struct //Cache the value for verifying array elements/Cube face offset/Mip Offset { uint64_t Offset; // Note : absolute mip offset } RenderOffset[GMM_ULT_MAX_MIPMAP]; TEST_BPP bpp = static_cast(i); gmmParams.Format = SetResourceFormat(bpp); gmmParams.BaseWidth64 = ResWidth; // 1 pixel larger than 1 tile width gmmParams.BaseHeight = gmmParams.BaseWidth64; // Heigth must be equal to width. gmmParams.Depth = 0x1; gmmParams.MaxLod = MaxLod; gmmParams.ArraySize = MaxArraySize; GMM_RESOURCE_INFO *ResourceInfo; ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); VerifyResourceHAlign(ResourceInfo, HAlign); VerifyResourceVAlign(ResourceInfo, VAlign); //------------------------------| // | // LOD0 | // | // | //------------------------------| // LOD1 | LOD2 | // |----------| // | LOD3 | //-------------| LOD4 .. so on //Mip 0 //Mip 0 decides the pitch of the entire resource. const uint32_t AlignedWidthMip0 = GMM_ULT_ALIGN(ResWidth, HAlign); // HAlign width in pixel const uint32_t AlignedHeightMip0 = GMM_ULT_ALIGN(ResWidth, VAlign); uint32_t ExpectedPitch = GMM_ULT_ALIGN(AlignedWidthMip0 * GetBppValue(bpp), TileSize[X]); // Align AlignedWidthMip0 to 128 bytes VerifyResourcePitch(ResourceInfo, ExpectedPitch); VerifyResourcePitchInTiles(ResourceInfo, ExpectedPitch / TileSize[X]); // Pitch/TileY-Width // Mip0 should be at offset 0 and tile aligned GMM_REQ_OFFSET_INFO OffsetInfo = {}; OffsetInfo.ReqRender = 1; OffsetInfo.MipLevel = 0; //Mip 0 ResourceInfo->GetOffset(OffsetInfo); EXPECT_EQ(0, OffsetInfo.Render.Offset64); EXPECT_EQ(0, OffsetInfo.Render.XOffset); EXPECT_EQ(0, OffsetInfo.Render.YOffset); EXPECT_EQ(0, OffsetInfo.Render.ZOffset); //cache Mip 0 offset RenderOffset[0].Offset = 0; // Mip 1 should be under mip 0 OffsetInfo = {}; OffsetInfo.ReqRender = 1; OffsetInfo.MipLevel = 1; //Mip 1 ResourceInfo->GetOffset(OffsetInfo); EXPECT_EQ(GMM_ULT_ALIGN_FLOOR(AlignedHeightMip0, TileSize[Y]) * ExpectedPitch, // Render offset is tile's base address on which mip begins OffsetInfo.Render.Offset64); EXPECT_EQ(0, OffsetInfo.Render.XOffset); // Aligns with Mip0 at X = 0 EXPECT_EQ((AlignedHeightMip0) % TileSize[Y], OffsetInfo.Render.YOffset); // AlignedHeightMip0 % TileY-Height EXPECT_EQ(0, OffsetInfo.Render.ZOffset); //cache Mip 1 offset RenderOffset[1].Offset = AlignedHeightMip0 * ExpectedPitch; //Absolute base const uint32_t AlignedWidthMip1 = GMM_ULT_ALIGN(ResWidth >> 1, HAlign); // Align width in pixel to HAlign const uint32_t AlignedHeightMip1 = GMM_ULT_ALIGN(ResWidth >> 1, VAlign); uint32_t HeightOfMip; uint32_t HeightLinesLevel2 = 0; // Mips 2-9 should be stacked on the right of Mip1 as shown in figure above. for(int i = 2; i <= MaxLod; i++) { OffsetInfo = {}; OffsetInfo.ReqRender = 1; OffsetInfo.MipLevel = i; ResourceInfo->GetOffset(OffsetInfo); HeightOfMip = GMM_ULT_ALIGN(ResWidth >> i, VAlign); EXPECT_EQ(GMM_ULT_ALIGN_FLOOR(AlignedHeightMip0 + HeightLinesLevel2, TileSize[Y]) * ExpectedPitch + // Render offset is tile's base address on which mip begins (AlignedWidthMip1 * GetBppValue(bpp) / TileSize[X]) * PAGE_SIZE, OffsetInfo.Render.Offset64); EXPECT_EQ((AlignedWidthMip1 * GetBppValue(bpp)) % TileSize[X], OffsetInfo.Render.XOffset); // Aligns with Mip0 at X = 0 EXPECT_EQ((AlignedHeightMip0 + HeightLinesLevel2) % TileSize[Y], OffsetInfo.Render.YOffset); // AlignedHeightMip0 % TileY-Height EXPECT_EQ(0, OffsetInfo.Render.ZOffset); //cache Mip i'th offset RenderOffset[i].Offset = (AlignedHeightMip0 + HeightLinesLevel2) * ExpectedPitch + (AlignedWidthMip1 * GetBppValue(bpp)); HeightLinesLevel2 += HeightOfMip; } uint32_t Max2DHeight = GMM_ULT_MAX(AlignedHeightMip1, HeightLinesLevel2); uint32_t ExpectedQPitch = GFX_ALIGN_NP2(AlignedHeightMip0 + Max2DHeight, VAlign); VerifyResourceQPitch(ResourceInfo, ExpectedQPitch); // Each face should be Valigned-BaseHeight rows apart VerifyResourceSize(ResourceInfo, // PitchInBytes * Rows where Rows = __GMM_MAX_CUBE_FACE x QPitch, then aligned to tile boundary ExpectedPitch * GMM_ULT_ALIGN(MaxArraySize * __GMM_MAX_CUBE_FACE * ExpectedQPitch, TileSize[Y])); // Verify each array element's Mip offset, Cube face offset etc. for(uint32_t ArrayIndex = 0; ArrayIndex < __GMM_MAX_CUBE_FACE; ArrayIndex++) { for(uint32_t CubeFaceIndex = 0; CubeFaceIndex < __GMM_MAX_CUBE_FACE; CubeFaceIndex++) { GMM_REQ_OFFSET_INFO OffsetInfo = {}; OffsetInfo.ReqRender = 1; OffsetInfo.ArrayIndex = ArrayIndex; OffsetInfo.CubeFace = static_cast(CubeFaceIndex); ResourceInfo->GetOffset(OffsetInfo); //Verify cube face offsets EXPECT_EQ(GMM_ULT_ALIGN_FLOOR(((6 * ArrayIndex) + CubeFaceIndex) * ExpectedQPitch, TileSize[Y]) * ExpectedPitch, OffsetInfo.Render.Offset64); // Render offset is tile's base address on which cube face begins. EXPECT_EQ(0, OffsetInfo.Render.XOffset); // X Offset should be 0 EXPECT_EQ((((6 * ArrayIndex) + CubeFaceIndex) * ExpectedQPitch) % TileSize[Y], OffsetInfo.Render.YOffset); // Y Offset should be (CubeFaceIndex * QPitch) % TileHeight EXPECT_EQ(0, OffsetInfo.Render.ZOffset); // Z offset N/A should be 0 uint32_t CubeFaceBaseOffset = ((6 * ArrayIndex) + CubeFaceIndex) * (ExpectedQPitch * ExpectedPitch); //Verify mip offsets in each cube face for(uint32_t Lod = 0; Lod <= MaxLod; Lod++) { OffsetInfo.MipLevel = Lod; ResourceInfo->GetOffset(OffsetInfo); uint32_t MipOffset = CubeFaceBaseOffset + RenderOffset[Lod].Offset; uint32_t OffsetX = MipOffset % ExpectedPitch; uint32_t TileAlignedOffsetX = GMM_ULT_ALIGN_FLOOR(OffsetX, TileSize[X]); OffsetX -= TileAlignedOffsetX; uint32_t OffsetY = MipOffset / ExpectedPitch; uint32_t TileAlignedOffsetY = GMM_ULT_ALIGN_FLOOR(OffsetY, TileSize[Y]); OffsetY -= TileAlignedOffsetY; uint32_t RenderAlignOffset = TileAlignedOffsetY * ExpectedPitch + (TileAlignedOffsetX / TileSize[X]) * PAGE_SIZE; EXPECT_EQ(RenderAlignOffset, OffsetInfo.Render.Offset64); // Render offset is tile's base address on which cube face begins. EXPECT_EQ(OffsetX, OffsetInfo.Render.XOffset); EXPECT_EQ(OffsetY, OffsetInfo.Render.YOffset); // Y Offset should be (CubeFaceIndex * QPitch) % TileHeight EXPECT_EQ(0, OffsetInfo.Render.ZOffset); // Z offset N/A should be 0 } } } pGmmULTClientContext->DestroyResInfoObject(ResourceInfo); } } /// @brief ULT for Cube TileYs Mipped Array Resource TEST_F(CTestGen9Resource, TestCubeTileYsMippedResourceArray) { enum Coords { X = 0, Y = 1 }; const uint32_t HAlign[TEST_BPP_MAX] = {256, 256, 128, 128, 64}; const uint32_t VAlign[TEST_BPP_MAX] = {256, 128, 128, 64, 64}; const uint32_t TileSize[TEST_BPP_MAX][2] = {{256, 256}, {512, 128}, {512, 128}, {1024, 64}, {1024, 64}}; const uint32_t MaxMipTailSize[TEST_BPP_MAX][2] = {{128, 256}, {128, 128}, {64, 128}, {64, 64}, {32, 64}}; const uint32_t MipTailSlotSize[GMM_ULT_MAX_MIPTAIL_SLOTS] = { GMM_KBYTE(32), GMM_KBYTE(16), GMM_KBYTE(8), GMM_KBYTE(4), GMM_KBYTE(2), GMM_KBYTE(1), GMM_BYTES(768), GMM_BYTES(512), GMM_BYTES(448), GMM_BYTES(384), GMM_BYTES(320), GMM_BYTES(256), GMM_BYTES(192), GMM_BYTES(128), GMM_BYTES(64)}; const TEST_MIPTAIL_SLOT_OFFSET MipTailSlotOffsets[GMM_ULT_MAX_MIPTAIL_SLOTS][TEST_BPP_MAX] = { /* | 8 bpe | 16 bpe | 32 bpe | 64 bpe | 128 bpe | */ {{128, 0, 0}, {128, 0, 0}, {64, 0, 0}, {64, 0, 0}, {32, 0, 0}}, {{0, 128, 0}, {0, 64, 0}, {0, 64, 0}, {0, 32, 0}, {0, 32, 0}}, {{64, 0, 0}, {64, 0, 0}, {32, 0, 0}, {32, 0, 0}, {16, 0, 0}}, {{0, 64, 0}, {0, 32, 0}, {0, 32, 0}, {0, 16, 0}, {0, 16, 0}}, {{32, 0, 0}, {32, 0, 0}, {16, 0, 0}, {16, 0, 0}, {8, 0, 0}}, {{16, 32, 0}, {16, 16, 0}, {8, 16, 0}, {8, 8, 0}, {4, 8, 0}}, {{0, 48, 0}, {0, 24, 0}, {0, 24, 0}, {0, 12, 0}, {0, 12, 0}}, {{0, 32, 0}, {0, 16, 0}, {0, 16, 0}, {0, 8, 0}, {0, 8, 0}}, {{16, 16, 0}, {16, 8, 0}, {8, 8, 0}, {8, 4, 0}, {4, 4, 0}}, {{16, 0, 0}, {16, 0, 0}, {8, 0, 0}, {8, 0, 0}, {4, 0, 0}}, {{0, 16, 0}, {0, 8, 0}, {0, 8, 0}, {0, 4, 0}, {0, 4, 0}}, {{0, 12, 0}, {8, 4, 0}, {4, 4, 0}, {6, 0, 0}, {3, 0, 0}}, {{0, 8, 0}, {8, 0, 0}, {4, 0, 0}, {4, 0, 0}, {2, 0, 0}}, {{0, 4, 0}, {0, 4, 0}, {0, 4, 0}, {2, 0, 0}, {1, 0, 0}}, {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}}}; GMM_RESCREATE_PARAMS gmmParams = {}; gmmParams.Type = RESOURCE_CUBE; gmmParams.NoGfxMemory = 1; gmmParams.Flags.Info.TiledY = 1; gmmParams.Flags.Info.TiledYs = 1; gmmParams.Flags.Gpu.Texture = 1; // Allocate CUBE surface for(uint32_t i = 0; i < TEST_BPP_MAX; i++) { const uint32_t ResWidth = 0x1001; const uint32_t MaxLod = 0x9; const uint32_t MaxArraySize = 0x10; struct //Cache the value for verifying array elements/Cube face offset/Mip Offset { uint64_t Offset; // Note : absolute mip offset } RenderOffset[GMM_ULT_MAX_MIPMAP]; TEST_BPP bpp = static_cast(i); gmmParams.Format = SetResourceFormat(bpp); gmmParams.BaseWidth64 = ResWidth; gmmParams.BaseHeight = gmmParams.BaseWidth64; // Heigth must be equal to width. gmmParams.Depth = 0x1; gmmParams.MaxLod = MaxLod; gmmParams.ArraySize = MaxArraySize; GMM_RESOURCE_INFO *ResourceInfo; ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); VerifyResourceHAlign(ResourceInfo, HAlign[i]); VerifyResourceVAlign(ResourceInfo, VAlign[i]); //------------------------------| // | // LOD0 | // | // | //------------------------------| // LOD1 | LOD2 | // |----------| // | LOD3 | //-------------| LOD4 .. so on //Mip 0 //Mip 0 decides the pitch of the entire resource. const uint32_t AlignedWidthMip0 = GMM_ULT_ALIGN(ResWidth, HAlign[i]); // HAlign width in pixel const uint32_t AlignedHeightMip0 = GMM_ULT_ALIGN(ResWidth, VAlign[i]); uint32_t ExpectedPitch = GMM_ULT_ALIGN(AlignedWidthMip0 * GetBppValue(bpp), TileSize[i][X]); // Align AlignedWidthMip0 to Tile width VerifyResourcePitch(ResourceInfo, ExpectedPitch); VerifyResourcePitchInTiles(ResourceInfo, ExpectedPitch / TileSize[i][X]); // Pitch/Tile-Width // Mip0 should be at offset 0 and tile aligned GMM_REQ_OFFSET_INFO OffsetInfo = {}; OffsetInfo.ReqRender = 1; OffsetInfo.MipLevel = 0; //Mip 0 ResourceInfo->GetOffset(OffsetInfo); EXPECT_EQ(0, OffsetInfo.Render.Offset64); EXPECT_EQ(0, OffsetInfo.Render.XOffset); EXPECT_EQ(0, OffsetInfo.Render.YOffset); EXPECT_EQ(0, OffsetInfo.Render.ZOffset); //cache Mip 0 offset RenderOffset[0].Offset = 0; // Mip 1 should be under mip 0 OffsetInfo = {}; OffsetInfo.ReqRender = 1; OffsetInfo.MipLevel = 1; //Mip 1 ResourceInfo->GetOffset(OffsetInfo); EXPECT_EQ(AlignedHeightMip0 * ExpectedPitch, // Render offset is tile's base address on which mip begins OffsetInfo.Render.Offset64); EXPECT_EQ(0, OffsetInfo.Render.XOffset); // Mips are always tile aligned EXPECT_EQ(0, OffsetInfo.Render.YOffset); // Mips are always tile aligned EXPECT_EQ(0, OffsetInfo.Render.ZOffset); //cache Mip 1 offset RenderOffset[1].Offset = AlignedHeightMip0 * ExpectedPitch; //Absolute base const uint32_t AlignedWidthMip1 = GMM_ULT_ALIGN(ResWidth >> 1, HAlign[i]); // Align width in pixel to HAlign const uint32_t AlignedHeightMip1 = GMM_ULT_ALIGN(ResWidth >> 1, VAlign[i]); // Determine MipTail start LOD uint32_t ExpectedMipTailStartLod = 0; { uint32_t MipWidth, MipHeight; MipWidth = MipHeight = ResWidth; while((ExpectedMipTailStartLod < MaxLod) && !((MipWidth <= MaxMipTailSize[i][X]) && (MipHeight <= MaxMipTailSize[i][Y]))) { ExpectedMipTailStartLod++; MipWidth = MipWidth >> 1; MipHeight = MipHeight >> 1; } } VerifyResourceMipTailStartLod(ResourceInfo, ExpectedMipTailStartLod); uint32_t HeightOfMip; uint32_t HeightLinesLevel2 = 0; // Mips[2,MipTailStartLod - 1] should be stacked on the right of Mip1 as shown in figure above. for(int Lod = 2; Lod < ExpectedMipTailStartLod; Lod++) { OffsetInfo = {}; OffsetInfo.ReqRender = 1; OffsetInfo.MipLevel = Lod; ResourceInfo->GetOffset(OffsetInfo); HeightOfMip = GMM_ULT_ALIGN(ResWidth >> Lod, VAlign[i]); EXPECT_EQ((AlignedHeightMip0 + HeightLinesLevel2) * ExpectedPitch + // Render offset is tile's base address on which mip begins (AlignedWidthMip1 * GetBppValue(bpp) / TileSize[i][X]) * GMM_KBYTE(64), OffsetInfo.Render.Offset64); EXPECT_EQ(0, OffsetInfo.Render.XOffset); // Mip lies on Tile boundary EXPECT_EQ(0, OffsetInfo.Render.YOffset); // Mip lies on Tile boundary EXPECT_EQ(0, OffsetInfo.Render.ZOffset); //cache Mip i'th offset RenderOffset[Lod].Offset = (AlignedHeightMip0 + HeightLinesLevel2) * ExpectedPitch + (AlignedWidthMip1 * GetBppValue(bpp)); HeightLinesLevel2 += HeightOfMip; } // Mips[MipTailStartLod, MaxLod] will be on the mip tail. for(int Lod = ExpectedMipTailStartLod; Lod <= MaxLod; Lod++) { OffsetInfo = {}; OffsetInfo.ReqRender = 1; OffsetInfo.MipLevel = Lod; ResourceInfo->GetOffset(OffsetInfo); uint64_t ExpectedRenderAlignOffset = (AlignedHeightMip0 + HeightLinesLevel2) * (uint64_t)ExpectedPitch + // Render offset is tile's base address on which mip begins (AlignedWidthMip1 * GetBppValue(bpp) / TileSize[i][X]) * GMM_KBYTE(64); EXPECT_EQ(ExpectedRenderAlignOffset, OffsetInfo.Render.Offset64); EXPECT_EQ(MipTailSlotOffsets[Lod - ExpectedMipTailStartLod][i].X * GetBppValue(bpp), OffsetInfo.Render.XOffset); EXPECT_EQ(MipTailSlotOffsets[Lod - ExpectedMipTailStartLod][i].Y, OffsetInfo.Render.YOffset); EXPECT_EQ(0, OffsetInfo.Render.ZOffset); RenderOffset[Lod].Offset = ExpectedRenderAlignOffset + MipTailSlotSize[Lod - ExpectedMipTailStartLod]; } if(ExpectedMipTailStartLod) // Include mip tail height in the Level 2 height { HeightLinesLevel2 += TileSize[i][Y]; } uint32_t Max2DHeight = GMM_ULT_MAX(AlignedHeightMip1, HeightLinesLevel2); uint32_t ExpectedQPitch = GFX_ALIGN_NP2(AlignedHeightMip0 + Max2DHeight, VAlign[i]); VerifyResourceQPitch(ResourceInfo, ExpectedQPitch); // Each face should be Valigned-BaseHeight rows apart VerifyResourceSize(ResourceInfo, // PitchInBytes * Rows where Rows = __GMM_MAX_CUBE_FACE x QPitch, then aligned to tile boundary (uint64_t)ExpectedPitch * MaxArraySize * __GMM_MAX_CUBE_FACE * ExpectedQPitch); // Verify each array element's Mip offset, Cube face offset etc. for(uint32_t ArrayIndex = 0; ArrayIndex < MaxArraySize; ArrayIndex++) { for(uint32_t CubeFaceIndex = 0; CubeFaceIndex < __GMM_MAX_CUBE_FACE; CubeFaceIndex++) { GMM_REQ_OFFSET_INFO OffsetInfo = {}; OffsetInfo.ReqRender = 1; OffsetInfo.ArrayIndex = ArrayIndex; OffsetInfo.CubeFace = static_cast(CubeFaceIndex); ResourceInfo->GetOffset(OffsetInfo); //Verify cube face offsets EXPECT_EQ((((6 * ArrayIndex) + CubeFaceIndex) * ExpectedQPitch) * (uint64_t)ExpectedPitch, OffsetInfo.Render.Offset64); // Render offset is tile's base address on which cube face begins. EXPECT_EQ(0, OffsetInfo.Render.XOffset); // X Offset should be 0 EXPECT_EQ(0, OffsetInfo.Render.YOffset); // Y Offset should be 0 EXPECT_EQ(0, OffsetInfo.Render.ZOffset); // Z offset N/A should be 0 uint64_t CubeFaceBaseOffset = ((6 * ArrayIndex) + CubeFaceIndex) * (ExpectedQPitch * (uint64_t)ExpectedPitch); //Verify mip offsets in each cube face // Mips[0,MipTailStartLod - 1] for(int Lod = 0; Lod < ExpectedMipTailStartLod; Lod++) { OffsetInfo.MipLevel = Lod; ResourceInfo->GetOffset(OffsetInfo); uint64_t MipOffset = CubeFaceBaseOffset + RenderOffset[Lod].Offset; uint32_t TileAlignedOffsetX = MipOffset % ExpectedPitch; uint32_t TileAlignedOffsetY = MipOffset / ExpectedPitch; uint64_t ExpectedRenderAlignOffset = TileAlignedOffsetY * (uint64_t)ExpectedPitch + (TileAlignedOffsetX / TileSize[i][X]) * GMM_KBYTE(64); EXPECT_EQ(ExpectedRenderAlignOffset, OffsetInfo.Render.Offset64); // Render offset is tile's base address on which cube face begins. EXPECT_EQ(0, OffsetInfo.Render.XOffset); // Mip lies on Tile boundary EXPECT_EQ(0, OffsetInfo.Render.YOffset); // Mip lies on Tile boundary EXPECT_EQ(0, OffsetInfo.Render.ZOffset); // Z offset N/A should be 0 } // Mips[MipTailStartLod, MaxLod] will be on the mip tail. for(int Lod = ExpectedMipTailStartLod; Lod <= MaxLod; Lod++) { OffsetInfo.MipLevel = Lod; ResourceInfo->GetOffset(OffsetInfo); uint64_t MipOffset = CubeFaceBaseOffset + RenderOffset[Lod].Offset; uint64_t ExpectedRenderAlignOffset = GMM_ULT_ALIGN_FLOOR(MipOffset, GMM_KBYTE(64)); EXPECT_EQ(ExpectedRenderAlignOffset, OffsetInfo.Render.Offset64); EXPECT_EQ(MipTailSlotOffsets[Lod - ExpectedMipTailStartLod][i].X * GetBppValue(bpp), OffsetInfo.Render.XOffset); EXPECT_EQ(MipTailSlotOffsets[Lod - ExpectedMipTailStartLod][i].Y, OffsetInfo.Render.YOffset); EXPECT_EQ(0, OffsetInfo.Render.ZOffset); } } } pGmmULTClientContext->DestroyResInfoObject(ResourceInfo); } } /// @brief ULT for Plannar 2D Resource - Tiling TileYs TEST_F(CTestGen9Resource, TestPlanar2DTileYs) { } /// @brief ULT for Plannar 2D Resource - Tiling TileYf TEST_F(CTestGen9Resource, TestPlanar2DTileYf) { } int BuildInputIterator(std::vector> &List, int maxTestDimension, int TestArray, bool XEHPPlus) { for(uint32_t i = TEST_LINEAR; i < TEST_TILE_MAX; i++) { if(XEHPPlus) { if(i >= TEST_TILEX && i <= TEST_TILEY_MAX) continue; } else { if(i > TEST_TILEY_MAX) break; } for(uint32_t j = TEST_BPP_8; j < TEST_BPP_MAX; j++) for(uint32_t k = TEST_RESOURCE_1D; k < TEST_RESOURCE_MAX; k++) for(uint32_t l = 0; l < maxTestDimension; l++) for(uint32_t m = 0; m < TestArray; m++) { List.emplace_back(std::make_tuple(i, j, k, true, l, m)); List.emplace_back(std::make_tuple(i, j, k, false, l, m)); } } return List.size(); } /// @brief ULT for MSAA Resource TEST_F(CTestGen9Resource, TestMSAA) { //Tile dimensions in Bytes const uint32_t MCSTileSize[1][2] = {128, 32}; //MCS is TileY //Gen9: MSAA 16x no MCS for width > 8K //No MSAA for YUV/compressed formats //Interleaved MSS (IMS) for Depth/Stencil. Arrayed MSS (CMS) for Color RT //MSS (Arrayed): px_wL, px_hL = pixel width/height of single sample at Lod L // MSS width = px_wL, MSS height = NumSamples*px_hL //MSS (Interleaved): px_wL, px_hL = pixel width/height of single sample at Lod L // Samples MSS width MSS Height // 2x 4*ceil(px_wL/2) px_hL // 4x 4*ceil(px_wL/2) 4*ceil(px_hL/2) // 8x 8*ceil(px_wL/2) 4*ceil(px_hL/2) // 16x 8*ceil(px_wL/2) 8*ceil(px_hL/2) //MCS (bpp): 2x/4x - bpp_8, 8x - bpp_32, 16x - bpp_64 const uint32_t TestDimensions[4][2] = { //Input dimensions in #Tiles {15, 20}, //16 Tiles x 20 {0, 0}, //1x1x1 {1, 0}, //2 Tilesx1 {1, 1}, //2 Tiles x 2 }; uint32_t TestArraySize[2] = {1, 5}; uint32_t HAlign = 0, VAlign = 0, TileDimX = 0, TileDimY = 0; uint32_t MCSHAlign = 0, MCSVAlign = 0, TileSize = 0; uint32_t ExpectedMCSBpp; std::vector> List; //TEST_TILE_TYPE, TEST_BPP, TEST_RESOURCE_TYPE, Depth or RT, TestDimension index, ArraySize auto Size = BuildInputIterator(List, 4, 2, false); // Size of arrays TestDimensions, TestArraySize for(auto element : List) { GMM_RESCREATE_PARAMS gmmParams = {}; gmmParams.Flags.Info = {0}; TEST_TILE_TYPE Tiling = (TEST_TILE_TYPE)std::get<0>(element); TEST_BPP Bpp = (TEST_BPP)std::get<1>(element); TEST_RESOURCE_TYPE ResType = (TEST_RESOURCE_TYPE)std::get<2>(element); bool IsRT = std::get<3>(element); // True for RT, False for Depth int TestDimIdx = std::get<4>(element); //index into TestDimensions array int ArrayIdx = std::get<5>(element); //index into TestArraySize TileSize = (Tiling == TEST_TILEYS) ? GMM_KBYTE(64) : GMM_KBYTE(4); //Discard un-supported Tiling/Res_type/bpp for this test if(ResType != TEST_RESOURCE_2D || Tiling >= TEST_TILEYF //No 1D/3D/Cube. Supported 2D mip-maps/array || (!IsRT && (Tiling == TEST_TILEX || !(Bpp == TEST_BPP_16 || Bpp == TEST_BPP_32)))) //depth supported on 16bit, 32bit formats only continue; SetTileFlag(gmmParams, Tiling); SetResType(gmmParams, ResType); SetResGpuFlags(gmmParams, IsRT); SetResArraySize(gmmParams, TestArraySize[ArrayIdx]); gmmParams.NoGfxMemory = 1; gmmParams.Format = SetResourceFormat(Bpp); for(uint32_t k = MSAA_2x; k <= MSAA_16x; k++) { GetAlignmentAndTileDimensionsForMSAA(Bpp, IsRT, Tiling, (TEST_MSAA)k, TileDimX, TileDimY, HAlign, VAlign, ExpectedMCSBpp, MCSHAlign, MCSVAlign); gmmParams.BaseWidth64 = TestDimensions[TestDimIdx][0] * TileDimX + 0x1; gmmParams.BaseHeight = TestDimensions[TestDimIdx][1] * TileDimY + 0x1; gmmParams.Depth = 0x1; gmmParams.MSAA.NumSamples = static_cast(pow((double)2, k)); gmmParams.Flags.Gpu.MCS = 0; //MSS surface GMM_RESOURCE_INFO *MSSResourceInfo; MSSResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); if(MSSResourceInfo) { VerifyResourceHAlign(MSSResourceInfo, HAlign); VerifyResourceVAlign(MSSResourceInfo, VAlign); if(IsRT) //Arrayed MSS { uint32_t ExpectedPitch = 0, ExpectedQPitch = 0; ExpectedPitch = GMM_ULT_ALIGN(GMM_ULT_ALIGN(gmmParams.BaseWidth64, HAlign) * (uint32_t)pow(2.0, Bpp), TileDimX); // Aligned width * bpp, aligned to TileWidth VerifyResourcePitch(MSSResourceInfo, ExpectedPitch); if(Tiling != TEST_LINEAR) VerifyResourcePitchInTiles(MSSResourceInfo, ExpectedPitch / TileDimX); ExpectedQPitch = GMM_ULT_ALIGN(gmmParams.BaseHeight, VAlign); if(gmmParams.ArraySize > 1) //Gen9: Qpitch is distance between array slices (not sample slices) { VerifyResourceQPitch(MSSResourceInfo, ExpectedQPitch); } uint32_t ExpectedHeight = GMM_ULT_ALIGN(ExpectedQPitch * gmmParams.MSAA.NumSamples * gmmParams.ArraySize, TileDimY); //Align Height =ExpectedPitch * NumSamples * ExpectedQPitch, to Tile-Height VerifyResourceSize(MSSResourceInfo, GMM_ULT_ALIGN(ExpectedPitch * ExpectedHeight, TileSize)); } else // Interleaved MSS { uint32_t WidthMultiplier, HeightMultiplier; GetInterleaveMSSPattern((TEST_MSAA)k, WidthMultiplier, HeightMultiplier, IsRT, Bpp); gmmParams.BaseWidth64 = WidthMultiplier > 1 ? GMM_ULT_ALIGN(gmmParams.BaseWidth64, 2) : gmmParams.BaseWidth64; gmmParams.BaseHeight = HeightMultiplier > 1 ? GMM_ULT_ALIGN(gmmParams.BaseHeight, 2) : gmmParams.BaseHeight; uint32_t ExpectedPitch = GMM_ULT_ALIGN(GMM_ULT_ALIGN(gmmParams.BaseWidth64 * WidthMultiplier, HAlign) * (uint32_t)pow(2.0, Bpp), TileDimX); VerifyResourcePitch(MSSResourceInfo, ExpectedPitch); if(Tiling != TEST_LINEAR) { VerifyResourcePitchInTiles(MSSResourceInfo, ExpectedPitch / TileDimX); } uint64_t ExpectedQPitch = GMM_ULT_ALIGN(gmmParams.BaseHeight * HeightMultiplier, VAlign); if(gmmParams.ArraySize > 1) { VerifyResourceQPitch(MSSResourceInfo, ExpectedQPitch); } uint64_t ExpectedHeight = GMM_ULT_ALIGN(ExpectedQPitch * gmmParams.ArraySize, TileDimY); //Align Height = ExpectedQPitch*ArraySize, to Tile-Height VerifyResourceSize(MSSResourceInfo, GMM_ULT_ALIGN(ExpectedPitch * ExpectedHeight, TileSize)); //ExpectedPitch *ExpectedHeight } } //No MCS surface if MSS creation failed if(MSSResourceInfo) { gmmParams.Flags.Gpu.MCS = 1; GMM_RESOURCE_INFO *MCSResourceInfo; MCSResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); VerifyResourceHAlign(MCSResourceInfo, MCSHAlign); VerifyResourceVAlign(MCSResourceInfo, MCSVAlign); uint32_t ExpectedPitch = GMM_ULT_ALIGN(GMM_ULT_ALIGN(gmmParams.BaseWidth64, MCSHAlign) * ExpectedMCSBpp, MCSTileSize[0][0]); // Align in texels, tehn multiply w/ Bpt VerifyResourcePitch(MCSResourceInfo, ExpectedPitch); VerifyResourcePitchInTiles(MCSResourceInfo, ExpectedPitch / MCSTileSize[0][0]); uint32_t ExpectedQPitch = GMM_ULT_ALIGN(gmmParams.BaseHeight, MCSVAlign); if(gmmParams.ArraySize > 1) { ExpectedQPitch = GMM_ULT_ALIGN(gmmParams.BaseHeight, MCSVAlign); //QPitch only for array VerifyResourceQPitch(MCSResourceInfo, ExpectedQPitch); } uint32_t ExpectedHeight = GMM_ULT_ALIGN(ExpectedQPitch * gmmParams.ArraySize, MCSTileSize[0][1]); VerifyResourceSize(MCSResourceInfo, GMM_ULT_ALIGN(ExpectedPitch * ExpectedHeight, GMM_KBYTE(4))); //MCS Tile is TileY pGmmULTClientContext->DestroyResInfoObject(MCSResourceInfo); } //MCS pGmmULTClientContext->DestroyResInfoObject(MSSResourceInfo); } //NumSamples = k } //Iterate through all Input types //Mip-mapped, MSAA case: } int BuildInputIterator(std::vector> &List, int maxTestDimension, int TestArraySize) { for(uint32_t i = TEST_LINEAR; i < TEST_TILE_MAX; i++) for(uint32_t j = TEST_BPP_8; j < TEST_BPP_MAX; j++) for(uint32_t k = TEST_RESOURCE_1D; k < TEST_RESOURCE_MAX; k++) for(uint32_t l = 0; l < maxTestDimension; l++) for(uint32_t m = 0; m < TestArraySize; m++) { List.emplace_back(make_tuple(i, j, k, l, m)); } return List.size(); } /// @brief ULT for Color control Resource (non-MSAA compression) TEST_F(CTestGen9Resource, TestCCS) { const uint32_t CCSTileSize[1][2] = {128, 32}; //CCS is TileY const uint32_t TestDimensions[4][3] = { //Input dimensions in #Tiles {0, 0, 0}, //1x1x1 {1, 0, 0}, //2 Tilesx1x1 {1, 1, 0}, //2 Tilesx 2x1 {1, 1, 1}, //2 Tilesx 2x2 }; uint32_t TestArraySize[2] = {1, 9}; uint32_t RTHAlign = 128, RTVAlign = 64; //Gen9 CCS's RT should be aligned to 128x64 uint32_t TileDimX, TileDimY, TileDimZ, WidthDivisor, HeightDivisor, TileSize; uint32_t ExpectedMCSBpp; std::vector> List; //TEST_TILE_TYPE, TEST_BPP, TEST_RESOURCE_TYPE, TestDimension index, TestArraySize index auto Size = BuildInputIterator(List, 4, 2); // Send size of TestDimensions, TestArraySize for(auto element : List) { GMM_RESCREATE_PARAMS gmmParams = {}; gmmParams.Flags.Info = {0}; TEST_TILE_TYPE Tiling = (TEST_TILE_TYPE)std::get<0>(element); TEST_BPP Bpp = (TEST_BPP)std::get<1>(element); TEST_RESOURCE_TYPE ResType = (TEST_RESOURCE_TYPE)std::get<2>(element); int TestDimIdx = std::get<3>(element); //index into TestDimensions array int ArrayIdx = std::get<4>(element); //index into TestArraySize TileSize = (Tiling == TEST_TILEYS) ? GMM_KBYTE(64) : GMM_KBYTE(4); //Discard if un-supported Tiling/Res_type/bpp for this test if(Tiling < TEST_TILEY || !(Bpp == TEST_BPP_32 || //Gen8: NO TileYs/Yf, CCS not supported for !TileY/Yf/Ys/X - gen8 support tilex Bpp == TEST_BPP_64 || Bpp == TEST_BPP_128) || //LRTC not supported on <32bpp ResType == TEST_RESOURCE_1D || ResType == TEST_RESOURCE_BUFFER) //non-MSAA CCS, 1D is showing issues CCS becoming linear (Buffer is linear) continue; SetTileFlag(gmmParams, Tiling); SetResType(gmmParams, ResType); SetResGpuFlags(gmmParams, true); //Depth not Supported w/ CCS. Depth only has HiZ, and IMS SetResArraySize(gmmParams, TestArraySize[ArrayIdx]); gmmParams.NoGfxMemory = 1; gmmParams.Format = SetResourceFormat(Bpp); GetAlignmentAndTileDimensionsForCCS(Bpp, Tiling, ResType, TileDimX, TileDimY, TileDimZ, WidthDivisor, HeightDivisor); gmmParams.BaseWidth64 = TestDimensions[TestDimIdx][0] * TileDimX + 0x1; gmmParams.BaseHeight = (gmmParams.Type == RESOURCE_CUBE) ? gmmParams.BaseWidth64 : TestDimensions[TestDimIdx][1] * TileDimY + 0x1; gmmParams.Depth = (gmmParams.Type == RESOURCE_3D) ? TestDimensions[TestDimIdx][2] * TileDimZ + 0x1 : 0x1; gmmParams.MSAA.NumSamples = 1; gmmParams.Flags.Gpu.CCS = 0; //RT surface GMM_RESOURCE_INFO *RTResourceInfo; RTResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); //No CCS surface if RT creation failed if(RTResourceInfo) { gmmParams.Flags.Gpu.CCS = 1; GMM_RESOURCE_INFO *CCSResourceInfo; CCSResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); VerifyResourceHAlign(CCSResourceInfo, RTHAlign); //Check if RT for CCS creation was aligned to CCS's RT alignment VerifyResourceVAlign(CCSResourceInfo, RTVAlign); uint32_t ExpectedPitch = GMM_ULT_ALIGN((uint32_t)(GMM_ULT_ALIGN(gmmParams.BaseWidth64, RTHAlign) / WidthDivisor), CCSTileSize[0][0]); VerifyResourcePitch(CCSResourceInfo, ExpectedPitch); VerifyResourcePitchInTiles(CCSResourceInfo, ExpectedPitch / CCSTileSize[0][0]); // 1 tileY wide uint32_t ExpectedQPitch = GMM_ULT_ALIGN(gmmParams.BaseHeight, RTVAlign); // / HeightDivisor; if(gmmParams.ArraySize > 1 || gmmParams.Type == RESOURCE_CUBE || gmmParams.Type == RESOURCE_3D) { uint32_t DepthSlice = gmmParams.Depth; //if (gmmParams.Type == RESOURCE_3D && DepthSlice > 1) //{ // ExpectedQPitch *= DepthSlice; //} //else { // Should 3D surface Aux QPitch be distance between R-slices or not // If it must be R-slice distance, compute 3D QPitch, remove depthslice from arraysize VerifyResourceQPitch(CCSResourceInfo, ExpectedQPitch); //verify false, else QPitch given for RT-size not CCS //} gmmParams.ArraySize *= (gmmParams.Type == RESOURCE_3D) ? DepthSlice : //3D R-slices (gmmParams.Type == RESOURCE_CUBE) ? 6 : 1; //cube faces treated as array slices } ExpectedQPitch /= HeightDivisor; uint32_t ExpectedHeight = GMM_ULT_ALIGN(ExpectedQPitch * gmmParams.ArraySize, CCSTileSize[0][1]); VerifyResourceSize(CCSResourceInfo, GMM_ULT_ALIGN(ExpectedPitch * ExpectedHeight, GMM_KBYTE(4))); pGmmULTClientContext->DestroyResInfoObject(CCSResourceInfo); } //CCS pGmmULTClientContext->DestroyResInfoObject(RTResourceInfo); } //Iterate through all input tuples // Mip-mapped case } /// @brief ULT for MMC Resource TEST_F(CTestGen9Resource, TestMMC) { const TEST_TILE_TYPE TileTypeSupported[3] = {TEST_TILEY, TEST_TILEYS, TEST_TILEYF}; const uint32_t TileSize[3][TEST_BPP_MAX][2] = { {{128, 32}, {128, 32}, {128, 32}, {128, 32}, {128, 32}}, // TileY {{256, 256}, {512, 128}, {512, 128}, {1024, 64}, {1024, 64}}, // TileYs {{64, 64}, {128, 32}, {128, 32}, {256, 16}, {256, 16}}}; // TileYf // Normal 2D surface for(uint32_t Tile : TileTypeSupported) { GMM_RESCREATE_PARAMS gmmParams = {}; gmmParams.Type = RESOURCE_2D; gmmParams.NoGfxMemory = 1; gmmParams.Flags.Gpu.Texture = 1; gmmParams.Flags.Gpu.MMC = 1; gmmParams.BaseWidth64 = 0x100; gmmParams.BaseHeight = 0x50; gmmParams.Depth = 0x1; SetTileFlag(gmmParams, static_cast(Tile)); for(uint32_t i = 0; i < TEST_BPP_MAX; i++) { TEST_BPP bpp = static_cast(i); gmmParams.Format = SetResourceFormat(bpp); GMM_RESOURCE_INFO *ResourceInfo; ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); uint32_t ExpectedPitch = GMM_ULT_ALIGN(gmmParams.BaseWidth64, TileSize[Tile - TEST_TILEY][i][0] / GetBppValue(bpp)); ExpectedPitch *= GetBppValue(bpp); ExpectedPitch += TileSize[Tile - TEST_TILEY][i][0]; // MMC will have extra tile on the right VerifyResourcePitch(ResourceInfo, ExpectedPitch); VerifyResourcePitchInTiles(ResourceInfo, ExpectedPitch / TileSize[Tile - TEST_TILEY][i][0]); uint32_t Size = GMM_ULT_ALIGN(gmmParams.BaseHeight, TileSize[Tile - TEST_TILEY][i][1]) * ExpectedPitch; VerifyResourceSize(ResourceInfo, GMM_ULT_ALIGN(Size, GMM_KBYTE(4))); VerifyResourceHAlign(ResourceInfo, 0); // Tested elsewhere VerifyResourceVAlign(ResourceInfo, 0); // Tested elsewhere VerifyResourceQPitch(ResourceInfo, 0); // N/A for non-mipped surface pGmmULTClientContext->DestroyResInfoObject(ResourceInfo); } } // Planar 2D surface { GMM_RESCREATE_PARAMS gmmParams = {}; gmmParams.Type = RESOURCE_2D; gmmParams.NoGfxMemory = 1; gmmParams.Flags.Gpu.Texture = 1; gmmParams.Flags.Gpu.MMC = 1; gmmParams.BaseWidth64 = 0x100; gmmParams.BaseHeight = 0x50; gmmParams.Depth = 0x1; SetTileFlag(gmmParams, TEST_TILEY); // TileY only gmmParams.Format = GMM_FORMAT_NV12; // 8bpp GMM_RESOURCE_INFO *ResourceInfo; ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); uint32_t ExpectedPitch = GMM_ULT_ALIGN(gmmParams.BaseWidth64, TileSize[0][0][0]); ExpectedPitch += TileSize[0][0][0]; // MMC will have extra tile on the right VerifyResourcePitch(ResourceInfo, ExpectedPitch); VerifyResourcePitchInTiles(ResourceInfo, ExpectedPitch / TileSize[0][0][0]); VerifyResourceSize(ResourceInfo, 0); // Tested elsewhere VerifyResourceHAlign(ResourceInfo, 0); // Tested elsewhere VerifyResourceVAlign(ResourceInfo, 0); // Tested elsewhere VerifyResourceQPitch(ResourceInfo, 0); // N/A for non-mipped surface pGmmULTClientContext->DestroyResInfoObject(ResourceInfo); } } /// @brief ULT for StdSwizzle surfaces TEST_F(CTestGen9Resource, TestStdSwizzle) { // TODO: Test RedescribedPlanes, along with other StdSwizzle mappings } gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/ULT/GmmGen9ResourceULT.h000066400000000000000000000144701466655022700242360ustar00rootroot00000000000000/*============================================================================== Copyright(c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ============================================================================*/ #pragma once #include "GmmResourceULT.h" class CTestGen9Resource : public CTestResource { protected: void FillExpectedPitch(); void FillExpectedPitchInTiles(); void FillExpectedHAlign(); void FillExpectedVAlign(); void FillExpectedDAlign(); void FillExpectedSize(); void FillExpectedQPitch(); void FillExpectedMipOffsets(); public: static void SetUpTestCase(); static void TearDownTestCase(); ///////////////////////////////////////////////////////////////////////////////////// /// Get the Tile dimension and RT->CCS downscale factor /// /// @param[in] Bpp: bits per pixel /// @param[in] Tiling: Tile Type /// @param[in] ResType: Resource Type /// @param[out] TileDimX: Tile Width for given Tile, Resource, bpp /// @param[out] TileDimY: Tile Height for given Tile, Resource, bpp /// @param[out] TileDimZ: Tile Depth for given Tile, Resource, bpp /// @param[out] WidthDivisor: RT->CCS width downscale factor /// @param[out] HeightDivisor: RT->CCS height downscale factor /// ///////////////////////////////////////////////////////////////////////////////////// void GetAlignmentAndTileDimensionsForCCS(TEST_BPP Bpp, TEST_TILE_TYPE Tiling, TEST_RESOURCE_TYPE ResType, uint32_t &TileDimX, uint32_t &TileDimY, uint32_t & TileDimZ, uint32_t &WidthDivisor, uint32_t &HeightDivisor) { const uint32_t RT2DTileSize[TEST_TILE_MAX][TEST_BPP_MAX][3] = { { { 64, 1, 1 },{ 64, 1, 1 },{ 64, 1, 1 },{ 64, 1, 1 },{ 64, 1, 1 } }, //Linear - no Tile Size, but min PitchAlign = 64 (cacheLine size) { { 512, 8, 1 },{ 512, 8,1 },{ 512, 8,1 },{ 512, 8, 1 },{ 512, 8, 1 } }, //TileX { { 128, 32, 1 },{ 128, 32, 1 },{ 128, 32, 1 },{ 128, 32, 1 },{ 128, 32, 1 } }, //TileY { { 256, 256, 1 },{ 512, 128, 1 },{ 512, 128, 1 },{ 1024, 64, 1 },{ 1024, 64, 1 } }, //TileYs { { 64, 64, 1 },{ 128, 32, 1 },{ 128, 32,1 },{ 256, 16, 1 },{ 256, 16, 1 } } //TileYf }; const uint32_t RT3DTileSize[TEST_TILE_MAX][TEST_BPP_MAX][3] = { { { 64, 1, 1 },{ 64, 1, 1 },{ 64, 1, 1 },{ 64, 1, 1 },{ 64, 1, 1 } }, //Linear - no Tile Size, but min PitchAlign = 64 (cacheLine size) { { 512, 8, 1 },{ 512, 8, 1 },{ 512, 8, 1 },{ 512, 8, 1 },{ 512, 8, 1 } }, //TileX { { 128, 32, 1 },{ 128, 32, 1 },{ 128, 32, 1 },{ 128, 32, 1 },{ 128, 32, 1 } }, //TileY { { 64, 32, 32 },{ 64, 32, 32 },{ 128, 32, 16 },{ 256, 16, 16 },{ 512, 16, 16 } }, //TileYs { { 16, 16, 16 },{ 16, 16, 16 },{ 32, 16, 8 },{ 64, 8, 8 },{ 64, 8, 8 } } //TileYf }; uint32_t TileDim[3] = { RT2DTileSize[Tiling][Bpp][0], RT2DTileSize[Tiling][Bpp][1], RT2DTileSize[Tiling][Bpp][2] }; if (ResType == TEST_RESOURCE_3D) { TileDim[0] = RT3DTileSize[Tiling][Bpp][0]; TileDim[1] = RT3DTileSize[Tiling][Bpp][1]; TileDim[2] = RT3DTileSize[Tiling][Bpp][2]; } TileDimX = TileDim[0]; TileDimY = TileDim[1]; TileDimZ = TileDim[2]; uint32_t ExpectedCCSBpp = 1; //1 byte per pixel (contains 4 2b-CCS, //Each 2b covers 2CLs = 128B RT) /*** 2b-CCS per 2CLs of RT (2:1 compression ie 2CL->1CL) 1B-CCS covers 4x2 RT CLs (as square as possible in px) CL Byte size 16 x 4 8CLs could cover {(16x32), (128x4), (64x8), (32x16)} Byte-blocks, of which last one is most-square hence should be used ie RT coverage by 1B CCS is 32x16, taking RT-bpp into account: bpp RT-coverage in pixel by 1B CCS 32 32/4 x 16 = 8x16 64 32/8 x 16 = 4x16 128 32/16 x 16 = 2x16 Finally CCS needs to be Tile-aligned (TileY) ***/ const uint32_t RTWidthDivisor[2][TEST_BPP_MAX] = { { 1, 1, 16, 8, 4 },{ 1, 1, 8, 4, 2 } }; //Divisor for TileX, TileY const uint32_t RTHeightDivisor[2] = { 8, 16 }; uint32_t Idx = (Tiling == TEST_TILEX) ? 0 : 1; WidthDivisor = RTWidthDivisor[Idx][Bpp]; HeightDivisor = RTHeightDivisor[Idx]; } ///////////////////////////////////////////////////////////////////////////////////// /// Verifies if Mip tail start Lod matches the expected value. Fails test if value /// doesn't match /// /// @param[in] ResourceInfo: ResourceInfo returned by GmmLib /// @param[in] ExpectedValue: expected value to check against ///////////////////////////////////////////////////////////////////////////////////// template void VerifyResourceMipTailStartLod(GMM_RESOURCE_INFO *ResourceInfo, uint32_t ExpectedValue) { if (Verify) { EXPECT_EQ(ExpectedValue, ResourceInfo->GetMipTailStartLodSurfaceState()); } } CTestGen9Resource(); ~CTestGen9Resource(); }; gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/ULT/GmmMultiAdapterULT.cpp000066400000000000000000000535231466655022700246540ustar00rootroot00000000000000/*========================== begin_copyright_notice ============================ Copyright(c) 2021 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ============================= end_copyright_notice ===========================*/ #include "GmmMultiAdapterULT.h" #ifndef _WIN32 #include #endif #include MACommonULT::MACommonULT() { // Ideally this should be in the SetUp function for each test case, but since there are // wrapper classes around this for the test suites and SetUp does not get called on this // class, it needs to go in the constructor which gets created for each test case. //reset all test info memset(GmmTestInfo, 0, sizeof(GmmTestInfo)); memset(AdapterSaved, 0, sizeof(AdapterSaved)); hGmmLib = NULL; pfnGmmDestroy = NULL; pfnGmmInit = NULL; //set a seed value so the test is always reproducible srand(0); // Save the random Generated bdf value in an array during intantiation itself // These value remain live for each of the ULT lifetime. for (int i = 0; i < MAX_NUM_ADAPTERS; i++) { AdapterSaved[i].Bus = rand() / 100; AdapterSaved[i].Device = rand() / 100; AdapterSaved[i].Function = rand() / 100; AdapterSaved[i].Reserved = 0; } // Validate the generated BDfs are unique // No two Adapter's BDF should be equal on a PCI bus. for (int i = 0; i < MAX_NUM_ADAPTERS; i++) { for (int j = 0; j < MAX_NUM_ADAPTERS; j++) { if (i != j) { if (AdapterSaved[i].Bus == AdapterSaved[j].Bus) { if (AdapterSaved[i].Device == AdapterSaved[j].Device) { if (AdapterSaved[i].Function == AdapterSaved[j].Function) { // OOps! Generated BDFs are equal. // Lets change any one field to make it unique // Lets increment Bus. AdapterSaved[j].Bus++; } } } } } } } MACommonULT::~MACommonULT() { } CTestMA::CTestMA() { } CTestMA::~CTestMA() { } void CTestMA::SetUpTestCase() { } void CTestMA::TearDownTestCase() { } void CTestMA::SetUp() { LoadGmmDll(); } void CTestMA::TearDown() { UnLoadGmmDll(); } void MACommonULT::LoadGmmDll() { hGmmLib = dlopen(GMM_UMD_DLL, RTLD_LAZY); ASSERT_TRUE(hGmmLib); *(void **)(&pfnGmmInit) = dlsym(hGmmLib, "InitializeGmm"); *(void **)(&pfnGmmDestroy) = dlsym(hGmmLib, "GmmAdapterDestroy"); ASSERT_TRUE(pfnGmmInit); ASSERT_TRUE(pfnGmmDestroy); } void MACommonULT::UnLoadGmmDll() { if (hGmmLib) { dlclose(hGmmLib); hGmmLib = NULL; pfnGmmInit = NULL; pfnGmmDestroy = NULL; } } // Lets test with the recent GPUs till 32nd adapters and take IGFX_COFFEELAKE for 32+ adapters // Only for our ULT to supply dummy ProductFamily PRODUCT_FAMILY MACommonULT::GetProductFamily(uint32_t AdapterIdx) { switch (AdapterIdx) { case 0: return IGFX_DG1; case 1: return IGFX_ICELAKE; case 2: return IGFX_TIGERLAKE_LP; case 3: case 4: case 5: case 6: case 7: case 8: case 9: return IGFX_DG2; case 11: case 12: case 13: case 14: case 15: case 16: return IGFX_XE_HP_SDV; case 17: case 18: case 19: case 20: case 21: case 22: case 23: case 24: case 25: case 26: case 27: case 28: case 29: return IGFX_PVC; case 30: case 31: default: break; } return IGFX_COFFEELAKE; } // Lets test with the recent GPUs till 32nd adpater and take IGFX_GEN9_CORE for 32+ adapters // Only for our ULT to supply dummy GFXCORE_FAMILY GFXCORE_FAMILY MACommonULT::GetRenderCoreFamily(uint32_t AdapterIdx) { switch (AdapterIdx) { case 0: return IGFX_XE_HP_CORE; case 1: return IGFX_GEN11LP_CORE; case 2: return IGFX_GEN12LP_CORE; case 3: case 4: case 5: case 6: case 7: case 8: case 9: return IGFX_XE_HPG_CORE; case 11: case 12: case 13: case 14: case 15: case 16: return IGFX_XE_HP_CORE; case 17: case 18: case 19: case 20: case 21: case 22: case 23: case 24: case 25: case 26: case 27: case 28: case 29: return IGFX_XE_HPC_CORE; case 30: case 31: default: break; } return IGFX_GEN9_CORE; } // To simulate the UMDs/ClinentContexts per adapter i.e MAX_COUNT_PER_ADAPTER // Increase MAX_COUNT_PER_ADAPTER value if there are more UMDs involved GMM_CLIENT MACommonULT::GetClientType(uint32_t CountIdx) { switch (CountIdx) { case 0: return GMM_D3D9_VISTA; case 1: return GMM_D3D10_VISTA; case 2: return GMM_D3D12_VISTA; case 3: return GMM_EXCITE_VISTA; case 4: return GMM_OCL_VISTA; default: break; } return GMM_D3D9_VISTA; } // Returns the AdapterSaved array value, Adapter BDFs based on input AdapterIdx ADAPTER_BDF MACommonULT::GetAdapterBDF(uint32_t AdapterIdx) { ADAPTER_BDF AdapterBDF = {0, 2, 0, 0}; if (AdapterIdx < MAX_NUM_ADAPTERS) { AdapterBDF.Bus = AdapterSaved[AdapterIdx].Bus; AdapterBDF.Device = AdapterSaved[AdapterIdx].Device; AdapterBDF.Function = AdapterSaved[AdapterIdx].Function; } return AdapterBDF; } void MACommonULT::GmmInitModule(uint32_t AdapterIdx, uint32_t CountIdx) { ASSERT_TRUE(AdapterIdx < MAX_NUM_ADAPTERS); GMM_STATUS Status = GMM_SUCCESS; ADAPTER_BDF AdapterBDF = GetAdapterBDF(AdapterIdx); GmmTestInfo[AdapterIdx][CountIdx].GfxPlatform.eProductFamily = GetProductFamily(AdapterIdx); GmmTestInfo[AdapterIdx][CountIdx].GfxPlatform.eRenderCoreFamily = GetRenderCoreFamily(AdapterIdx); if (!GmmTestInfo[AdapterIdx][CountIdx].pGfxAdapterInfo) { GmmTestInfo[AdapterIdx][CountIdx].pGfxAdapterInfo = (ADAPTER_INFO *)malloc(sizeof(ADAPTER_INFO)); if (!GmmTestInfo[AdapterIdx][CountIdx].pGfxAdapterInfo) { ASSERT_TRUE(false); return; } memset(GmmTestInfo[AdapterIdx][CountIdx].pGfxAdapterInfo, 0, sizeof(ADAPTER_INFO)); GmmTestInfo[AdapterIdx][CountIdx].pGfxAdapterInfo->SkuTable.FtrTileY = 1; // Legacy TileY if (GmmTestInfo[AdapterIdx][CountIdx].GfxPlatform.eRenderCoreFamily >= IGFX_GEN12_CORE) { GmmTestInfo[AdapterIdx][CountIdx].pGfxAdapterInfo->SkuTable.FtrWddm2GpuMmu = 1; GmmTestInfo[AdapterIdx][CountIdx].pGfxAdapterInfo->SkuTable.FtrUserModeTranslationTable = 1; GmmTestInfo[AdapterIdx][CountIdx].pGfxAdapterInfo->SkuTable.FtrE2ECompression = 1; GmmTestInfo[AdapterIdx][CountIdx].pGfxAdapterInfo->SkuTable.FtrLinearCCS = 1; GmmTestInfo[AdapterIdx][CountIdx].pGfxAdapterInfo->SkuTable.FtrTileY = 1; GmmTestInfo[AdapterIdx][CountIdx].pGfxAdapterInfo->SkuTable.FtrLLCBypass = 0; GmmTestInfo[AdapterIdx][CountIdx].pGfxAdapterInfo->SkuTable.FtrWddm2Svm = 0; // keep this disabled for pagetablemgr testing GmmTestInfo[AdapterIdx][CountIdx].pGfxAdapterInfo->SkuTable.FtrSVM = 1; // keep this enabled for pagetablemgr testing //GmmTestInfo[AdapterIdx][CountIdx].pGfxAdapterInfo->SkuTable.WaUntypedBufferCompression = 1; } if (IGFX_DG1 == GmmTestInfo[AdapterIdx][CountIdx].GfxPlatform.eProductFamily) { GmmTestInfo[AdapterIdx][CountIdx].pGfxAdapterInfo->SkuTable.FtrLinearCCS = 1; GmmTestInfo[AdapterIdx][CountIdx].pGfxAdapterInfo->SkuTable.FtrStandardMipTailFormat = 1; GmmTestInfo[AdapterIdx][CountIdx].pGfxAdapterInfo->SkuTable.FtrTileY = 0; GmmTestInfo[AdapterIdx][CountIdx].pGfxAdapterInfo->SkuTable.FtrLocalMemory = 1; GmmTestInfo[AdapterIdx][CountIdx].pGfxAdapterInfo->SkuTable.FtrWddm2_1_64kbPages = 1; } } GmmTestInfo[AdapterIdx][CountIdx].InArgs.ClientType = GetClientType(CountIdx); GmmTestInfo[AdapterIdx][CountIdx].InArgs.pGtSysInfo = &GmmTestInfo[AdapterIdx][CountIdx].pGfxAdapterInfo->SystemInfo; GmmTestInfo[AdapterIdx][CountIdx].InArgs.pSkuTable = &GmmTestInfo[AdapterIdx][CountIdx].pGfxAdapterInfo->SkuTable; GmmTestInfo[AdapterIdx][CountIdx].InArgs.pWaTable = &GmmTestInfo[AdapterIdx][CountIdx].pGfxAdapterInfo->WaTable; GmmTestInfo[AdapterIdx][CountIdx].InArgs.Platform = GmmTestInfo[AdapterIdx][CountIdx].GfxPlatform; #if LHDM GmmTestInfo[AdapterIdx][CountIdx].InArgs.stAdapterBDF = AdapterBDF; GmmTestInfo[AdapterIdx][CountIdx].InArgs.DeviceRegistryPath = NULL; #else GmmTestInfo[AdapterIdx][CountIdx].InArgs.FileDescriptor = AdapterBDF.Data; #endif Status = pfnGmmInit(&GmmTestInfo[AdapterIdx][CountIdx].InArgs, &GmmTestInfo[AdapterIdx][CountIdx].OutArgs); EXPECT_EQ(Status, GMM_SUCCESS); GmmTestInfo[AdapterIdx][CountIdx].pGmmULTClientContext = GmmTestInfo[AdapterIdx][CountIdx].OutArgs.pGmmClientContext; ASSERT_TRUE(GmmTestInfo[AdapterIdx][CountIdx].pGmmULTClientContext); GmmTestInfo[AdapterIdx][CountIdx].pLibContext = GmmTestInfo[AdapterIdx][CountIdx].pGmmULTClientContext->GetLibContext(); ASSERT_TRUE(GmmTestInfo[AdapterIdx][CountIdx].pLibContext); } void MACommonULT::GmmDestroyModule(uint32_t AdapterIdx, uint32_t CountIdx) { GmmTestInfo[AdapterIdx][CountIdx].OutArgs.pGmmClientContext = GmmTestInfo[AdapterIdx][CountIdx].pGmmULTClientContext; pfnGmmDestroy(&GmmTestInfo[AdapterIdx][CountIdx].OutArgs); GmmTestInfo[AdapterIdx][CountIdx].pGmmULTClientContext = NULL; GmmTestInfo[AdapterIdx][CountIdx].pLibContext = NULL; if (GmmTestInfo[AdapterIdx][CountIdx].pGfxAdapterInfo) { free(GmmTestInfo[AdapterIdx][CountIdx].pGfxAdapterInfo); GmmTestInfo[AdapterIdx][CountIdx].pGfxAdapterInfo = NULL; } } // This member function creates MaxClientThreads number of threads // MaxClientsThreads to represent total numbers of UMD Clients // MaxClientsThreads = MAX_NUM_ADAPTERS for ULT TestMTLoadMultipleAdapters // MaxClientsThreads = MAX_COUNT_PER_ADAPTER for ULT TestMTLoadAdaptersMultipleTimes // MaxClientsThreads = MAX_NUM_ADAPTERS * MAX_COUNT_PER_ADAPTER, for ULT TestMTLoadMultipleAdaptersMultipleTimes static void CreateMAThread(uint32_t MaxClientThreads, ThreadInParams *InParams) { // Spawn all threads upto MaxClientThreads and wait for them all at once uint32_t i = 0; int Status; /* return value */ pthread_t thread_id[MAX_NUM_ADAPTERS * MAX_COUNT_PER_ADAPTER]; /* thread's ID (just an integer) */ /* MaxClientsThreads to represent MAX_NUM_ADAPTERS *MAX_COUNT_PER_ADAPTER Clients */ for (i = 0; i < (MaxClientThreads); i++) { Status = pthread_create(&thread_id[i], NULL, MAULTThreadEntryFunc, (void *)&InParams[i]); ASSERT_TRUE((!Status)); } /* wait for threads to terminate */ for (i = 0; i < (MaxClientThreads); i++) { Status = pthread_join(thread_id[i], NULL); ASSERT_TRUE((!Status)); } } void *MAULTThreadEntryFunc(void *lpParam) { ThreadInParams *pInParams = (ThreadInParams *)(lpParam); pInParams->MATestObj->GmmInitModule(pInParams->AdapterIdx, pInParams->CountIdx); pInParams->MATestObj->GmmDestroyModule(pInParams->AdapterIdx, pInParams->CountIdx); pthread_exit(NULL); } #if GMM_LIB_DLL_MA /* To simulate the real time scenario between the Gmmlib and the UMD clients Folowing ULTs assume: MAX_NUM_ADAPTERS = Number of GPU Adapters (BDFs) available on a system at a given point of time. MAX_COUNT_PER_ADAPTER = Number of UMD clients that can be simulated per Adapter So Total clients simulated = MAX_NUM_ADAPTERS * MAX_COUNT_PER_ADAPTER Where, The LibContext for an Adapter is equal across all Clients for that adapter The ClientConetxt is unique(Not equal) across all Clients for that adapter */ // Load multiple Adapters in the same process with the Limit up to MAX_NUM_ADAPTERS // Increase MAX_NUM_ADAPTERS > 32 if needed TEST_F(CTestMA, TestLoadMultipleAdapters) { uint32_t AdapterCount = 0; uint32_t i = 0; // Initilize the dll for all available adapters for (AdapterCount = 0; AdapterCount < MAX_NUM_ADAPTERS; AdapterCount++) { GmmInitModule(AdapterCount, 0); } // Check the Libcontext for each of the adapter is different or not for (AdapterCount = 0; AdapterCount < MAX_NUM_ADAPTERS; AdapterCount++) { for (i = 0; i < MAX_NUM_ADAPTERS; i++) { if (AdapterCount != i) { EXPECT_NE(GmmTestInfo[AdapterCount][0].pLibContext, GmmTestInfo[i][0].pLibContext); } } } // Un-Initilize the dll for all loaded adapters for (AdapterCount = 0; AdapterCount < MAX_NUM_ADAPTERS; AdapterCount++) { GmmDestroyModule(AdapterCount, 0); } } /// Load all adapters(MAX_NUM_ADAPTERS) multiple times up to MAX_COUNT_PER_ADAPTER in same process TEST_F(CTestMA, TestLoadAdapterMultipleTimes) { uint32_t AdapterCount = 0, RefCount = 0; // Initilize the dll upto MAX_COUNT_PER_ADAPTER times for each of MAX_NUM_ADAPTERS adapters for (AdapterCount = 0; AdapterCount < MAX_NUM_ADAPTERS; AdapterCount++) { for (RefCount = 0; RefCount < MAX_COUNT_PER_ADAPTER; RefCount++) { GmmInitModule(AdapterCount, RefCount); } } // For each adapter upto MAX_NUM_ADAPTERS Check the LibContext for all instances upto // MAX_COUNT_PER_ADAPTER to be equal for (AdapterCount = 0; AdapterCount < MAX_NUM_ADAPTERS; AdapterCount++) { for (RefCount = 0; RefCount < MAX_COUNT_PER_ADAPTER - 1; RefCount++) { EXPECT_EQ(GmmTestInfo[AdapterCount][RefCount].pLibContext, GmmTestInfo[AdapterCount][RefCount + 1].pLibContext); } } // Un-Initilize the dll upto MAX_COUNT_PER_ADAPTER times for each of MAX_NUM_ADAPTERS adapters // The destroy/unload can be out of order for (AdapterCount = 0; AdapterCount < MAX_NUM_ADAPTERS; AdapterCount++) { for (RefCount = 0; RefCount < MAX_COUNT_PER_ADAPTER; RefCount++) { GmmDestroyModule(AdapterCount, RefCount); } } } /// Test Init-Destroy multiple times Upto MAX_COUNT_PER_ADAPTER before Unloading DLL, on Same Adapter upto MAX_NUM_ADAPTERS TEST_F(CTestMA, TestInitDestroyMultipleTimesOnSameAdapter) { uint32_t AdapterCount = 0, RefCount = 0; // Initilize and destroy module upto MAX_COUNT_PER_ADAPTER times for each of MAX_NUM_ADAPTERS adapters // For each adapter(AdapterCount < MAX_NUM_ADAPTERS) Check the LibContext for all instances to be equal for (AdapterCount = 0; AdapterCount < MAX_NUM_ADAPTERS; AdapterCount++) { // Initilize the dll upto MAX_COUNT_PER_ADAPTER times for each adapter // In reality the init and destroy can occurs any number of time on a particular adapter, so for simplcity treating that UMD // will load already loaded lib again for MAX_COUNT_PER_ADAPTER times. for (RefCount = 0; RefCount < MAX_COUNT_PER_ADAPTER; RefCount++) { GmmInitModule(AdapterCount, RefCount); } // Check the LibContext for all instances on a same adapter to be equal // It might also seems that LibContext pointer value on next adapters is same as previous pointer value returned in previous adapter init. // This is the OS Memory Manager's role to avoid fragmentation in the process VA space // Also our ULT is a Light-Weight process due to which the freed memory not assigned to other processes may get assigned again. // But mind that this is possible only when the previous libcontext intialized is compulsorily inactive and destroyed. // otherwise the same secnario as in TestLoadMultipleAdapters occurs .i.e different pointer value is returned on new adpater bdf. for (RefCount = 0; RefCount < MAX_COUNT_PER_ADAPTER - 1; RefCount++) { EXPECT_EQ(GmmTestInfo[AdapterCount][RefCount].pLibContext, GmmTestInfo[AdapterCount][RefCount + 1].pLibContext); } // Un-Initilize the dll upto MAX_COUNT_PER_ADAPTER times for each adapter for (RefCount = 0; RefCount < MAX_COUNT_PER_ADAPTER; RefCount++) { GmmDestroyModule(AdapterCount, RefCount); } } } /// Test Init-Destroy multiple times before Unloading DLL, on Multiple Adapters TEST_F(CTestMA, TestInitDestroyMultipleTimesOnMultiAdapter) { uint32_t AdapterCount = 0, RefCount = 0; // Initilize and destroy the dll upto MAX_COUNT_PER_ADAPTER times for each of MAX_NUM_ADAPTERS adapters // For each adapter(AdapterCount < MAX_NUM_ADAPTERS) Check the LibContext for all instances to is unique // This is similar to TestInitDestroyMultipleTimesOnSameAdapter ULT apart from the order of adapter initialization. for (RefCount = 0; RefCount < MAX_COUNT_PER_ADAPTER; RefCount++) { // Initilize the dll upto MAX_COUNT_PER_ADAPTER times for each adapter for (AdapterCount = 0; AdapterCount < MAX_NUM_ADAPTERS; AdapterCount++) { GmmInitModule(AdapterCount, RefCount); } // Check the LibContext for each of the adpater(upto MAX_NUM_ADAPTERS) to be unique // whereas LibContext for all instances on a same adapter is to be equal for (AdapterCount = 0; AdapterCount < MAX_NUM_ADAPTERS - 1; AdapterCount++) { EXPECT_NE(GmmTestInfo[AdapterCount][RefCount].pLibContext, GmmTestInfo[AdapterCount + 1][RefCount].pLibContext); } for (AdapterCount = 0; AdapterCount < MAX_NUM_ADAPTERS; AdapterCount++) { GmmDestroyModule(AdapterCount, RefCount); } } } /* Following ULT's Exhibit the multitasking behaviour of UMDs considering that all UMDs loads and unloads dll in parallel and in random order. */ // Load Multiple Adapters upto MAX_NUM_ADAPTERS on multiple threads in same process at the same time // Here the number of client per adapter is 1 .i.e 0th count Index TEST_F(CTestMA, TestMTLoadMultipleAdapters) { uint32_t AdapterCount = 0; ThreadInParams InParams[MAX_NUM_ADAPTERS * MAX_COUNT_PER_ADAPTER]; memset(InParams, 0, sizeof(InParams)); //Populate the Inparams array with the MAX_NUM_ADAPTERS indices for (AdapterCount = 0; AdapterCount < MAX_NUM_ADAPTERS; AdapterCount++) { InParams[AdapterCount].AdapterIdx = AdapterCount; InParams[AdapterCount].CountIdx = 0; InParams[AdapterCount].MATestObj = this; } // Create threads to load all Adapters upto MAX_NUM_ADAPTERS for a single client each CreateMAThread(MAX_NUM_ADAPTERS, InParams); } // Load a Single Adapter multiple times upto MAX_COUNT_PER_ADAPTER on multiple threads in same process TEST_F(CTestMA, TestMTLoadAdaptersMultipleTimes) { uint32_t RefCount = 0; ThreadInParams InParams[MAX_NUM_ADAPTERS * MAX_COUNT_PER_ADAPTER]; memset(InParams, 0, sizeof(InParams)); //Populate the Inparams array with MAX_COUNT_PER_ADAPTER indices for (RefCount = 0; RefCount < MAX_COUNT_PER_ADAPTER; RefCount++) { InParams[RefCount].AdapterIdx = 0; InParams[RefCount].CountIdx = RefCount; InParams[RefCount].MATestObj = this; } // Create threads to load all clients i.e MAX_COUNT_PER_ADAPTER on single adpater CreateMAThread(MAX_COUNT_PER_ADAPTER, InParams); } // Load Multiple Adapters upto MAX_NUM_ADAPTERS, multiple times upto MAX_COUNT_PER_ADAPTER on multiple threads in same process TEST_F(CTestMA, TestMTLoadMultipleAdaptersMultipleTimes) { uint32_t i = 0, j = 0, k = 0; uint32_t AdapterCount = 0, RefCount = 0; ThreadInParams InParams[MAX_NUM_ADAPTERS * MAX_COUNT_PER_ADAPTER]; memset(InParams, 0, sizeof(InParams)); //Populate the Inparams array with the MAX_NUM_ADAPTERS*MAX_COUNT_PER_ADAPTER indices //Such that Each Adapter corresponds to its max mumber of clients in a sequential order for (i = 0; i < (MAX_NUM_ADAPTERS * MAX_COUNT_PER_ADAPTER); i++) { for (j = 0; j < MAX_NUM_ADAPTERS; j++) { for (k = 0; k < MAX_COUNT_PER_ADAPTER; k++) { InParams[i].AdapterIdx = AdapterCount; InParams[i].CountIdx = RefCount++; InParams[i].MATestObj = this; i++; } RefCount = 0; AdapterCount++; } } // Create threads to load MAX_NUM_ADAPTERS, MAX_COUNT_PER_ADAPTER times // Thread Count = MAX_NUM_ADAPTERS * MAX_COUNT_PER_ADAPTER CreateMAThread(MAX_NUM_ADAPTERS * MAX_COUNT_PER_ADAPTER, InParams); } #endif // GMM_LIB_DLL_MA gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/ULT/GmmMultiAdapterULT.h000066400000000000000000000057771466655022700243310ustar00rootroot00000000000000/*========================== begin_copyright_notice ============================ Copyright(c) 2021 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ============================= end_copyright_notice ===========================*/ #pragma once #include "stdafx.h" #include "GmmCommonULT.h" #include "../inc/External/Common/GmmClientContext.h" #define MAX_COUNT_PER_ADAPTER 5 #ifdef _WIN32 #define GMM_DLL_HANDLE HINSTANCE #else #define GMM_DLL_HANDLE void* #endif typedef struct GmmULTInfo_Rec { ADAPTER_INFO *pGfxAdapterInfo; PLATFORM GfxPlatform; GMM_LIB_CONTEXT *pLibContext; GMM_CLIENT_CONTEXT *pGmmULTClientContext; GMM_INIT_IN_ARGS InArgs; GMM_INIT_OUT_ARGS OutArgs; } GmmULTInfo; class MACommonULT : public testing::Test { public: MACommonULT(); ~MACommonULT(); void LoadGmmDll(); void UnLoadGmmDll(); void GmmInitModule(uint32_t AdapterIdx, uint32_t CountIdx); void GmmDestroyModule(uint32_t AdapterIdx, uint32_t CountIdx); PRODUCT_FAMILY GetProductFamily(uint32_t AdapterIdx); GFXCORE_FAMILY GetRenderCoreFamily(uint32_t AdapterIdx); GMM_CLIENT GetClientType(uint32_t CountIdx); ADAPTER_BDF GetAdapterBDF(uint32_t AdapterIdx); protected: GmmULTInfo GmmTestInfo[MAX_NUM_ADAPTERS][MAX_COUNT_PER_ADAPTER]; GMM_DLL_HANDLE hGmmLib; PFNGMMINIT pfnGmmInit; PFNGMMDESTROY pfnGmmDestroy; // Array to store the adapter BDFs from simulated UMD, Save the adapter bdf in an array ADAPTER_BDF AdapterSaved[MAX_NUM_ADAPTERS]; }; typedef MACommonULT GMM_MA_ULT_CONTEXT; typedef struct ThreadInParams_Rec { uint32_t AdapterIdx; uint32_t CountIdx; GMM_MA_ULT_CONTEXT *MATestObj; } ThreadInParams; class CTestMA : public MACommonULT { public: CTestMA(); ~CTestMA(); void SetUp() override; void TearDown() override; static void SetUpTestCase(); static void TearDownTestCase(); }; #ifdef _WIN32 DWORD WINAPI MAULTThreadEntryFunc(LPVOID lpParam); #else void *MAULTThreadEntryFunc(void *lpParam); #endif gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/ULT/GmmResourceCpuBltULT.cpp000066400000000000000000000042361466655022700251570ustar00rootroot00000000000000/*============================================================================== Copyright(c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ============================================================================*/ #include "GmmResourceULT.h" using namespace std; ///////////////////////////////////////////////////////////////////////////////////// /// CTestCpuBltResource Constructor /// ///////////////////////////////////////////////////////////////////////////////////// CTestCpuBltResource::CTestCpuBltResource() { } ///////////////////////////////////////////////////////////////////////////////////// /// CTestCpuBltResource Constructor /// ///////////////////////////////////////////////////////////////////////////////////// CTestCpuBltResource::~CTestCpuBltResource() { } void CTestCpuBltResource::SetUpTestCase() { } void CTestCpuBltResource::TearDownTestCase() { } /// @brief ULT for 1D Resource TEST_F(CTestCpuBltResource, TestCpuBlt1D) { } /// @brief ULT for 2D Resource TEST_F(CTestCpuBltResource, TestCpuBlt2D) { } /// @brief ULT for 3D Resource TEST_F(CTestCpuBltResource, TestCpuBlt3D) { } /// @brief ULT for Cube Resource TEST_F(CTestCpuBltResource, TestCpuBltCube) { }gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/ULT/GmmResourceULT.cpp000066400000000000000000004622661466655022700240600ustar00rootroot00000000000000/*============================================================================== Copyright(c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ============================================================================*/ #include "GmmResourceULT.h" ///////////////////////////////////////////////////////////////////////////////////// /// CTestResource Constructor ///////////////////////////////////////////////////////////////////////////////////// CTestResource::CTestResource() { } ///////////////////////////////////////////////////////////////////////////////////// /// CTestResource Destructor /// ///////////////////////////////////////////////////////////////////////////////////// CTestResource::~CTestResource() { } ///////////////////////////////////////////////////////////////////////////////////// /// Sets up common environment for Resource fixture tests. this is called once per /// test case before executing all tests under resource fixture test case. /// It also calls SetupTestCase from CommonULT to initialize global context and others. /// /// @see CTestResource::SetUpTestCase() /// ///////////////////////////////////////////////////////////////////////////////////// void CTestResource::SetUpTestCase() { printf("%s\n", __FUNCTION__); GfxPlatform.eProductFamily = IGFX_BROADWELL; GfxPlatform.eRenderCoreFamily = IGFX_GEN8_CORE; CommonULT::SetUpTestCase(); } ///////////////////////////////////////////////////////////////////////////////////// /// Cleans up once all the tests finish execution. It also calls TearDownTestCase /// from CommonULT to destroy global context and others. /// /// @see CTestResource::TearDownTestCase() ///////////////////////////////////////////////////////////////////////////////////// void CTestResource::TearDownTestCase() { printf("%s\n", __FUNCTION__); CommonULT::TearDownTestCase(); } /// @brief ULT for 1D Linear Resource TEST_F(CTestResource, Test1DLinearResource) { // Horizontal/Vertical pixel alignment const uint32_t HAlign = 16; const uint32_t VAlign = 4; const uint32_t MinPitch = 32; const uint32_t PitchAlignment = 64; GMM_RESCREATE_PARAMS gmmParams = {}; gmmParams.Type = RESOURCE_1D; gmmParams.NoGfxMemory = 1; gmmParams.Flags.Info.Linear = 1; gmmParams.Flags.Gpu.Texture = 1; // Allocate 1x1x1 surface for(uint32_t i = 0; i < TEST_BPP_MAX; i++) { TEST_BPP bpp = static_cast(i); gmmParams.Format = SetResourceFormat(bpp); gmmParams.BaseWidth64 = 0x1; gmmParams.BaseHeight = 0x1; GMM_RESOURCE_INFO *ResourceInfo; ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); uint32_t AlignedWidth = GMM_ULT_ALIGN(gmmParams.BaseWidth64, HAlign); uint32_t AlignedHeight = GMM_ULT_ALIGN(gmmParams.BaseHeight, VAlign); uint32_t PitchInBytes = AlignedWidth * GetBppValue(bpp); PitchInBytes = GFX_MAX(PitchInBytes, MinPitch); PitchInBytes = GMM_ULT_ALIGN(PitchInBytes, PitchAlignment); uint32_t AlignedSize = GMM_ULT_ALIGN(PitchInBytes * AlignedHeight, PAGE_SIZE); VerifyResourceHAlign(ResourceInfo, HAlign); VerifyResourceVAlign(ResourceInfo, VAlign); VerifyResourcePitch(ResourceInfo, PitchInBytes); VerifyResourceSize(ResourceInfo, AlignedSize); VerifyResourceQPitch(ResourceInfo, 0); // Not valid for 1D pGmmULTClientContext->DestroyResInfoObject(ResourceInfo); } // Allocate more than 1 page for(uint32_t i = 0; i < TEST_BPP_MAX; i++) { TEST_BPP bpp = static_cast(i); gmmParams.Format = SetResourceFormat(bpp); gmmParams.BaseWidth64 = 0x1001; gmmParams.BaseHeight = 1; GMM_RESOURCE_INFO *ResourceInfo; ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); uint32_t AlignedWidth = GMM_ULT_ALIGN(gmmParams.BaseWidth64, HAlign); uint32_t AlignedHeight = GMM_ULT_ALIGN(gmmParams.BaseHeight, VAlign); uint32_t PitchInBytes = AlignedWidth * GetBppValue(bpp); PitchInBytes = GFX_MAX(PitchInBytes, MinPitch); PitchInBytes = GMM_ULT_ALIGN(PitchInBytes, PitchAlignment); uint32_t AlignedSize = GMM_ULT_ALIGN(PitchInBytes * AlignedHeight, PAGE_SIZE); VerifyResourceHAlign(ResourceInfo, HAlign); VerifyResourceVAlign(ResourceInfo, VAlign); VerifyResourcePitch(ResourceInfo, PitchInBytes); VerifyResourceSize(ResourceInfo, AlignedSize); VerifyResourceQPitch(ResourceInfo, 0); pGmmULTClientContext->DestroyResInfoObject(ResourceInfo); } } /// @brief ULT for 1D Linear Resource Arrays TEST_F(CTestResource, Test1DLinearResourceArrays) { // Horizontal/Vertical pixel alignment const uint32_t HAlign = 16; const uint32_t VAlign = 4; const uint32_t MinPitch = 32; const uint32_t PitchAlignment = 64; GMM_RESCREATE_PARAMS gmmParams = {}; gmmParams.Type = RESOURCE_1D; gmmParams.NoGfxMemory = 1; gmmParams.Flags.Info.Linear = 1; gmmParams.Flags.Gpu.Texture = 1; gmmParams.ArraySize = 4; // Allocate 1x1x1 surface for(uint32_t i = 0; i < TEST_BPP_MAX; i++) { TEST_BPP bpp = static_cast(i); gmmParams.Format = SetResourceFormat(bpp); gmmParams.BaseWidth64 = 0x100; gmmParams.BaseHeight = 0x1; GMM_RESOURCE_INFO *ResourceInfo; ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); uint32_t AlignedWidth = GMM_ULT_ALIGN(gmmParams.BaseWidth64, HAlign); uint32_t AlignedHeight = GMM_ULT_ALIGN(gmmParams.BaseHeight, VAlign); uint32_t PitchInBytes = AlignedWidth * GetBppValue(bpp); PitchInBytes = GFX_MAX(PitchInBytes, MinPitch); PitchInBytes = GMM_ULT_ALIGN(PitchInBytes, PitchAlignment); uint32_t AlignedSize = GMM_ULT_ALIGN(PitchInBytes * AlignedHeight * gmmParams.ArraySize, PAGE_SIZE); VerifyResourceHAlign(ResourceInfo, HAlign); VerifyResourceVAlign(ResourceInfo, VAlign); VerifyResourcePitch(ResourceInfo, PitchInBytes); VerifyResourceSize(ResourceInfo, AlignedSize); VerifyResourceQPitch(ResourceInfo, AlignedHeight); pGmmULTClientContext->DestroyResInfoObject(ResourceInfo); } } /// @brief ULT for 1D Mipped Linear Resource TEST_F(CTestResource, Test1DLinearResourceMips) { // Horizontal/Vertical pixel alignment const uint32_t HAlign = 16; const uint32_t VAlign = 4; const uint32_t MinPitch = 32; const uint32_t PitchAlignment = 64; GMM_RESCREATE_PARAMS gmmParams = {}; gmmParams.Type = RESOURCE_1D; gmmParams.NoGfxMemory = 1; gmmParams.Flags.Info.Linear = 1; gmmParams.Flags.Gpu.Texture = 1; gmmParams.MaxLod = 5; // Allocate 256x1 surface for(uint32_t i = 0; i < TEST_BPP_MAX; i++) { TEST_BPP bpp = static_cast(i); gmmParams.Format = SetResourceFormat(bpp); gmmParams.BaseWidth64 = 0x100; gmmParams.BaseHeight = 0x1; GMM_RESOURCE_INFO *ResourceInfo; ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); uint32_t AlignedWidth = GMM_ULT_ALIGN(gmmParams.BaseWidth64, HAlign); uint32_t AlignedHeight = GMM_ULT_ALIGN(gmmParams.BaseHeight, VAlign); // Height of 1D surface will just be VAlign. So height of the whole block will be // Height of Mip0 + Mip2 + Mip3 + Mip4 + Mip5... AlignedHeight = gmmParams.MaxLod * AlignedHeight; uint32_t PitchInBytes = AlignedWidth * GetBppValue(bpp); PitchInBytes = GFX_MAX(PitchInBytes, MinPitch); PitchInBytes = GMM_ULT_ALIGN(PitchInBytes, PitchAlignment); uint32_t AlignedSize = GMM_ULT_ALIGN(PitchInBytes * AlignedHeight, PAGE_SIZE); VerifyResourceHAlign(ResourceInfo, HAlign); VerifyResourceVAlign(ResourceInfo, VAlign); VerifyResourcePitch(ResourceInfo, PitchInBytes); VerifyResourceSize(ResourceInfo, AlignedSize); VerifyResourceQPitch(ResourceInfo, 0); // N/A for non-arrayed surface // Mip0 should be at offset 0. X/Y/Z Offset should be 0 for linear. GMM_REQ_OFFSET_INFO OffsetInfo = {}; OffsetInfo.ReqRender = 1; OffsetInfo.MipLevel = 0; //Mip 0 ResourceInfo->GetOffset(OffsetInfo); EXPECT_EQ(0, OffsetInfo.Render.Offset64); EXPECT_EQ(0, OffsetInfo.Render.XOffset); EXPECT_EQ(0, OffsetInfo.Render.YOffset); EXPECT_EQ(0, OffsetInfo.Render.ZOffset); // Mip1 should be after Mip0. X/Y/Z Offset should be 0 for linear. OffsetInfo = {}; OffsetInfo.ReqRender = 1; OffsetInfo.MipLevel = 1; //Mip 1 ResourceInfo->GetOffset(OffsetInfo); uint32_t SizeOfMip0 = PitchInBytes * GMM_ULT_ALIGN(gmmParams.BaseHeight, VAlign); EXPECT_EQ(SizeOfMip0, OffsetInfo.Render.Offset64); EXPECT_EQ(0, OffsetInfo.Render.XOffset); EXPECT_EQ(0, OffsetInfo.Render.YOffset); EXPECT_EQ(0, OffsetInfo.Render.ZOffset); // Mip2 should to the right of Mip1. X/Y/Z Offset should be 0 for linear. OffsetInfo = {}; OffsetInfo.ReqRender = 1; OffsetInfo.MipLevel = 2; //Mip 2 ResourceInfo->GetOffset(OffsetInfo); uint32_t StartOfMip = SizeOfMip0 + (GMM_ULT_ALIGN(gmmParams.BaseWidth64 >> 1, HAlign) * GetBppValue(bpp)); EXPECT_EQ(StartOfMip, OffsetInfo.Render.Offset64); EXPECT_EQ(0, OffsetInfo.Render.XOffset); EXPECT_EQ(0, OffsetInfo.Render.YOffset); EXPECT_EQ(0, OffsetInfo.Render.ZOffset); // Rest of the mips should be below mip2, each with height of HAlign. X/Y/Z Offset should be 0 for linear. for(int mip = 3; mip <= gmmParams.MaxLod; mip++) { OffsetInfo = {}; OffsetInfo.ReqRender = 1; OffsetInfo.MipLevel = mip; ResourceInfo->GetOffset(OffsetInfo); StartOfMip += PitchInBytes * VAlign; EXPECT_EQ(StartOfMip, OffsetInfo.Render.Offset64); EXPECT_EQ(0, OffsetInfo.Render.XOffset); EXPECT_EQ(0, OffsetInfo.Render.YOffset); EXPECT_EQ(0, OffsetInfo.Render.ZOffset); } pGmmULTClientContext->DestroyResInfoObject(ResourceInfo); } } // ********************************************************************************// /// @brief ULT for 2D Linear Resource Arrays TEST_F(CTestResource, Test2DLinearResourceArrays) { // Horizontal/Vertical pixel alignment const uint32_t HAlign = 16; const uint32_t VAlign = 4; const uint32_t MinPitch = 32; const uint32_t PitchAlignment = 64; GMM_RESCREATE_PARAMS gmmParams = {}; gmmParams.Type = RESOURCE_2D; gmmParams.NoGfxMemory = 1; gmmParams.Flags.Info.Linear = 1; gmmParams.Flags.Gpu.Texture = 1; gmmParams.ArraySize = 4; // Allocate 256x256 surface for(uint32_t i = 0; i < TEST_BPP_MAX; i++) { TEST_BPP bpp = static_cast(i); gmmParams.Format = SetResourceFormat(bpp); gmmParams.BaseWidth64 = 0x100; gmmParams.BaseHeight = 0x100; GMM_RESOURCE_INFO *ResourceInfo; ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); uint32_t AlignedWidth = GMM_ULT_ALIGN(gmmParams.BaseWidth64, HAlign); uint32_t AlignedHeight = GMM_ULT_ALIGN(gmmParams.BaseHeight, VAlign); uint32_t PitchInBytes = AlignedWidth * GetBppValue(bpp); PitchInBytes = GFX_MAX(PitchInBytes, MinPitch); PitchInBytes = GMM_ULT_ALIGN(PitchInBytes, PitchAlignment); uint32_t AlignedSize = GMM_ULT_ALIGN(PitchInBytes * AlignedHeight * gmmParams.ArraySize, PAGE_SIZE); VerifyResourceHAlign(ResourceInfo, HAlign); VerifyResourceVAlign(ResourceInfo, VAlign); VerifyResourcePitch(ResourceInfo, PitchInBytes); VerifyResourceSize(ResourceInfo, AlignedSize); VerifyResourceQPitch(ResourceInfo, AlignedHeight); pGmmULTClientContext->DestroyResInfoObject(ResourceInfo); } } /// @brief ULT for 2D Mipped Linear Resource TEST_F(CTestResource, Test2DLinearResourceMips) { // Horizontal/Vertical pixel alignment const uint32_t HAlign = 16; const uint32_t VAlign = 4; const uint32_t MinPitch = 32; const uint32_t PitchAlignment = 64; GMM_RESCREATE_PARAMS gmmParams = {}; gmmParams.Type = RESOURCE_2D; gmmParams.NoGfxMemory = 1; gmmParams.Flags.Info.Linear = 1; gmmParams.Flags.Gpu.Texture = 1; gmmParams.MaxLod = 8; // Allocate 256x256 surface for(uint32_t i = 0; i < TEST_BPP_MAX; i++) { TEST_BPP bpp = static_cast(i); gmmParams.Format = SetResourceFormat(bpp); gmmParams.BaseWidth64 = 0x100; gmmParams.BaseHeight = 0x100; GMM_RESOURCE_INFO *ResourceInfo; ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); uint32_t AlignedWidth = GMM_ULT_ALIGN(gmmParams.BaseWidth64, HAlign); uint32_t AlignedHeight; uint32_t PitchInBytes = AlignedWidth * GetBppValue(bpp); PitchInBytes = GFX_MAX(PitchInBytes, MinPitch); PitchInBytes = GMM_ULT_ALIGN(PitchInBytes, PitchAlignment); uint32_t HeightOfPrevMip = AlignedHeight = gmmParams.BaseHeight; // Mip0 should be at offset 0. X/Y/Z Offset should be 0 for linear. GMM_REQ_OFFSET_INFO OffsetInfo = {}; OffsetInfo.ReqRender = 1; OffsetInfo.MipLevel = 0; //Mip 0 ResourceInfo->GetOffset(OffsetInfo); EXPECT_EQ(0, OffsetInfo.Render.Offset64); EXPECT_EQ(0, OffsetInfo.Render.XOffset); EXPECT_EQ(0, OffsetInfo.Render.YOffset); EXPECT_EQ(0, OffsetInfo.Render.ZOffset); // Mip1 should be after Mip0. X/Y/Z Offset should be 0 for linear. OffsetInfo = {}; OffsetInfo.ReqRender = 1; OffsetInfo.MipLevel = 1; //Mip 1 ResourceInfo->GetOffset(OffsetInfo); uint32_t SizeOfMip0 = PitchInBytes * GMM_ULT_ALIGN(gmmParams.BaseHeight, VAlign); EXPECT_EQ(SizeOfMip0, OffsetInfo.Render.Offset64); EXPECT_EQ(0, OffsetInfo.Render.XOffset); EXPECT_EQ(0, OffsetInfo.Render.YOffset); EXPECT_EQ(0, OffsetInfo.Render.ZOffset); // Mip2 should to the right of Mip1. X/Y/Z Offset should be 0 for linear. OffsetInfo = {}; OffsetInfo.ReqRender = 1; OffsetInfo.MipLevel = 2; //Mip 2 ResourceInfo->GetOffset(OffsetInfo); uint32_t StartOfMip = SizeOfMip0 + (GMM_ULT_ALIGN(gmmParams.BaseWidth64 >> 1, HAlign) * GetBppValue(bpp)); EXPECT_EQ(StartOfMip, OffsetInfo.Render.Offset64); EXPECT_EQ(0, OffsetInfo.Render.XOffset); EXPECT_EQ(0, OffsetInfo.Render.YOffset); EXPECT_EQ(0, OffsetInfo.Render.ZOffset); // Rest of the mips should be below mip2, each with height of HAlign. X/Y/Z Offset should be 0 for linear. for(int mip = 3; mip <= 8; mip++) { OffsetInfo = {}; OffsetInfo.ReqRender = 1; OffsetInfo.MipLevel = mip; ResourceInfo->GetOffset(OffsetInfo); HeightOfPrevMip = GMM_ULT_ALIGN((gmmParams.BaseHeight >> (mip - 1)), VAlign); AlignedHeight += HeightOfPrevMip; StartOfMip += PitchInBytes * HeightOfPrevMip; EXPECT_EQ(StartOfMip, OffsetInfo.Render.Offset64); EXPECT_EQ(0, OffsetInfo.Render.XOffset); EXPECT_EQ(0, OffsetInfo.Render.YOffset); EXPECT_EQ(0, OffsetInfo.Render.ZOffset); } //Mip8 will go till Mip0Height + Mip1Height + VALIGN AlignedHeight += VAlign; uint32_t AlignedSize = GMM_ULT_ALIGN(PitchInBytes * AlignedHeight, PAGE_SIZE); VerifyResourceHAlign(ResourceInfo, HAlign); VerifyResourceVAlign(ResourceInfo, VAlign); VerifyResourcePitch(ResourceInfo, PitchInBytes); VerifyResourceSize(ResourceInfo, AlignedSize); VerifyResourceQPitch(ResourceInfo, 0); // N/A for non-arrayed surface pGmmULTClientContext->DestroyResInfoObject(ResourceInfo); } } /// @brief ULT for Arrayed 2D TileX Resource TEST_F(CTestResource, Test2DTileXResourceArrays) { // Horizontal/Vertical pixel alignment const uint32_t HAlign = 16; const uint32_t VAlign = 4; const uint32_t TileWidth = 512; const uint32_t TileHeight = 8; GMM_RESCREATE_PARAMS gmmParams = {}; gmmParams.Type = RESOURCE_2D; gmmParams.NoGfxMemory = 1; gmmParams.Flags.Info.TiledX = 1; gmmParams.Flags.Gpu.Texture = 1; gmmParams.ArraySize = 4; // Allocate 2 tiles in X/Y dimension for(uint32_t i = 0; i < TEST_BPP_MAX; i++) { TEST_BPP bpp = static_cast(i); gmmParams.Format = SetResourceFormat(bpp); gmmParams.BaseWidth64 = (TileWidth / GetBppValue(bpp)) + 1; // 1 pixel larger than 1 tile width gmmParams.BaseHeight = TileHeight + 1; // 1 row larger than 1 tile height const uint32_t AlignedWidth = GMM_ULT_ALIGN(gmmParams.BaseWidth64, HAlign); uint32_t PitchInBytes = AlignedWidth * GetBppValue(bpp); PitchInBytes = GMM_ULT_ALIGN(PitchInBytes, TileWidth); uint32_t AlignedHeight, BlockHeight; BlockHeight = GMM_ULT_ALIGN(gmmParams.BaseHeight, VAlign); AlignedHeight = GMM_ULT_ALIGN_NP2(BlockHeight * gmmParams.ArraySize, TileHeight); GMM_RESOURCE_INFO *ResourceInfo; ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); VerifyResourceHAlign(ResourceInfo, HAlign); VerifyResourceVAlign(ResourceInfo, VAlign); VerifyResourcePitch(ResourceInfo, PitchInBytes); // As wide as 2 tile VerifyResourcePitchInTiles(ResourceInfo, PitchInBytes / TileWidth); // 2 tile wide VerifyResourceSize(ResourceInfo, PitchInBytes * AlignedHeight); // 4 tile big x 4 array size VerifyResourceQPitch(ResourceInfo, BlockHeight); pGmmULTClientContext->DestroyResInfoObject(ResourceInfo); } } /// @brief ULT for Mipped 2D TileX Resource TEST_F(CTestResource, Test2DTileXResourceMips) { const uint32_t TileSize[2] = {512, 8}; enum Coords { X = 0, Y = 1 }; // Test normal mip case for(uint32_t i = 0; i < TEST_BPP_MAX; i++) { const uint32_t ResourceWidth = 0x400; const uint32_t ResourceHeight = 0x400; const uint32_t MaxLod = 10; TEST_BPP bpp = static_cast(i); GMM_RESCREATE_PARAMS gmmParams = {}; gmmParams.Type = RESOURCE_2D; gmmParams.Flags.Info.TiledX = 1; gmmParams.NoGfxMemory = 1; gmmParams.Flags.Gpu.Texture = 1; gmmParams.BaseWidth64 = ResourceWidth; gmmParams.BaseHeight = ResourceHeight; gmmParams.MaxLod = MaxLod; gmmParams.Format = SetResourceFormat(bpp); // Create resource GMM_RESOURCE_INFO *ResourceInfo; ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); // Mip0 is the widest mip. So it will dictate the pitch of the whole surface const uint32_t Pitch = ResourceWidth * GetBppValue(bpp); uint32_t AllocationHeight = 0; // Mip0 should be at offset 0 and tile aligned GMM_REQ_OFFSET_INFO OffsetInfo = {}; OffsetInfo.ReqRender = 1; OffsetInfo.MipLevel = 0; //Mip 0 ResourceInfo->GetOffset(OffsetInfo); EXPECT_EQ(0, OffsetInfo.Render.Offset64); EXPECT_EQ(0, OffsetInfo.Render.XOffset); EXPECT_EQ(0, OffsetInfo.Render.YOffset); EXPECT_EQ(0, OffsetInfo.Render.ZOffset); // Mip1 should be after whole Mip0. Should still be tile aligned. OffsetInfo = {}; OffsetInfo.ReqRender = 1; OffsetInfo.MipLevel = 1; // Mip 1 ResourceInfo->GetOffset(OffsetInfo); uint32_t SizeOfMip0 = Pitch * ResourceHeight; uint32_t HeightOfPrevMip = AllocationHeight = ResourceHeight; EXPECT_EQ(SizeOfMip0, OffsetInfo.Render.Offset64); EXPECT_EQ(0, OffsetInfo.Render.XOffset); EXPECT_EQ(0, OffsetInfo.Render.YOffset); EXPECT_EQ(0, OffsetInfo.Render.ZOffset); // Mip2 should be on the right of Mip1. Should still be tile aligned. OffsetInfo = {}; OffsetInfo.ReqRender = 1; OffsetInfo.MipLevel = 2; // Mip 2 ResourceInfo->GetOffset(OffsetInfo); // MipOffset = Mip1Offset + Mip1Width in tiles uint32_t MipOffset = SizeOfMip0 + ((Pitch >> 1) / TileSize[X]) * PAGE_SIZE; EXPECT_EQ(MipOffset, OffsetInfo.Render.Offset64); EXPECT_EQ(0, OffsetInfo.Render.XOffset); EXPECT_EQ(0, OffsetInfo.Render.YOffset); EXPECT_EQ(0, OffsetInfo.Render.ZOffset); // Mips 3-8 should be on tile boundary for(int i = 3; i < 9; i++) { OffsetInfo = {}; OffsetInfo.ReqRender = 1; OffsetInfo.MipLevel = i; ResourceInfo->GetOffset(OffsetInfo); HeightOfPrevMip = (ResourceHeight >> (i - 1)); AllocationHeight += HeightOfPrevMip; MipOffset += Pitch * HeightOfPrevMip; EXPECT_EQ(MipOffset, OffsetInfo.Render.Offset64); // No X/Y/Z offset since mip is at tile boundary EXPECT_EQ(0, OffsetInfo.Render.XOffset); EXPECT_EQ(0, OffsetInfo.Render.YOffset); EXPECT_EQ(0, OffsetInfo.Render.ZOffset); } // Mips 9 will share 1 tile with Mip 8 AllocationHeight += TileSize[Y]; uint32_t HeightOfPrevMipsInTile = 0; { OffsetInfo = {}; OffsetInfo.ReqRender = 1; OffsetInfo.MipLevel = 9; ResourceInfo->GetOffset(OffsetInfo); EXPECT_EQ(MipOffset, OffsetInfo.Render.Offset64); // Same as previous tile aligned mip offset // X is 0, but Y offset will change EXPECT_EQ(0, OffsetInfo.Render.XOffset); HeightOfPrevMipsInTile += (ResourceHeight >> (9 - 1)); EXPECT_EQ(HeightOfPrevMipsInTile, OffsetInfo.Render.YOffset); EXPECT_EQ(0, OffsetInfo.Render.ZOffset); } // Mip 10 is back on tile boundary OffsetInfo = {}; OffsetInfo.ReqRender = 1; OffsetInfo.MipLevel = 10; // Mip 10 ResourceInfo->GetOffset(OffsetInfo); MipOffset += Pitch * TileSize[Y]; AllocationHeight += TileSize[Y]; EXPECT_EQ(MipOffset, OffsetInfo.Render.Offset64); EXPECT_EQ(0, OffsetInfo.Render.XOffset); EXPECT_EQ(0, OffsetInfo.Render.YOffset); EXPECT_EQ(0, OffsetInfo.Render.ZOffset); // Verify ResourceSize and Pitch VerifyResourceSize(ResourceInfo, AllocationHeight * Pitch); VerifyResourcePitch(ResourceInfo, Pitch); VerifyResourcePitchInTiles(ResourceInfo, Pitch / TileSize[X]); // These are verified elsewhere VerifyResourceHAlign(ResourceInfo, 0); VerifyResourceVAlign(ResourceInfo, 0); VerifyResourceQPitch(ResourceInfo, 0); pGmmULTClientContext->DestroyResInfoObject(ResourceInfo); } // Test where Mip1 + Mip2 width > Mip0 width, and where everything fits in 1 tile for(uint32_t i = 0; i < TEST_BPP_64; i++) { const uint32_t ResourceWidth = 0x4; const uint32_t ResourceHeight = 0x2; const uint32_t MaxLod = 0x2; TEST_BPP bpp = static_cast(i); GMM_RESCREATE_PARAMS gmmParams = {}; gmmParams.Type = RESOURCE_2D; gmmParams.Flags.Info.TiledX = 1; gmmParams.NoGfxMemory = 1; gmmParams.Flags.Gpu.Texture = 1; gmmParams.BaseWidth64 = ResourceWidth; gmmParams.BaseHeight = ResourceHeight; gmmParams.MaxLod = MaxLod; gmmParams.Format = SetResourceFormat(bpp); // Create resource GMM_RESOURCE_INFO *ResourceInfo; ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); // Get Alignment that GmmLib is using const uint32_t HAlign = ResourceInfo->GetHAlign(); const uint32_t VAlign = ResourceInfo->GetVAlign(); // Mip1 + Mip2 is the widest width. So it will dictate the pitch of the whole surface uint32_t Pitch = GetBppValue(bpp) * (GMM_ULT_ALIGN(ResourceWidth >> 1, HAlign) + GMM_ULT_ALIGN(ResourceWidth >> 2, HAlign)); Pitch = GMM_ULT_ALIGN(Pitch, TileSize[X]); // Mip0 should be at offset 0 and tile aligned GMM_REQ_OFFSET_INFO OffsetInfo = {}; OffsetInfo.ReqRender = 1; OffsetInfo.MipLevel = 0; //Mip 0 ResourceInfo->GetOffset(OffsetInfo); EXPECT_EQ(0, OffsetInfo.Render.Offset64); EXPECT_EQ(0, OffsetInfo.Render.XOffset); EXPECT_EQ(0, OffsetInfo.Render.YOffset); EXPECT_EQ(0, OffsetInfo.Render.ZOffset); // Mip1 should be after whole Mip0. Not tile aligned OffsetInfo = {}; OffsetInfo.ReqRender = 1; OffsetInfo.MipLevel = 1; // Mip 1 ResourceInfo->GetOffset(OffsetInfo); EXPECT_EQ(0, OffsetInfo.Render.Offset64); // Same tile as Mip0 EXPECT_EQ(0, OffsetInfo.Render.XOffset); EXPECT_EQ(GMM_ULT_ALIGN(ResourceHeight, VAlign), OffsetInfo.Render.YOffset); // After Mip0 EXPECT_EQ(0, OffsetInfo.Render.ZOffset); // Mip2 should be on the right of Mip1. Not tile aligned OffsetInfo = {}; OffsetInfo.ReqRender = 1; OffsetInfo.MipLevel = 2; // Mip 2 ResourceInfo->GetOffset(OffsetInfo); EXPECT_EQ(0, OffsetInfo.Render.Offset64); // Same Tile as Mip0 uint32_t Mip1Width = GMM_ULT_ALIGN(ResourceWidth >> 1, HAlign) * GetBppValue(bpp); EXPECT_EQ(Mip1Width, OffsetInfo.Render.XOffset); // On right of Mip1 EXPECT_EQ(GMM_ULT_ALIGN(ResourceHeight, VAlign), OffsetInfo.Render.YOffset); // After Mip0 EXPECT_EQ(0, OffsetInfo.Render.ZOffset); // Verify ResourceSize and Pitch VerifyResourceSize(ResourceInfo, PAGE_SIZE); // everything should fit in 1 tile VerifyResourcePitch(ResourceInfo, Pitch); VerifyResourcePitchInTiles(ResourceInfo, Pitch / TileSize[X]); // These are verified elsewhere VerifyResourceHAlign(ResourceInfo, 0); VerifyResourceVAlign(ResourceInfo, 0); VerifyResourceQPitch(ResourceInfo, 0); pGmmULTClientContext->DestroyResInfoObject(ResourceInfo); } } /// @brief ULT for 2D Linear Resource TEST_F(CTestResource, Test2DLinearResource) { const uint32_t HAlign = 16; const uint32_t VAlign = 4; GMM_RESCREATE_PARAMS gmmParams = {}; gmmParams.Type = RESOURCE_2D; gmmParams.NoGfxMemory = 1; gmmParams.Flags.Info.Linear = 1; gmmParams.Flags.Gpu.Texture = 1; //Allocate 1x1 surface for(uint32_t i = 0; i < TEST_BPP_MAX; i++) { TEST_BPP bpp = static_cast(i); gmmParams.Format = SetResourceFormat(bpp); gmmParams.BaseWidth64 = 0x1; gmmParams.BaseHeight = 0x1; const uint32_t MinPitch = 32; const uint32_t PitchAlignment = 64; GMM_RESOURCE_INFO *ResourceInfo; ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); const uint32_t AlignedWidth = GMM_ULT_ALIGN(gmmParams.BaseWidth64, HAlign); const uint32_t AlignedHeight = GMM_ULT_ALIGN(gmmParams.BaseHeight, VAlign); uint32_t PitchInBytes = AlignedWidth * GetBppValue(bpp); PitchInBytes = GMM_ULT_MAX(PitchInBytes, MinPitch); PitchInBytes = GMM_ULT_ALIGN(PitchInBytes, PitchAlignment); const uint32_t AlignedSize = GMM_ULT_ALIGN(PitchInBytes * AlignedHeight, PAGE_SIZE); VerifyResourceHAlign(ResourceInfo, HAlign); VerifyResourceVAlign(ResourceInfo, VAlign); VerifyResourcePitch(ResourceInfo, PitchInBytes); VerifyResourceSize(ResourceInfo, AlignedSize); pGmmULTClientContext->DestroyResInfoObject(ResourceInfo); } // Allocate 256 x 256 for(uint32_t i = 0; i < TEST_BPP_MAX; i++) { TEST_BPP bpp = static_cast(i); gmmParams.Format = SetResourceFormat(bpp); gmmParams.BaseWidth64 = 256; gmmParams.BaseHeight = 256; const uint32_t MinPitch = 32; const uint32_t PitchAlignment = 64; GMM_RESOURCE_INFO *ResourceInfo; ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); const uint32_t AlignedWidth = GMM_ULT_ALIGN(gmmParams.BaseWidth64, HAlign); const uint32_t AlignedHeight = GMM_ULT_ALIGN(gmmParams.BaseHeight, VAlign); uint32_t PitchInBytes = AlignedWidth * GetBppValue(bpp); PitchInBytes = GMM_ULT_MAX(PitchInBytes, MinPitch); PitchInBytes = GMM_ULT_ALIGN(PitchInBytes, PitchAlignment); const uint32_t AlignedSize = GMM_ULT_ALIGN(PitchInBytes * AlignedHeight, PAGE_SIZE); VerifyResourceHAlign(ResourceInfo, HAlign); VerifyResourceVAlign(ResourceInfo, VAlign); VerifyResourcePitch(ResourceInfo, PitchInBytes); VerifyResourceSize(ResourceInfo, AlignedSize); pGmmULTClientContext->DestroyResInfoObject(ResourceInfo); } } /// @brief ULT for 2D TileX Resource TEST_F(CTestResource, Test2DTileXResource) { const uint32_t HAlign = 16; const uint32_t VAlign = 4; const uint32_t TileWidth = 512; const uint32_t TileHeight = 8; GMM_RESCREATE_PARAMS gmmParams = {}; gmmParams.Type = RESOURCE_2D; gmmParams.NoGfxMemory = 1; gmmParams.Flags.Info.TiledX = 1; gmmParams.Flags.Gpu.Texture = 1; //Allocate 1x1 surface for(uint32_t i = 0; i < TEST_BPP_MAX; i++) { TEST_BPP bpp = static_cast(i); gmmParams.Format = SetResourceFormat(bpp); gmmParams.BaseWidth64 = 0x1; gmmParams.BaseHeight = 0x1; GMM_RESOURCE_INFO *ResourceInfo; ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); VerifyResourceHAlign(ResourceInfo, HAlign); VerifyResourceVAlign(ResourceInfo, VAlign); VerifyResourcePitch(ResourceInfo, TileWidth); // As wide as 1 Tile VerifyResourcePitchInTiles(ResourceInfo, 1); // 1 Tile wide VerifyResourceSize(ResourceInfo, GMM_KBYTE(4)); // 1 Tile Big VerifyResourceQPitch(ResourceInfo, 0); // Not Tested pGmmULTClientContext->DestroyResInfoObject(ResourceInfo); } // Allocate surface that requires multi tiles in two dimension // Allocate 2 tiles in X dimension for(uint32_t i = 0; i < TEST_BPP_MAX; i++) { TEST_BPP bpp = static_cast(i); gmmParams.Format = SetResourceFormat(bpp); gmmParams.BaseWidth64 = (TileWidth / GetBppValue(bpp)) + 1; // 1 pixel larger than 1 tile width gmmParams.BaseHeight = 0x1; GMM_RESOURCE_INFO *ResourceInfo; ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); VerifyResourceHAlign(ResourceInfo, HAlign); VerifyResourceVAlign(ResourceInfo, VAlign); VerifyResourcePitch(ResourceInfo, TileWidth * 2); // As wide as 2 tile VerifyResourcePitchInTiles(ResourceInfo, 2); // 2 tile wide VerifyResourceSize(ResourceInfo, GMM_KBYTE(4) * 2); // 2 tile big VerifyResourceQPitch(ResourceInfo, 0); // Not tested pGmmULTClientContext->DestroyResInfoObject(ResourceInfo); } // Allocate 2 tiles in X/Y dimension for(uint32_t i = 0; i < TEST_BPP_MAX; i++) { TEST_BPP bpp = static_cast(i); gmmParams.Format = SetResourceFormat(bpp); gmmParams.BaseWidth64 = (TileWidth / GetBppValue(bpp)) + 1; // 1 pixel larger than 1 tile width gmmParams.BaseHeight = TileHeight + 1; // 1 row larger than 1 tile height GMM_RESOURCE_INFO *ResourceInfo; ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); VerifyResourceHAlign(ResourceInfo, HAlign); VerifyResourceVAlign(ResourceInfo, VAlign); VerifyResourcePitch(ResourceInfo, TileWidth * 2); // As wide as 2 tile VerifyResourcePitchInTiles(ResourceInfo, 2); // 2 tile wide VerifyResourceSize(ResourceInfo, GMM_KBYTE(4) * 4); // 4 tile big VerifyResourceQPitch(ResourceInfo, 0); // Not tested pGmmULTClientContext->DestroyResInfoObject(ResourceInfo); } } /// @brief ULT for 2D TileY Resource TEST_F(CTestResource, Test2DTileYResource) { const uint32_t HAlign = 16; const uint32_t VAlign = 4; const uint32_t TileWidth = 128; const uint32_t TileHeight = 32; GMM_RESCREATE_PARAMS gmmParams = {}; gmmParams.Type = RESOURCE_2D; gmmParams.NoGfxMemory = 1; gmmParams.Flags.Info.TiledY = 1; gmmParams.Flags.Gpu.Texture = 1; //Allocate 1x1 surface for(uint32_t i = 0; i < TEST_BPP_MAX; i++) { TEST_BPP bpp = static_cast(i); gmmParams.Format = SetResourceFormat(bpp); gmmParams.BaseWidth64 = 0x1; gmmParams.BaseHeight = 0x1; const uint32_t MinPitch = 32; const uint32_t PitchAlignment = 32; GMM_RESOURCE_INFO *ResourceInfo; ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); const uint32_t AlignedWidth = GMM_ULT_ALIGN(gmmParams.BaseWidth64, HAlign); uint32_t PitchInBytes = AlignedWidth * GetBppValue(bpp); PitchInBytes = GMM_ULT_MAX(PitchInBytes, MinPitch); PitchInBytes = GMM_ULT_ALIGN(PitchInBytes, PitchAlignment); PitchInBytes = GMM_ULT_ALIGN(PitchInBytes, TileWidth); VerifyResourceHAlign(ResourceInfo, HAlign); VerifyResourceVAlign(ResourceInfo, VAlign); VerifyResourcePitch(ResourceInfo, PitchInBytes); VerifyResourcePitchInTiles(ResourceInfo, PitchInBytes / TileWidth); VerifyResourceSize(ResourceInfo, PitchInBytes / TileWidth * GMM_KBYTE(4)); VerifyResourceQPitch(ResourceInfo, 0); // Not Tested pGmmULTClientContext->DestroyResInfoObject(ResourceInfo); } // Allocate surface that requires multi tiles in two dimension // Allocate 2 tiles in X dimension for(uint32_t i = 0; i < TEST_BPP_MAX; i++) { TEST_BPP bpp = static_cast(i); gmmParams.Format = SetResourceFormat(bpp); gmmParams.BaseWidth64 = (TileWidth / GetBppValue(bpp)) + 1; // 1 pixel larger than 1 tile width gmmParams.BaseHeight = 0x1; const uint32_t MinPitch = 32; const uint32_t PitchAlignment = 32; GMM_RESOURCE_INFO *ResourceInfo; ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); const uint32_t AlignedWidth = GMM_ULT_ALIGN(gmmParams.BaseWidth64, HAlign); uint32_t PitchInBytes = AlignedWidth * GetBppValue(bpp); PitchInBytes = GMM_ULT_MAX(PitchInBytes, MinPitch); PitchInBytes = GMM_ULT_ALIGN(PitchInBytes, PitchAlignment); PitchInBytes = GMM_ULT_ALIGN(PitchInBytes, TileWidth); VerifyResourceHAlign(ResourceInfo, HAlign); VerifyResourceVAlign(ResourceInfo, VAlign); VerifyResourcePitch(ResourceInfo, PitchInBytes); VerifyResourcePitchInTiles(ResourceInfo, PitchInBytes / TileWidth); VerifyResourceSize(ResourceInfo, PitchInBytes / TileWidth * GMM_KBYTE(4)); VerifyResourceQPitch(ResourceInfo, 0); // Not tested pGmmULTClientContext->DestroyResInfoObject(ResourceInfo); } // Allocate 2 tiles in X/Y dimension for(uint32_t i = 0; i < TEST_BPP_MAX; i++) { TEST_BPP bpp = static_cast(i); gmmParams.Format = SetResourceFormat(bpp); gmmParams.BaseWidth64 = (TileWidth / GetBppValue(bpp)) + 1; // 1 pixel larger than 1 tile width gmmParams.BaseHeight = TileHeight + 1; // 1 row larger than 1 tile height const uint32_t MinPitch = 32; const uint32_t PitchAlignment = 32; GMM_RESOURCE_INFO *ResourceInfo; ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); const uint32_t AlignedWidth = GMM_ULT_ALIGN(gmmParams.BaseWidth64, HAlign); uint32_t PitchInBytes = AlignedWidth * GetBppValue(bpp); PitchInBytes = GMM_ULT_MAX(PitchInBytes, MinPitch); PitchInBytes = GMM_ULT_ALIGN(PitchInBytes, PitchAlignment); PitchInBytes = GMM_ULT_ALIGN(PitchInBytes, TileWidth); VerifyResourceHAlign(ResourceInfo, HAlign); VerifyResourceVAlign(ResourceInfo, VAlign); VerifyResourcePitch(ResourceInfo, PitchInBytes); VerifyResourcePitchInTiles(ResourceInfo, PitchInBytes / TileWidth); VerifyResourceSize(ResourceInfo, PitchInBytes / TileWidth * 2 * GMM_KBYTE(4)); VerifyResourceQPitch(ResourceInfo, 0); // Not tested pGmmULTClientContext->DestroyResInfoObject(ResourceInfo); } } /// @brief ULT for Arrayed 2D TileY Resource TEST_F(CTestResource, Test2DTileYResourceArrays) { // Horizontal/Vertical pixel alignment const uint32_t HAlign = 16; const uint32_t VAlign = 4; const uint32_t TileWidth = 128; const uint32_t TileHeight = 32; GMM_RESCREATE_PARAMS gmmParams = {}; gmmParams.Type = RESOURCE_2D; gmmParams.NoGfxMemory = 1; gmmParams.Flags.Info.TiledY = 1; gmmParams.Flags.Gpu.Texture = 1; gmmParams.ArraySize = 4; // Allocate 2 tiles in X/Y dimension for(uint32_t i = 0; i < TEST_BPP_MAX; i++) { TEST_BPP bpp = static_cast(i); gmmParams.Format = SetResourceFormat(bpp); gmmParams.BaseWidth64 = (TileWidth / GetBppValue(bpp)) + 1; // 1 pixel larger than 1 tile width gmmParams.BaseHeight = TileHeight + 1; // 1 row larger than 1 tile height uint32_t AlignedHeight, BlockHeight; BlockHeight = GMM_ULT_ALIGN(gmmParams.BaseHeight, VAlign); AlignedHeight = GMM_ULT_ALIGN_NP2(BlockHeight * gmmParams.ArraySize, TileHeight); GMM_RESOURCE_INFO *ResourceInfo; ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); const uint32_t AlignedWidth = GMM_ULT_ALIGN(gmmParams.BaseWidth64, HAlign); uint32_t PitchInBytes = AlignedWidth * GetBppValue(bpp); PitchInBytes = GMM_ULT_ALIGN(PitchInBytes, TileWidth); VerifyResourceHAlign(ResourceInfo, HAlign); VerifyResourceVAlign(ResourceInfo, VAlign); VerifyResourcePitch(ResourceInfo, PitchInBytes); VerifyResourcePitchInTiles(ResourceInfo, PitchInBytes / TileWidth); VerifyResourceSize(ResourceInfo, PitchInBytes * AlignedHeight); // 4 tile big x 4 array size VerifyResourceQPitch(ResourceInfo, BlockHeight); pGmmULTClientContext->DestroyResInfoObject(ResourceInfo); } } /// @brief ULT for Mipped 2D TileY Resource TEST_F(CTestResource, Test2DTileYResourceMips) { const uint32_t TileSize[2] = {128, 32}; enum Coords { X = 0, Y = 1 }; // Test normal mip case for(uint32_t i = 0; i < TEST_BPP_MAX; i++) { const uint32_t ResourceWidth = 0x200; const uint32_t ResourceHeight = 0x200; const uint32_t MaxLod = 0x9; TEST_BPP bpp = static_cast(i); GMM_RESCREATE_PARAMS gmmParams = {}; gmmParams.Type = RESOURCE_2D; gmmParams.Flags.Info.TiledY = 1; gmmParams.NoGfxMemory = 1; gmmParams.Flags.Gpu.Texture = 1; gmmParams.BaseWidth64 = ResourceWidth; gmmParams.BaseHeight = ResourceHeight; gmmParams.MaxLod = MaxLod; gmmParams.Format = SetResourceFormat(bpp); // Create resource GMM_RESOURCE_INFO *ResourceInfo; ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); // Mip0 is the widest mip. So it will dictate the pitch of the whole surface const uint32_t Pitch = ResourceWidth * GetBppValue(bpp); uint32_t AllocationHeight = 0; // Mip0 should be at offset 0 and tile aligned GMM_REQ_OFFSET_INFO OffsetInfo = {}; OffsetInfo.ReqRender = 1; OffsetInfo.MipLevel = 0; //Mip 0 ResourceInfo->GetOffset(OffsetInfo); EXPECT_EQ(0, OffsetInfo.Render.Offset64); EXPECT_EQ(0, OffsetInfo.Render.XOffset); EXPECT_EQ(0, OffsetInfo.Render.YOffset); EXPECT_EQ(0, OffsetInfo.Render.ZOffset); // Mip1 should be after whole Mip0. Should still be tile aligned. OffsetInfo = {}; OffsetInfo.ReqRender = 1; OffsetInfo.MipLevel = 1; // Mip 1 ResourceInfo->GetOffset(OffsetInfo); uint32_t SizeOfMip0 = Pitch * ResourceHeight; uint32_t HeightOfPrevMip = AllocationHeight = ResourceHeight; EXPECT_EQ(SizeOfMip0, OffsetInfo.Render.Offset64); EXPECT_EQ(0, OffsetInfo.Render.XOffset); EXPECT_EQ(0, OffsetInfo.Render.YOffset); EXPECT_EQ(0, OffsetInfo.Render.ZOffset); // Mip2 should be on the right of Mip1. Should still be tile aligned. OffsetInfo = {}; OffsetInfo.ReqRender = 1; OffsetInfo.MipLevel = 2; // Mip 2 ResourceInfo->GetOffset(OffsetInfo); // MipOffset = Mip1Offset + Mip1Width in tiles uint32_t MipOffset = SizeOfMip0 + ((Pitch >> 1) / TileSize[X]) * PAGE_SIZE; EXPECT_EQ(MipOffset, OffsetInfo.Render.Offset64); EXPECT_EQ(0, OffsetInfo.Render.XOffset); EXPECT_EQ(0, OffsetInfo.Render.YOffset); EXPECT_EQ(0, OffsetInfo.Render.ZOffset); // Mips 3-5 should be on tile boundary for(int i = 3; i < 6; i++) { OffsetInfo = {}; OffsetInfo.ReqRender = 1; OffsetInfo.MipLevel = i; ResourceInfo->GetOffset(OffsetInfo); HeightOfPrevMip = (ResourceHeight >> (i - 1)); AllocationHeight += HeightOfPrevMip; MipOffset += Pitch * HeightOfPrevMip; EXPECT_EQ(MipOffset, OffsetInfo.Render.Offset64); // No X/Y/Z offset since mip is at tile boundary EXPECT_EQ(0, OffsetInfo.Render.XOffset); EXPECT_EQ(0, OffsetInfo.Render.YOffset); EXPECT_EQ(0, OffsetInfo.Render.ZOffset); } // Mips 6-8 will share 1 tile AllocationHeight += TileSize[Y]; uint32_t HeightOfPrevMipsInTile = 0; for(int i = 6; i < 9; i++) { OffsetInfo = {}; OffsetInfo.ReqRender = 1; OffsetInfo.MipLevel = i; ResourceInfo->GetOffset(OffsetInfo); EXPECT_EQ(MipOffset, OffsetInfo.Render.Offset64); // Same as previous tile aligned mip offset // X is 0, but Y offset will change EXPECT_EQ(0, OffsetInfo.Render.XOffset); HeightOfPrevMipsInTile += (ResourceHeight >> (i - 1)); EXPECT_EQ(HeightOfPrevMipsInTile, OffsetInfo.Render.YOffset); EXPECT_EQ(0, OffsetInfo.Render.ZOffset); } // Mip 9 is back on tile boundary OffsetInfo = {}; OffsetInfo.ReqRender = 1; OffsetInfo.MipLevel = 9; // Mip 9 ResourceInfo->GetOffset(OffsetInfo); MipOffset += Pitch * TileSize[Y]; AllocationHeight += TileSize[Y]; EXPECT_EQ(MipOffset, OffsetInfo.Render.Offset64); EXPECT_EQ(0, OffsetInfo.Render.XOffset); EXPECT_EQ(0, OffsetInfo.Render.YOffset); EXPECT_EQ(0, OffsetInfo.Render.ZOffset); // Verify ResourceSize and Pitch VerifyResourceSize(ResourceInfo, AllocationHeight * Pitch); VerifyResourcePitch(ResourceInfo, Pitch); VerifyResourcePitchInTiles(ResourceInfo, Pitch / TileSize[X]); // These are verified elsewhere VerifyResourceHAlign(ResourceInfo, 0); VerifyResourceVAlign(ResourceInfo, 0); VerifyResourceQPitch(ResourceInfo, 0); pGmmULTClientContext->DestroyResInfoObject(ResourceInfo); } // Test where Mip1 + Mip2 width > Mip0 width, and where everything fits in 1 tile for(uint32_t i = 0; i < TEST_BPP_64; i++) { const uint32_t ResourceWidth = 0x4; const uint32_t ResourceHeight = 0x2; const uint32_t MaxLod = 0x2; TEST_BPP bpp = static_cast(i); GMM_RESCREATE_PARAMS gmmParams = {}; gmmParams.Type = RESOURCE_2D; gmmParams.Flags.Info.TiledY = 1; gmmParams.NoGfxMemory = 1; gmmParams.Flags.Gpu.Texture = 1; gmmParams.BaseWidth64 = ResourceWidth; gmmParams.BaseHeight = ResourceHeight; gmmParams.MaxLod = MaxLod; gmmParams.Format = SetResourceFormat(bpp); // Create resource GMM_RESOURCE_INFO *ResourceInfo; ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); // Get Alignment that GmmLib is using const uint32_t HAlign = ResourceInfo->GetHAlign(); const uint32_t VAlign = ResourceInfo->GetVAlign(); // Mip1 + Mip2 is the widest width. So it will dictate the pitch of the whole surface uint32_t Pitch = GetBppValue(bpp) * (GMM_ULT_ALIGN(ResourceWidth >> 1, HAlign) + GMM_ULT_ALIGN(ResourceWidth >> 2, HAlign)); Pitch = GMM_ULT_ALIGN(Pitch, TileSize[X]); // Mip0 should be at offset 0 and tile aligned GMM_REQ_OFFSET_INFO OffsetInfo = {}; OffsetInfo.ReqRender = 1; OffsetInfo.MipLevel = 0; //Mip 0 ResourceInfo->GetOffset(OffsetInfo); EXPECT_EQ(0, OffsetInfo.Render.Offset64); EXPECT_EQ(0, OffsetInfo.Render.XOffset); EXPECT_EQ(0, OffsetInfo.Render.YOffset); EXPECT_EQ(0, OffsetInfo.Render.ZOffset); // Mip1 should be after whole Mip0. Not tile aligned OffsetInfo = {}; OffsetInfo.ReqRender = 1; OffsetInfo.MipLevel = 1; // Mip 1 ResourceInfo->GetOffset(OffsetInfo); EXPECT_EQ(0, OffsetInfo.Render.Offset64); // Same tile as Mip0 EXPECT_EQ(0, OffsetInfo.Render.XOffset); EXPECT_EQ(GMM_ULT_ALIGN(ResourceHeight, VAlign), OffsetInfo.Render.YOffset); // After Mip0 EXPECT_EQ(0, OffsetInfo.Render.ZOffset); // Mip2 should be on the right of Mip1. Not tile aligned OffsetInfo = {}; OffsetInfo.ReqRender = 1; OffsetInfo.MipLevel = 2; // Mip 2 ResourceInfo->GetOffset(OffsetInfo); EXPECT_EQ(0, OffsetInfo.Render.Offset64); // Same Tile as Mip0 uint32_t Mip1Width = GMM_ULT_ALIGN(ResourceWidth >> 1, HAlign) * GetBppValue(bpp); EXPECT_EQ(Mip1Width, OffsetInfo.Render.XOffset); // On right of Mip1 EXPECT_EQ(GMM_ULT_ALIGN(ResourceHeight, VAlign), OffsetInfo.Render.YOffset); // After Mip0 EXPECT_EQ(0, OffsetInfo.Render.ZOffset); // Verify ResourceSize and Pitch VerifyResourceSize(ResourceInfo, PAGE_SIZE); // everything should fit in 1 tile VerifyResourcePitch(ResourceInfo, Pitch); VerifyResourcePitchInTiles(ResourceInfo, Pitch / TileSize[X]); // These are verified elsewhere VerifyResourceHAlign(ResourceInfo, 0); VerifyResourceVAlign(ResourceInfo, 0); VerifyResourceQPitch(ResourceInfo, 0); pGmmULTClientContext->DestroyResInfoObject(ResourceInfo); } } // ********************************************************************************// /// @brief ULT for 3D Linear Resource TEST_F(CTestResource, Test3DLinearResource) { // Horizontal/Vertical pixel alignment const uint32_t HAlign = 16; const uint32_t VAlign = 4; GMM_RESCREATE_PARAMS gmmParams = {}; gmmParams.Type = RESOURCE_3D; gmmParams.NoGfxMemory = 1; gmmParams.Flags.Info.Linear = 1; gmmParams.Flags.Gpu.Texture = 1; // Allocate 1x1x1 surface for(uint32_t i = 0; i < TEST_BPP_MAX; i++) { TEST_BPP bpp = static_cast(i); gmmParams.Format = SetResourceFormat(bpp); gmmParams.BaseWidth64 = 0x1; gmmParams.BaseHeight = 0x1; gmmParams.Depth = 0x1; const uint32_t MinPitch = 32; const uint32_t PitchAlignment = 32; GMM_RESOURCE_INFO *ResourceInfo; ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); const uint32_t AlignedWidth = GMM_ULT_ALIGN(gmmParams.BaseWidth64, HAlign); const uint32_t AlignedHeight = GMM_ULT_ALIGN(gmmParams.BaseHeight, VAlign); uint32_t PitchInBytes = AlignedWidth * GetBppValue(bpp); PitchInBytes = GFX_MAX(PitchInBytes, MinPitch); PitchInBytes = GMM_ULT_ALIGN(PitchInBytes, PitchAlignment); const uint32_t AlignedSize = GMM_ULT_ALIGN(PitchInBytes * AlignedHeight, PAGE_SIZE); VerifyResourceHAlign(ResourceInfo, HAlign); VerifyResourceVAlign(ResourceInfo, VAlign); VerifyResourcePitch(ResourceInfo, PitchInBytes); VerifyResourceSize(ResourceInfo, AlignedSize); pGmmULTClientContext->DestroyResInfoObject(ResourceInfo); } // Allocate 256 x 256 x 256 for(uint32_t i = 0; i < TEST_BPP_MAX; i++) { TEST_BPP bpp = static_cast(i); gmmParams.Format = SetResourceFormat(bpp); gmmParams.BaseWidth64 = 256; gmmParams.BaseHeight = 256; gmmParams.Depth = 256; const uint32_t MinPitch = 32; const uint32_t PitchAlignment = 32; GMM_RESOURCE_INFO *ResourceInfo; ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); const uint32_t AlignedWidth = GMM_ULT_ALIGN(gmmParams.BaseWidth64, HAlign); const uint32_t AlignedHeight = GMM_ULT_ALIGN(gmmParams.BaseHeight, VAlign); uint32_t PitchInBytes = AlignedWidth * GetBppValue(bpp); PitchInBytes = GFX_MAX(PitchInBytes, MinPitch); PitchInBytes = GMM_ULT_ALIGN(PitchInBytes, PitchAlignment); const uint32_t AlignedSize = GMM_ULT_ALIGN(PitchInBytes * AlignedHeight * gmmParams.Depth, PAGE_SIZE); VerifyResourceHAlign(ResourceInfo, HAlign); VerifyResourceVAlign(ResourceInfo, VAlign); VerifyResourcePitch(ResourceInfo, PitchInBytes); VerifyResourceSize(ResourceInfo, AlignedSize); pGmmULTClientContext->DestroyResInfoObject(ResourceInfo); } } /// @brief ULT for 3D TileX Resource TEST_F(CTestResource, Test3DTileXResource) { const uint32_t HAlign = 16; const uint32_t VAlign = 4; const uint32_t TileSize[TEST_BPP_MAX][3] = {{512, 8, 1}, {512, 8, 1}, {512, 8, 1}, {512, 8, 1}, {512, 8, 1}}; GMM_RESCREATE_PARAMS gmmParams = {}; gmmParams.Type = RESOURCE_3D; gmmParams.NoGfxMemory = 1; gmmParams.Flags.Info.TiledX = 1; gmmParams.Flags.Gpu.Texture = 1; // Allocate 1x1x1 surface for(uint32_t i = 0; i < TEST_BPP_MAX; i++) { TEST_BPP bpp = static_cast(i); gmmParams.Format = SetResourceFormat(bpp); gmmParams.BaseWidth64 = 0x1; gmmParams.BaseHeight = 0x1; gmmParams.Depth = 0x1; GMM_RESOURCE_INFO *ResourceInfo; ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); VerifyResourceHAlign(ResourceInfo, HAlign); VerifyResourceVAlign(ResourceInfo, VAlign); VerifyResourcePitch(ResourceInfo, TileSize[i][0]); VerifyResourcePitchInTiles(ResourceInfo, 1); VerifyResourceSize(ResourceInfo, GMM_KBYTE(4)); pGmmULTClientContext->DestroyResInfoObject(ResourceInfo); } // Allocate 2 tiles in X dimension for(uint32_t i = 0; i < TEST_BPP_MAX; i++) { TEST_BPP bpp = static_cast(i); gmmParams.Format = SetResourceFormat(bpp); gmmParams.BaseWidth64 = (TileSize[i][0] / GetBppValue(bpp)) + 1; gmmParams.BaseHeight = 0x1; gmmParams.Depth = 0x1; GMM_RESOURCE_INFO *ResourceInfo; ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); VerifyResourceHAlign(ResourceInfo, HAlign); VerifyResourceVAlign(ResourceInfo, VAlign); VerifyResourcePitch(ResourceInfo, 2 * TileSize[i][0]); VerifyResourcePitchInTiles(ResourceInfo, 2); VerifyResourceSize(ResourceInfo, 2 * GMM_KBYTE(4)); pGmmULTClientContext->DestroyResInfoObject(ResourceInfo); } // Allocate 2 tiles in X/Y dimension for(uint32_t i = 0; i < TEST_BPP_MAX; i++) { TEST_BPP bpp = static_cast(i); gmmParams.Format = SetResourceFormat(bpp); gmmParams.BaseWidth64 = (TileSize[i][0] / GetBppValue(bpp)) + 1; gmmParams.BaseHeight = TileSize[i][1] + 1; gmmParams.Depth = 0x1; GMM_RESOURCE_INFO *ResourceInfo; ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); VerifyResourceHAlign(ResourceInfo, HAlign); VerifyResourceVAlign(ResourceInfo, VAlign); VerifyResourcePitch(ResourceInfo, 2 * TileSize[i][0]); VerifyResourcePitchInTiles(ResourceInfo, 2); VerifyResourceSize(ResourceInfo, 2 * 2 * GMM_KBYTE(4)); pGmmULTClientContext->DestroyResInfoObject(ResourceInfo); } // Allocate 2 tiles in X/Y/Z dimension for(uint32_t i = 0; i < TEST_BPP_MAX; i++) { TEST_BPP bpp = static_cast(i); gmmParams.Format = SetResourceFormat(bpp); gmmParams.BaseWidth64 = (TileSize[i][0] / GetBppValue(bpp)) + 1; gmmParams.BaseHeight = TileSize[i][1] + 1; gmmParams.Depth = TileSize[i][2] + 1; const uint32_t MinPitch = 32; const uint32_t PitchAlignment = 32; GMM_RESOURCE_INFO *ResourceInfo; ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); const uint32_t AlignedWidth = GMM_ULT_ALIGN(gmmParams.BaseWidth64, HAlign); uint32_t PitchInBytes = AlignedWidth * GetBppValue(bpp); PitchInBytes = GFX_MAX(PitchInBytes, MinPitch); PitchInBytes = GMM_ULT_ALIGN(PitchInBytes, PitchAlignment); PitchInBytes = GMM_ULT_ALIGN(PitchInBytes, TileSize[i][0]); const uint32_t AlignedHeight = 24; // See details in GetTotal3DHeight(); VerifyResourceHAlign(ResourceInfo, HAlign); VerifyResourceVAlign(ResourceInfo, VAlign); VerifyResourcePitch(ResourceInfo, PitchInBytes); VerifyResourcePitchInTiles(ResourceInfo, PitchInBytes / TileSize[i][0]); VerifyResourceSize(ResourceInfo, AlignedHeight / TileSize[i][1] * PitchInBytes / TileSize[i][0] * GMM_KBYTE(4)); pGmmULTClientContext->DestroyResInfoObject(ResourceInfo); } } /// @brief ULT for 3D TileY Resource TEST_F(CTestResource, Test3DTileYResource) { // Horizontal/Vertical pixel alignment const uint32_t HAlign = 16; const uint32_t VAlign = 4; const uint32_t TileSize[TEST_BPP_MAX][3] = {{128, 32, 1}, {128, 32, 1}, {128, 32, 1}, {128, 32, 1}, {128, 32, 1}}; GMM_RESCREATE_PARAMS gmmParams = {}; gmmParams.Type = RESOURCE_3D; gmmParams.NoGfxMemory = 1; gmmParams.Flags.Info.TiledY = 1; gmmParams.Flags.Gpu.Texture = 1; // Allocate 1x1x1 surface for(uint32_t i = 0; i < TEST_BPP_MAX; i++) { TEST_BPP bpp = static_cast(i); gmmParams.Format = SetResourceFormat(bpp); gmmParams.BaseWidth64 = 0x1; gmmParams.BaseHeight = 0x1; gmmParams.Depth = 0x1; const uint32_t MinPitch = 32; const uint32_t PitchAlignment = 32; GMM_RESOURCE_INFO *ResourceInfo; ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); const uint32_t AlignedWidth = GMM_ULT_ALIGN(gmmParams.BaseWidth64, HAlign); uint32_t PitchInBytes = AlignedWidth * GetBppValue(bpp); PitchInBytes = GFX_MAX(PitchInBytes, MinPitch); PitchInBytes = GMM_ULT_ALIGN(PitchInBytes, PitchAlignment); PitchInBytes = GMM_ULT_ALIGN(PitchInBytes, TileSize[i][0]); VerifyResourceHAlign(ResourceInfo, HAlign); VerifyResourceVAlign(ResourceInfo, VAlign); VerifyResourcePitch(ResourceInfo, PitchInBytes); VerifyResourcePitchInTiles(ResourceInfo, PitchInBytes / TileSize[i][0]); VerifyResourceSize(ResourceInfo, PitchInBytes / TileSize[i][0] * GMM_KBYTE(4)); pGmmULTClientContext->DestroyResInfoObject(ResourceInfo); } // Allocate 2 tiles in X dimension for(uint32_t i = 0; i < TEST_BPP_MAX; i++) { TEST_BPP bpp = static_cast(i); gmmParams.Format = SetResourceFormat(bpp); gmmParams.BaseWidth64 = (TileSize[i][0] / GetBppValue(bpp)) + 1; gmmParams.BaseHeight = 0x1; gmmParams.Depth = 0x1; const uint32_t MinPitch = 32; const uint32_t PitchAlignment = 32; GMM_RESOURCE_INFO *ResourceInfo; ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); const uint32_t AlignedWidth = GMM_ULT_ALIGN(gmmParams.BaseWidth64, HAlign); uint32_t PitchInBytes = AlignedWidth * GetBppValue(bpp); PitchInBytes = GFX_MAX(PitchInBytes, MinPitch); PitchInBytes = GMM_ULT_ALIGN(PitchInBytes, PitchAlignment); PitchInBytes = GMM_ULT_ALIGN(PitchInBytes, TileSize[i][0]); VerifyResourceHAlign(ResourceInfo, HAlign); VerifyResourceVAlign(ResourceInfo, VAlign); VerifyResourcePitch(ResourceInfo, PitchInBytes); VerifyResourcePitchInTiles(ResourceInfo, PitchInBytes / TileSize[i][0]); VerifyResourceSize(ResourceInfo, PitchInBytes / TileSize[i][0] * GMM_KBYTE(4)); pGmmULTClientContext->DestroyResInfoObject(ResourceInfo); } // Allocate 2 tiles in X/Y dimension for(uint32_t i = 0; i < TEST_BPP_MAX; i++) { TEST_BPP bpp = static_cast(i); gmmParams.Format = SetResourceFormat(bpp); gmmParams.BaseWidth64 = (TileSize[i][0] / GetBppValue(bpp)) + 1; gmmParams.BaseHeight = TileSize[i][1] + 1; gmmParams.Depth = 0x1; const uint32_t MinPitch = 32; const uint32_t PitchAlignment = 32; GMM_RESOURCE_INFO *ResourceInfo; ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); const uint32_t AlignedWidth = GMM_ULT_ALIGN(gmmParams.BaseWidth64, HAlign); uint32_t PitchInBytes = AlignedWidth * GetBppValue(bpp); PitchInBytes = GFX_MAX(PitchInBytes, MinPitch); PitchInBytes = GMM_ULT_ALIGN(PitchInBytes, PitchAlignment); PitchInBytes = GMM_ULT_ALIGN(PitchInBytes, TileSize[i][0]); VerifyResourceHAlign(ResourceInfo, HAlign); VerifyResourceVAlign(ResourceInfo, VAlign); VerifyResourcePitch(ResourceInfo, PitchInBytes); VerifyResourcePitchInTiles(ResourceInfo, PitchInBytes / TileSize[i][0]); VerifyResourceSize(ResourceInfo, PitchInBytes / TileSize[i][0] * 2 * GMM_KBYTE(4)); pGmmULTClientContext->DestroyResInfoObject(ResourceInfo); } // Allocate 2 tiles in X/Y/Z dimension for(uint32_t i = 0; i < TEST_BPP_MAX; i++) { TEST_BPP bpp = static_cast(i); gmmParams.Format = SetResourceFormat(bpp); gmmParams.BaseWidth64 = (TileSize[i][0] / GetBppValue(bpp)) + 1; gmmParams.BaseHeight = TileSize[i][1] + 1; gmmParams.Depth = TileSize[i][2] + 1; const uint32_t MinPitch = 32; const uint32_t PitchAlignment = 32; GMM_RESOURCE_INFO *ResourceInfo; ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); const uint32_t AlignedWidth = GMM_ULT_ALIGN(gmmParams.BaseWidth64, HAlign); uint32_t PitchInBytes = AlignedWidth * GetBppValue(bpp); PitchInBytes = GFX_MAX(PitchInBytes, MinPitch); PitchInBytes = GMM_ULT_ALIGN(PitchInBytes, PitchAlignment); PitchInBytes = GMM_ULT_ALIGN(PitchInBytes, TileSize[i][0]); const uint32_t AlignedHeight = 96; // See details in GetTotal3DHeight(); VerifyResourceHAlign(ResourceInfo, HAlign); VerifyResourceVAlign(ResourceInfo, VAlign); VerifyResourcePitch(ResourceInfo, PitchInBytes); VerifyResourcePitchInTiles(ResourceInfo, PitchInBytes / TileSize[i][0]); VerifyResourceSize(ResourceInfo, AlignedHeight / TileSize[i][1] * PitchInBytes / TileSize[i][0] * GMM_KBYTE(4)); pGmmULTClientContext->DestroyResInfoObject(ResourceInfo); } } /// @brief ULT for Cube Linear Resource TEST_F(CTestResource, Test3DTileYMippedResource) { // Horizontal/Vertical pixel alignment const uint32_t HAlign = 16; const uint32_t VAlign = 4; const uint32_t TileSize[TEST_BPP_MAX][3] = {{128, 32, 1}, {128, 32, 1}, {128, 32, 1}, {128, 32, 1}, {128, 32, 1}}; const uint32_t ResourceWidth = 0x100; const uint32_t ResourceHeight = 0x100; const uint32_t ResourceDepth = 0x100; const uint32_t MaxLod = 0x9; for(uint32_t i = 0; i < TEST_BPP_MAX; i++) { TEST_BPP bpp = static_cast(i); GMM_RESCREATE_PARAMS gmmParams = {}; gmmParams.Type = RESOURCE_3D; gmmParams.Flags.Info.TiledY = 1; gmmParams.NoGfxMemory = 1; gmmParams.Flags.Gpu.Texture = 1; gmmParams.BaseWidth64 = ResourceWidth; gmmParams.BaseHeight = ResourceHeight; gmmParams.Depth = ResourceDepth; gmmParams.MaxLod = MaxLod; gmmParams.Format = SetResourceFormat(bpp); GMM_RESOURCE_INFO *ResourceInfo; ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); const uint32_t Pitch = ResourceWidth * GetBppValue(bpp); const uint32_t Mip0Height = ResourceHeight; const uint32_t Mip0Depth = ResourceDepth; // Mip0 GMM_REQ_OFFSET_INFO OffsetInfo = {}; OffsetInfo.ReqRender = 1; OffsetInfo.MipLevel = 0; ResourceInfo->GetOffset(OffsetInfo); EXPECT_EQ(0, OffsetInfo.Render.Offset64); EXPECT_EQ(0, OffsetInfo.Render.XOffset); EXPECT_EQ(0, OffsetInfo.Render.YOffset); EXPECT_EQ(0, OffsetInfo.Render.ZOffset); // Mip1 OffsetInfo = {}; OffsetInfo.ReqRender = 1; OffsetInfo.MipLevel = 1; ResourceInfo->GetOffset(OffsetInfo); const uint32_t SizeOfMip0 = Pitch * Mip0Height * Mip0Depth; const uint32_t Mip1Offset = SizeOfMip0; const uint32_t Mip1Height = Mip0Height >> 1; const uint32_t Mip1Depth = Mip0Depth >> 1; EXPECT_EQ(Mip1Offset, OffsetInfo.Render.Offset64); EXPECT_EQ(0, OffsetInfo.Render.XOffset); EXPECT_EQ(0, OffsetInfo.Render.YOffset); EXPECT_EQ(0, OffsetInfo.Render.ZOffset); // Mip2 OffsetInfo = {}; OffsetInfo.ReqRender = 1; OffsetInfo.MipLevel = 2; ResourceInfo->GetOffset(OffsetInfo); const uint32_t SizeOfMip1 = (Pitch >> 1) * Mip1Height * Mip1Depth; const uint32_t Mip2Offset = Mip1Offset + SizeOfMip1; const uint32_t Mip2Height = Mip1Height >> 1; const uint32_t Mip2Depth = Mip1Depth >> 1; EXPECT_EQ(Mip2Offset, OffsetInfo.Render.Offset64); EXPECT_EQ(0, OffsetInfo.Render.XOffset); EXPECT_EQ(0, OffsetInfo.Render.YOffset); EXPECT_EQ(0, OffsetInfo.Render.ZOffset); // Mip3 OffsetInfo = {}; OffsetInfo.ReqRender = 1; OffsetInfo.MipLevel = 3; ResourceInfo->GetOffset(OffsetInfo); const uint32_t SizeOfMip2 = (Pitch >> 2) * Mip2Height * Mip2Depth; const uint32_t Mip3Offset = Mip2Offset + SizeOfMip2; const uint32_t Mip3Height = Mip2Height >> 1; const uint32_t Mip3Depth = Mip2Depth >> 1; EXPECT_EQ(Mip3Offset, OffsetInfo.Render.Offset64); EXPECT_EQ(0, OffsetInfo.Render.XOffset); EXPECT_EQ(0, OffsetInfo.Render.YOffset); EXPECT_EQ(0, OffsetInfo.Render.ZOffset); // Mip4 (Packed Mip) // For those mip width/height smaller than H/VAlign, they are upscaled to align with H/VAlign OffsetInfo = {}; OffsetInfo.ReqRender = 1; OffsetInfo.MipLevel = 4; ResourceInfo->GetOffset(OffsetInfo); const uint32_t SizeOfMip3 = (Pitch >> 3) * Mip3Height * Mip3Depth; const uint32_t Mip4Offset = Mip3Offset + SizeOfMip3; EXPECT_EQ(Mip4Offset, OffsetInfo.Render.Offset64); EXPECT_EQ(0, OffsetInfo.Render.XOffset); EXPECT_EQ(0, OffsetInfo.Render.YOffset); EXPECT_EQ(0, OffsetInfo.Render.ZOffset); // Mip 5 OffsetInfo = {}; OffsetInfo.ReqRender = 1; OffsetInfo.MipLevel = 5; ResourceInfo->GetOffset(OffsetInfo); EXPECT_EQ(Mip4Offset, OffsetInfo.Render.Offset64); EXPECT_EQ(0, OffsetInfo.Render.XOffset); EXPECT_EQ(16, OffsetInfo.Render.YOffset); EXPECT_EQ(0, OffsetInfo.Render.ZOffset); // Mip 6 OffsetInfo = {}; OffsetInfo.ReqRender = 1; OffsetInfo.MipLevel = 6; ResourceInfo->GetOffset(OffsetInfo); EXPECT_EQ(Mip4Offset, OffsetInfo.Render.Offset64); EXPECT_EQ(0, OffsetInfo.Render.XOffset); EXPECT_EQ(24, OffsetInfo.Render.YOffset); EXPECT_EQ(0, OffsetInfo.Render.ZOffset); // Mip 7 OffsetInfo = {}; OffsetInfo.ReqRender = 1; OffsetInfo.MipLevel = 7; ResourceInfo->GetOffset(OffsetInfo); EXPECT_EQ(Mip4Offset, OffsetInfo.Render.Offset64); EXPECT_EQ(0, OffsetInfo.Render.XOffset); EXPECT_EQ(28, OffsetInfo.Render.YOffset); EXPECT_EQ(0, OffsetInfo.Render.ZOffset); // Mip8 (Start of another packed Mip) OffsetInfo = {}; OffsetInfo.ReqRender = 1; OffsetInfo.MipLevel = 8; ResourceInfo->GetOffset(OffsetInfo); const uint32_t Mip8Offset = Mip4Offset + Pitch * TileSize[i][1]; EXPECT_EQ(Mip8Offset, OffsetInfo.Render.Offset64); EXPECT_EQ(0, OffsetInfo.Render.XOffset); EXPECT_EQ(0, OffsetInfo.Render.YOffset); EXPECT_EQ(0, OffsetInfo.Render.ZOffset); // Mip9 OffsetInfo = {}; OffsetInfo.ReqRender = 1; OffsetInfo.MipLevel = 9; ResourceInfo->GetOffset(OffsetInfo); EXPECT_EQ(Mip8Offset, OffsetInfo.Render.Offset64); EXPECT_EQ(0, OffsetInfo.Render.XOffset); EXPECT_EQ(4, OffsetInfo.Render.YOffset); EXPECT_EQ(0, OffsetInfo.Render.ZOffset); pGmmULTClientContext->DestroyResInfoObject(ResourceInfo); } } // ********************************************************************************// /// @brief ULT for Cube Linear Resource TEST_F(CTestResource, TestCubeLinearResource) { const uint32_t HAlign = 16; const uint32_t VAlign = 4; GMM_RESCREATE_PARAMS gmmParams = {}; gmmParams.Type = RESOURCE_CUBE; gmmParams.NoGfxMemory = 1; gmmParams.Flags.Info.Linear = 1; gmmParams.Flags.Gpu.Texture = 1; // Allocate 1x1 for(uint32_t i = 0; i < TEST_BPP_MAX; i++) { TEST_BPP bpp = static_cast(i); gmmParams.Format = SetResourceFormat(bpp); gmmParams.BaseWidth64 = 0x1; gmmParams.BaseHeight = 0x1; gmmParams.Depth = 0x1; GMM_RESOURCE_INFO *ResourceInfo; ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); VerifyResourceHAlign(ResourceInfo, HAlign); VerifyResourceVAlign(ResourceInfo, VAlign); uint32_t ExpectedPitch = GMM_ULT_MAX(GMM_BYTES(32), HAlign * GetBppValue(bpp)); // Min Pitch = 32 bytes VerifyResourcePitch(ResourceInfo, ExpectedPitch); // As wide as 1 tile VerifyResourcePitchInTiles(ResourceInfo, 1); // not applicable uint32_t ExpectedQPitch = VAlign; VerifyResourceQPitch(ResourceInfo, ExpectedQPitch); // Each face should be VAlign rows apart within a tile VerifyResourceSize(ResourceInfo, // PitchInBytes * Rows where Rows = __GMM_MAX_CUBE_FACE x QPitch, then aligned PAGE_SIZE GMM_ULT_ALIGN(ExpectedPitch * __GMM_MAX_CUBE_FACE * ExpectedQPitch, PAGE_SIZE)); for(uint32_t CubeFaceIndex = 0; CubeFaceIndex < __GMM_MAX_CUBE_FACE; CubeFaceIndex++) { GMM_REQ_OFFSET_INFO OffsetInfo = {}; OffsetInfo.ReqRender = 1; OffsetInfo.CubeFace = static_cast(CubeFaceIndex); ResourceInfo->GetOffset(OffsetInfo); EXPECT_EQ(CubeFaceIndex * ExpectedQPitch * ExpectedPitch, OffsetInfo.Render.Offset64); // Render offset is tile's base address on which cube face begins. EXPECT_EQ(0, OffsetInfo.Render.XOffset); // X Offset should be 0 EXPECT_EQ(0, OffsetInfo.Render.YOffset); // Y Offset should be 0 EXPECT_EQ(0, OffsetInfo.Render.ZOffset); // Z offset N/A should be 0 } pGmmULTClientContext->DestroyResInfoObject(ResourceInfo); } // Allocate arbitrary size (X/Y dimension not applicable as linear surface) // Width and Height must be equal for(uint32_t i = 0; i < TEST_BPP_MAX; i++) { TEST_BPP bpp = static_cast(i); gmmParams.Format = SetResourceFormat(bpp); gmmParams.BaseWidth64 = 0x201; // 512 + 1, help ult HAlign/VAlign/Pitch alignment logic as well. gmmParams.BaseHeight = gmmParams.BaseWidth64; // Heigth must be equal to width. gmmParams.Depth = 0x1; GMM_RESOURCE_INFO *ResourceInfo; ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); VerifyResourceHAlign(ResourceInfo, HAlign); VerifyResourceVAlign(ResourceInfo, VAlign); uint32_t ExpectedPitch = GMM_ULT_ALIGN(gmmParams.BaseWidth64, HAlign) * GetBppValue(bpp); // HAligned-width in bytes. ExpectedPitch = GMM_ULT_ALIGN(ExpectedPitch, GMM_BYTES(32)); VerifyResourcePitch(ResourceInfo, ExpectedPitch); VerifyResourcePitchInTiles(ResourceInfo, 2); // not applicable uint32_t ExpectedQPitch = GMM_ULT_ALIGN(gmmParams.BaseHeight, VAlign); VerifyResourceQPitch(ResourceInfo, ExpectedQPitch); // Each face should be Valigned-BaseHeight rows apart VerifyResourceSize(ResourceInfo, // PitchInBytes * Rows where Rows = __GMM_MAX_CUBE_FACE x QPitch, then aligned PAGE_SIZE GMM_ULT_ALIGN(ExpectedPitch * __GMM_MAX_CUBE_FACE * ExpectedQPitch, PAGE_SIZE)); for(uint32_t CubeFaceIndex = 0; CubeFaceIndex < __GMM_MAX_CUBE_FACE; CubeFaceIndex++) { GMM_REQ_OFFSET_INFO OffsetInfo = {}; OffsetInfo.ReqRender = 1; OffsetInfo.CubeFace = static_cast(CubeFaceIndex); ResourceInfo->GetOffset(OffsetInfo); EXPECT_EQ(CubeFaceIndex * ExpectedQPitch * ExpectedPitch, OffsetInfo.Render.Offset64); // Render offset is tile's base address on which cube face begins. EXPECT_EQ(0, OffsetInfo.Render.XOffset); // X Offset should be 0 EXPECT_EQ(0, OffsetInfo.Render.YOffset); // Y Offset should be 0 EXPECT_EQ(0, OffsetInfo.Render.ZOffset); // Z offset N/A should be 0 } pGmmULTClientContext->DestroyResInfoObject(ResourceInfo); } } /// @brief ULT for Cube Linear Mipped Resource TEST_F(CTestResource, TestCubeLinearMippedResourceArray) { const uint32_t HAlign = 16; const uint32_t VAlign = 4; const uint32_t MaxLod = 9; const uint32_t ResWidth = 0x201; const uint32_t MaxArraySize = 0x10; GMM_RESCREATE_PARAMS gmmParams = {}; gmmParams.Type = RESOURCE_CUBE; gmmParams.NoGfxMemory = 1; gmmParams.Flags.Info.Linear = 1; gmmParams.Flags.Gpu.Texture = 1; gmmParams.MaxLod = MaxLod; gmmParams.ArraySize = MaxArraySize; // Allocate arbitrary size (X/Y dimension not applicable as linear surface) // Width and Height must be equal for(uint32_t i = 0; i < TEST_BPP_MAX; i++) { struct //Cache the value for verifying array elements/Cube face offset/Mip Offset { uint64_t Offset; // Note : absolute mip offset } RenderOffset[GMM_ULT_MAX_MIPMAP] = {}; TEST_BPP bpp = static_cast(i); gmmParams.Format = SetResourceFormat(bpp); gmmParams.BaseWidth64 = ResWidth; // 1024 + 1, help ult HAlign/VAlign/Pitch alignment logic as well. gmmParams.BaseHeight = gmmParams.BaseWidth64; // Heigth must be equal to width. gmmParams.Depth = 0x1; GMM_RESOURCE_INFO *ResourceInfo; ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); VerifyResourceHAlign(ResourceInfo, HAlign); VerifyResourceVAlign(ResourceInfo, VAlign); //------------------------------| // | // LOD0 | // | // | //------------------------------| // LOD1 | LOD2 | // |----------| // | LOD3 | //-------------| LOD4 .. so on // Mip 0 // Mip 0 decides the pitch of the entire surface const uint32_t AlignedWidthMip0 = GMM_ULT_ALIGN(ResWidth, HAlign); // HAlign width in pixel const uint32_t AlignedHeightMip0 = GMM_ULT_ALIGN(ResWidth, VAlign); uint32_t ExpectedPitch = GMM_ULT_ALIGN(gmmParams.BaseWidth64, HAlign) * GetBppValue(bpp); // HAligned-width in bytes. ExpectedPitch = GMM_ULT_ALIGN(ExpectedPitch, GMM_BYTES(32)); VerifyResourcePitch(ResourceInfo, ExpectedPitch); VerifyResourcePitchInTiles(ResourceInfo, 2); // Not applicable // Mip0 should be at offset 0 and tile aligned GMM_REQ_OFFSET_INFO OffsetInfo = {}; OffsetInfo.ReqRender = 1; OffsetInfo.MipLevel = 0; //Mip 0 ResourceInfo->GetOffset(OffsetInfo); EXPECT_EQ(0, OffsetInfo.Render.Offset64); EXPECT_EQ(0, OffsetInfo.Render.XOffset); EXPECT_EQ(0, OffsetInfo.Render.YOffset); EXPECT_EQ(0, OffsetInfo.Render.ZOffset); //cache Mip 0 offset RenderOffset[0].Offset = 0; // Mip 1 should be under mip 0 OffsetInfo = {}; OffsetInfo.ReqRender = 1; OffsetInfo.MipLevel = 1; //Mip 1 ResourceInfo->GetOffset(OffsetInfo); EXPECT_EQ(AlignedHeightMip0 * ExpectedPitch, // Render offset is the absolute address at which the mip begins OffsetInfo.Render.Offset64); EXPECT_EQ(0, OffsetInfo.Render.XOffset); // Not applicable for linear surface EXPECT_EQ(0, OffsetInfo.Render.YOffset); // Not applicable for linear surface EXPECT_EQ(0, OffsetInfo.Render.ZOffset); // n/a //cache Mip 1 offset RenderOffset[1].Offset = AlignedHeightMip0 * ExpectedPitch; //Absolute base const uint32_t AlignedWidthMip1 = GMM_ULT_ALIGN(ResWidth >> 1, HAlign); // Align width in pixel to HAlign const uint32_t AlignedHeightMip1 = GMM_ULT_ALIGN(ResWidth >> 1, VAlign); uint32_t HeightOfMip; uint32_t HeightLinesLevel2 = 0; // Mips 2-9 should be stacked on the right of Mip1 as shown in figure above. for(int i = 2; i <= MaxLod; i++) { OffsetInfo = {}; OffsetInfo.ReqRender = 1; OffsetInfo.MipLevel = i; ResourceInfo->GetOffset(OffsetInfo); HeightOfMip = GMM_ULT_ALIGN(ResWidth >> i, VAlign); EXPECT_EQ((AlignedHeightMip0 + HeightLinesLevel2) * ExpectedPitch + // Render offset is tile's base address on which mip begins (AlignedWidthMip1 * GetBppValue(bpp)), OffsetInfo.Render.Offset64); EXPECT_EQ(0, OffsetInfo.Render.XOffset); // Not applicable for linear surface EXPECT_EQ(0, OffsetInfo.Render.YOffset); // Not applicable for linear surface EXPECT_EQ(0, OffsetInfo.Render.ZOffset); //cache Mip i'th offset RenderOffset[i].Offset = (AlignedHeightMip0 + HeightLinesLevel2) * ExpectedPitch + (AlignedWidthMip1 * GetBppValue(bpp)); HeightLinesLevel2 += HeightOfMip; } uint32_t ExpectedQPitch = AlignedHeightMip0 + AlignedHeightMip1 + 12 * VAlign; VerifyResourceQPitch(ResourceInfo, ExpectedQPitch); // Each face should be Valigned-BaseHeight rows apart VerifyResourceSize(ResourceInfo, // PitchInBytes * Rows where Rows = __GMM_MAX_CUBE_FACE x QPitch, then aligned to tile boundary GMM_ULT_ALIGN(ExpectedPitch * MaxArraySize * __GMM_MAX_CUBE_FACE * ExpectedQPitch, PAGE_SIZE)); // Verify each array element's Mip offset, Cube face offset etc. for(uint32_t ArrayIndex = 0; ArrayIndex < __GMM_MAX_CUBE_FACE; ArrayIndex++) { for(uint32_t CubeFaceIndex = 0; CubeFaceIndex < __GMM_MAX_CUBE_FACE; CubeFaceIndex++) { GMM_REQ_OFFSET_INFO OffsetInfo = {}; OffsetInfo.ReqRender = 1; OffsetInfo.ArrayIndex = ArrayIndex; OffsetInfo.CubeFace = static_cast(CubeFaceIndex); ResourceInfo->GetOffset(OffsetInfo); //Verify cube face offsets EXPECT_EQ(((6 * ArrayIndex) + CubeFaceIndex) * ExpectedQPitch * ExpectedPitch, OffsetInfo.Render.Offset64); // Render offset is tile's base address on which cube face begins. EXPECT_EQ(0, OffsetInfo.Render.XOffset); // X Offset should be 0 as linear surf EXPECT_EQ(0, OffsetInfo.Render.YOffset); // Y Offset should be 0 as linear surf EXPECT_EQ(0, OffsetInfo.Render.ZOffset); // Z offset N/A should be 0 uint32_t CubeFaceBaseOffset = ((6 * ArrayIndex) + CubeFaceIndex) * (ExpectedQPitch * ExpectedPitch); //Verify mip offsets in each cube face for(uint32_t Lod = 0; Lod <= MaxLod; Lod++) { OffsetInfo.MipLevel = Lod; ResourceInfo->GetOffset(OffsetInfo); uint32_t MipOffset = CubeFaceBaseOffset + RenderOffset[Lod].Offset; uint32_t OffsetX = MipOffset % ExpectedPitch; uint32_t OffsetY = MipOffset / ExpectedPitch; uint32_t RenderAlignOffset = OffsetY * ExpectedPitch + OffsetX; EXPECT_EQ(RenderAlignOffset, OffsetInfo.Render.Offset64); // Render offset absolute address on which cube face begins. EXPECT_EQ(0, OffsetInfo.Render.XOffset); // X Offset should be 0 as linear surf EXPECT_EQ(0, OffsetInfo.Render.YOffset); // Y Offset should be 0 as linear surf EXPECT_EQ(0, OffsetInfo.Render.ZOffset); // Z offset N/A should be 0 } } } pGmmULTClientContext->DestroyResInfoObject(ResourceInfo); } } /// @brief ULT for Cube TileX Resource TEST_F(CTestResource, TestCubeTileXResource) { // Cube is allocated as an array of 6 2D surface representing each cube face below //=============================== // q coordinate | face | // 0 | + x | // 1 | - x | // 2 | + y | // 3 | - y | // 4 | + z | // 5 | - z | //=============================== const uint32_t HAlign = 16; const uint32_t VAlign = 4; const uint32_t TileSize[1][2] = {512, 8}; GMM_RESCREATE_PARAMS gmmParams = {}; gmmParams.Type = RESOURCE_CUBE; gmmParams.NoGfxMemory = 1; gmmParams.Flags.Info.TiledX = 1; gmmParams.Flags.Gpu.Texture = 1; // Allocate 1x1 surface so that it occupies 1 Tile in X dimension for(uint32_t i = 0; i < TEST_BPP_MAX; i++) { TEST_BPP bpp = static_cast(i); gmmParams.Format = SetResourceFormat(bpp); gmmParams.BaseWidth64 = 0x1; gmmParams.BaseHeight = 0x1; gmmParams.Depth = 0x1; GMM_RESOURCE_INFO *ResourceInfo; ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); VerifyResourceHAlign(ResourceInfo, HAlign); VerifyResourceVAlign(ResourceInfo, VAlign); uint32_t ExpectedPitch = TileSize[0][0]; VerifyResourcePitch(ResourceInfo, ExpectedPitch); // As wide as 1 tile VerifyResourcePitchInTiles(ResourceInfo, 1); // 1 tile wide uint32_t ExpectedQPitch = VAlign; VerifyResourceQPitch(ResourceInfo, ExpectedQPitch); // Each face should be VAlign rows apart within a tile VerifyResourceSize(ResourceInfo, // PitchInBytes * Rows where Rows = __GMM_MAX_CUBE_FACE x QPitch, then aligned to tile boundary ExpectedPitch * GMM_ULT_ALIGN(__GMM_MAX_CUBE_FACE * ExpectedQPitch, TileSize[0][1])); for(uint32_t CubeFaceIndex = 0; CubeFaceIndex < __GMM_MAX_CUBE_FACE; CubeFaceIndex++) { GMM_REQ_OFFSET_INFO OffsetInfo = {}; OffsetInfo.ReqRender = 1; OffsetInfo.CubeFace = static_cast(CubeFaceIndex); ResourceInfo->GetOffset(OffsetInfo); EXPECT_EQ(GMM_ULT_ALIGN_FLOOR(CubeFaceIndex * ExpectedQPitch, TileSize[0][1]) * ExpectedPitch, OffsetInfo.Render.Offset64); // Render offset is tile's base address on which cube face begins. EXPECT_EQ(0, OffsetInfo.Render.XOffset); // X Offset should be 0 EXPECT_EQ((CubeFaceIndex * ExpectedQPitch) % TileSize[0][1], OffsetInfo.Render.YOffset); // Y Offset should be (CubeFaceIndex * QPitch) % TileHeight EXPECT_EQ(0, OffsetInfo.Render.ZOffset); // Z offset N/A should be 0 } pGmmULTClientContext->DestroyResInfoObject(ResourceInfo); } // Allocate 2 tiles in X dimension. // Width and Height must be equal for(uint32_t i = 0; i < TEST_BPP_MAX; i++) { TEST_BPP bpp = static_cast(i); gmmParams.Format = SetResourceFormat(bpp); gmmParams.BaseWidth64 = (TileSize[0][0] / GetBppValue(bpp)) + 1; // 1 pixel larger than 1 tile width gmmParams.BaseHeight = gmmParams.BaseWidth64; // Heigth must be equal to width. gmmParams.Depth = 0x1; GMM_RESOURCE_INFO *ResourceInfo; ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); VerifyResourceHAlign(ResourceInfo, HAlign); VerifyResourceVAlign(ResourceInfo, VAlign); uint32_t ExpectedPitch = TileSize[0][0] * 2; // As wide as 2 tile VerifyResourcePitch(ResourceInfo, ExpectedPitch); VerifyResourcePitchInTiles(ResourceInfo, 2); // 2 tile wide uint32_t ExpectedQPitch = GMM_ULT_ALIGN(gmmParams.BaseHeight, VAlign); VerifyResourceQPitch(ResourceInfo, ExpectedQPitch); // Each face should be Valigned-BaseHeight rows apart VerifyResourceSize(ResourceInfo, // PitchInBytes * Rows where Rows = __GMM_MAX_CUBE_FACE x QPitch, then aligned to tile boundary ExpectedPitch * GMM_ULT_ALIGN(__GMM_MAX_CUBE_FACE * ExpectedQPitch, TileSize[0][1])); for(uint32_t CubeFaceIndex = 0; CubeFaceIndex < __GMM_MAX_CUBE_FACE; CubeFaceIndex++) { GMM_REQ_OFFSET_INFO OffsetInfo = {}; OffsetInfo.ReqRender = 1; OffsetInfo.CubeFace = static_cast(CubeFaceIndex); ResourceInfo->GetOffset(OffsetInfo); EXPECT_EQ(GMM_ULT_ALIGN_FLOOR(CubeFaceIndex * ExpectedQPitch, TileSize[0][1]) * ExpectedPitch, OffsetInfo.Render.Offset64); // Render offset is tile's base address on which cube face begins. EXPECT_EQ(0, OffsetInfo.Render.XOffset); // X Offset should be 0 EXPECT_EQ((CubeFaceIndex * ExpectedQPitch) % TileSize[0][1], OffsetInfo.Render.YOffset); // Y Offset should be (CubeFaceIndex * QPitch) % TileHeight EXPECT_EQ(0, OffsetInfo.Render.ZOffset); // Z offset N/A should be 0 } pGmmULTClientContext->DestroyResInfoObject(ResourceInfo); } } /// @brief ULT for Cube TileY Resource TEST_F(CTestResource, TestCubeTileYResource) { // Cube is allocated as an array of 6 2D surface representing each cube face below //=============================== // q coordinate | face | // 0 | + x | // 1 | - x | // 2 | + y | // 3 | - y | // 4 | + z | // 5 | - z | //=============================== const uint32_t HAlign = 16; const uint32_t VAlign = 4; const uint32_t TileSize[1][2] = {128, 32}; GMM_RESCREATE_PARAMS gmmParams = {}; gmmParams.Type = RESOURCE_CUBE; gmmParams.NoGfxMemory = 1; gmmParams.Flags.Info.TiledY = 1; gmmParams.Flags.Gpu.Texture = 1; // Allocate 1x1 surface within a tile. for(uint32_t i = 0; i < TEST_BPP_128; i++) //TEST_BPP_128 cannot fit in a tile as HAlign = 16 { TEST_BPP bpp = static_cast(i); gmmParams.Format = SetResourceFormat(bpp); gmmParams.BaseWidth64 = 0x1; gmmParams.BaseHeight = 0x1; gmmParams.Depth = 0x1; GMM_RESOURCE_INFO *ResourceInfo; ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); VerifyResourceHAlign(ResourceInfo, HAlign); VerifyResourceVAlign(ResourceInfo, VAlign); VerifyResourcePitch(ResourceInfo, TileSize[0][0]); // As wide as 1 tile VerifyResourcePitchInTiles(ResourceInfo, 1); // 1 tile wide VerifyResourceSize(ResourceInfo, GMM_KBYTE(4)); // All 6 faces should be accomated in a tile. VerifyResourceQPitch(ResourceInfo, VAlign); // Each face should be VAlign rows apart within a tile for(uint32_t CubeFaceIndex = 0; CubeFaceIndex < __GMM_MAX_CUBE_FACE; CubeFaceIndex++) { GMM_REQ_OFFSET_INFO OffsetInfo = {}; OffsetInfo.ReqRender = 1; OffsetInfo.CubeFace = static_cast(CubeFaceIndex); ResourceInfo->GetOffset(OffsetInfo); EXPECT_EQ(0, OffsetInfo.Render.Offset64); // Render offset should be 0 as its on single tile. EXPECT_EQ(0, OffsetInfo.Render.XOffset); // X Offset should be 0 EXPECT_EQ(CubeFaceIndex * VAlign, OffsetInfo.Render.YOffset); // Y Offset should be VALIGN * CubeFace Index EXPECT_EQ(0, OffsetInfo.Render.ZOffset); } pGmmULTClientContext->DestroyResInfoObject(ResourceInfo); } // Allocate 2 tiles in X dimension. // Width and Height of Cube must be equal for(uint32_t i = 0; i < TEST_BPP_MAX; i++) { TEST_BPP bpp = static_cast(i); gmmParams.Format = SetResourceFormat(bpp); gmmParams.BaseWidth64 = (TileSize[0][0] / GetBppValue(bpp)) + 1; // 1 pixel larger than 1 tile width gmmParams.BaseHeight = gmmParams.BaseWidth64; // Heigth must be equal to width. gmmParams.Depth = 0x1; GMM_RESOURCE_INFO *ResourceInfo; ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); VerifyResourceHAlign(ResourceInfo, HAlign); VerifyResourceVAlign(ResourceInfo, VAlign); uint32_t ExpectedPitch = TileSize[0][0] * 2; // As wide as 2 tile VerifyResourcePitch(ResourceInfo, ExpectedPitch); VerifyResourcePitchInTiles(ResourceInfo, 2); // 2 tile wide uint32_t ExpectedQPitch = GMM_ULT_ALIGN(gmmParams.BaseHeight, VAlign); VerifyResourceQPitch(ResourceInfo, ExpectedQPitch); // Each face should be Valigned-BaseHeight rows apart VerifyResourceSize(ResourceInfo, // PitchInBytes * Rows where Rows = __GMM_MAX_CUBE_FACE x QPitch, then aligned to tile boundary ExpectedPitch * GMM_ULT_ALIGN(__GMM_MAX_CUBE_FACE * ExpectedQPitch, TileSize[0][1])); for(uint32_t CubeFaceIndex = 0; CubeFaceIndex < __GMM_MAX_CUBE_FACE; CubeFaceIndex++) { GMM_REQ_OFFSET_INFO OffsetInfo = {}; OffsetInfo.ReqRender = 1; OffsetInfo.CubeFace = static_cast(CubeFaceIndex); ResourceInfo->GetOffset(OffsetInfo); EXPECT_EQ(GMM_ULT_ALIGN_FLOOR(CubeFaceIndex * ExpectedQPitch, TileSize[0][1]) * ExpectedPitch, OffsetInfo.Render.Offset64); // Render offset is tile's base address on which cube face begins. EXPECT_EQ(0, OffsetInfo.Render.XOffset); // X Offset should be 0 EXPECT_EQ((CubeFaceIndex * ExpectedQPitch) % TileSize[0][1], OffsetInfo.Render.YOffset); // Y Offset should be (CubeFaceIndex * QPitch) % TileHeight EXPECT_EQ(0, OffsetInfo.Render.ZOffset); // Z offset N/A should be 0 } pGmmULTClientContext->DestroyResInfoObject(ResourceInfo); } } /// @brief ULT for Cube TileY Mipped Resource Array TEST_F(CTestResource, TestCubeTileYMippedResourceArray) { const uint32_t HAlign = 16; const uint32_t VAlign = 4; const uint32_t TileSize[2] = {128, 32}; enum Coords { X = 0, Y = 1 }; GMM_RESCREATE_PARAMS gmmParams = {}; gmmParams.Type = RESOURCE_CUBE; gmmParams.NoGfxMemory = 1; gmmParams.Flags.Info.TiledY = 1; gmmParams.Flags.Gpu.Texture = 1; // Allocate CUBE surface for(uint32_t i = 0; i < TEST_BPP_MAX; i++) { const uint32_t ResWidth = 0x201; const uint32_t MaxLod = 0x9; const uint32_t MaxArraySize = 0x10; struct //Cache the value for verifying array elements/Cube face offset/Mip Offset { uint64_t Offset; // Note : absolute mip offset } RenderOffset[GMM_ULT_MAX_MIPMAP]; TEST_BPP bpp = static_cast(i); gmmParams.Format = SetResourceFormat(bpp); gmmParams.BaseWidth64 = ResWidth; // 1 pixel larger than 1 tile width gmmParams.BaseHeight = gmmParams.BaseWidth64; // Heigth must be equal to width. gmmParams.Depth = 0x1; gmmParams.MaxLod = MaxLod; gmmParams.ArraySize = MaxArraySize; GMM_RESOURCE_INFO *ResourceInfo; ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); VerifyResourceHAlign(ResourceInfo, HAlign); VerifyResourceVAlign(ResourceInfo, VAlign); //------------------------------| // | // LOD0 | // | // | //------------------------------| // LOD1 | LOD2 | // |----------| // | LOD3 | //-------------| LOD4 .. so on //Mip 0 //Mip 0 decides the pitch of the entire resource. const uint32_t AlignedWidthMip0 = GMM_ULT_ALIGN(ResWidth, HAlign); // HAlign width in pixel const uint32_t AlignedHeightMip0 = GMM_ULT_ALIGN(ResWidth, VAlign); uint32_t ExpectedPitch = GMM_ULT_ALIGN(AlignedWidthMip0 * GetBppValue(bpp), TileSize[X]); // Align AlignedWidthMip0 to 128 bytes VerifyResourcePitch(ResourceInfo, ExpectedPitch); VerifyResourcePitchInTiles(ResourceInfo, ExpectedPitch / TileSize[X]); // Pitch/TileY-Width // Mip0 should be at offset 0 and tile aligned GMM_REQ_OFFSET_INFO OffsetInfo = {}; OffsetInfo.ReqRender = 1; OffsetInfo.MipLevel = 0; //Mip 0 ResourceInfo->GetOffset(OffsetInfo); EXPECT_EQ(0, OffsetInfo.Render.Offset64); EXPECT_EQ(0, OffsetInfo.Render.XOffset); EXPECT_EQ(0, OffsetInfo.Render.YOffset); EXPECT_EQ(0, OffsetInfo.Render.ZOffset); //cache Mip 0 offset RenderOffset[0].Offset = 0; // Mip 1 should be under mip 0 OffsetInfo = {}; OffsetInfo.ReqRender = 1; OffsetInfo.MipLevel = 1; //Mip 1 ResourceInfo->GetOffset(OffsetInfo); EXPECT_EQ(GMM_ULT_ALIGN_FLOOR(AlignedHeightMip0, TileSize[Y]) * ExpectedPitch, // Render offset is tile's base address on which mip begins OffsetInfo.Render.Offset64); EXPECT_EQ(0, OffsetInfo.Render.XOffset); // Aligns with Mip0 at X = 0 EXPECT_EQ((AlignedHeightMip0) % TileSize[Y], OffsetInfo.Render.YOffset); // AlignedHeightMip0 % TileY-Height EXPECT_EQ(0, OffsetInfo.Render.ZOffset); //cache Mip 1 offset RenderOffset[1].Offset = AlignedHeightMip0 * ExpectedPitch; //Absolute base const uint32_t AlignedWidthMip1 = GMM_ULT_ALIGN(ResWidth >> 1, HAlign); // Align width in pixel to HAlign const uint32_t AlignedHeightMip1 = GMM_ULT_ALIGN(ResWidth >> 1, VAlign); uint32_t HeightOfMip; uint32_t HeightLinesLevel2 = 0; // Mips 2-9 should be stacked on the right of Mip1 as shown in figure above. for(int i = 2; i <= MaxLod; i++) { OffsetInfo = {}; OffsetInfo.ReqRender = 1; OffsetInfo.MipLevel = i; ResourceInfo->GetOffset(OffsetInfo); HeightOfMip = GMM_ULT_ALIGN(ResWidth >> i, VAlign); EXPECT_EQ(GMM_ULT_ALIGN_FLOOR(AlignedHeightMip0 + HeightLinesLevel2, TileSize[Y]) * ExpectedPitch + // Render offset is tile's base address on which mip begins (AlignedWidthMip1 * GetBppValue(bpp) / TileSize[X]) * PAGE_SIZE, OffsetInfo.Render.Offset64); EXPECT_EQ((AlignedWidthMip1 * GetBppValue(bpp)) % TileSize[X], OffsetInfo.Render.XOffset); // Aligns with Mip0 at X = 0 EXPECT_EQ((AlignedHeightMip0 + HeightLinesLevel2) % TileSize[Y], OffsetInfo.Render.YOffset); // AlignedHeightMip0 % TileY-Height EXPECT_EQ(0, OffsetInfo.Render.ZOffset); //cache Mip i'th offset RenderOffset[i].Offset = (AlignedHeightMip0 + HeightLinesLevel2) * ExpectedPitch + (AlignedWidthMip1 * GetBppValue(bpp)); HeightLinesLevel2 += HeightOfMip; } uint32_t ExpectedQPitch = AlignedHeightMip0 + AlignedHeightMip1 + 12 * VAlign; VerifyResourceQPitch(ResourceInfo, ExpectedQPitch); // Each face should be Valigned-BaseHeight rows apart VerifyResourceSize(ResourceInfo, // PitchInBytes * Rows where Rows = __GMM_MAX_CUBE_FACE x QPitch, then aligned to tile boundary ExpectedPitch * GMM_ULT_ALIGN(MaxArraySize * __GMM_MAX_CUBE_FACE * ExpectedQPitch, TileSize[Y])); // Verify each array element's Mip offset, Cube face offset etc. for(uint32_t ArrayIndex = 0; ArrayIndex < __GMM_MAX_CUBE_FACE; ArrayIndex++) { for(uint32_t CubeFaceIndex = 0; CubeFaceIndex < __GMM_MAX_CUBE_FACE; CubeFaceIndex++) { GMM_REQ_OFFSET_INFO OffsetInfo = {}; OffsetInfo.ReqRender = 1; OffsetInfo.ArrayIndex = ArrayIndex; OffsetInfo.CubeFace = static_cast(CubeFaceIndex); ResourceInfo->GetOffset(OffsetInfo); //Verify cube face offsets EXPECT_EQ(GMM_ULT_ALIGN_FLOOR(((6 * ArrayIndex) + CubeFaceIndex) * ExpectedQPitch, TileSize[Y]) * ExpectedPitch, OffsetInfo.Render.Offset64); // Render offset is tile's base address on which cube face begins. EXPECT_EQ(0, OffsetInfo.Render.XOffset); // X Offset should be 0 EXPECT_EQ((((6 * ArrayIndex) + CubeFaceIndex) * ExpectedQPitch) % TileSize[Y], OffsetInfo.Render.YOffset); // Y Offset should be (CubeFaceIndex * QPitch) % TileHeight EXPECT_EQ(0, OffsetInfo.Render.ZOffset); // Z offset N/A should be 0 uint32_t CubeFaceBaseOffset = ((6 * ArrayIndex) + CubeFaceIndex) * (ExpectedQPitch * ExpectedPitch); //Verify mip offsets in each cube face for(uint32_t Lod = 0; Lod <= MaxLod; Lod++) { OffsetInfo.MipLevel = Lod; ResourceInfo->GetOffset(OffsetInfo); uint32_t MipOffset = CubeFaceBaseOffset + RenderOffset[Lod].Offset; uint32_t OffsetX = MipOffset % ExpectedPitch; uint32_t TileAlignedOffsetX = GMM_ULT_ALIGN_FLOOR(OffsetX, TileSize[X]); OffsetX -= TileAlignedOffsetX; uint32_t OffsetY = MipOffset / ExpectedPitch; uint32_t TileAlignedOffsetY = GMM_ULT_ALIGN_FLOOR(OffsetY, TileSize[Y]); OffsetY -= TileAlignedOffsetY; uint32_t RenderAlignOffset = TileAlignedOffsetY * ExpectedPitch + (TileAlignedOffsetX / TileSize[X]) * PAGE_SIZE; EXPECT_EQ(RenderAlignOffset, OffsetInfo.Render.Offset64); // Render offset is tile's base address on which cube face begins. EXPECT_EQ(OffsetX, OffsetInfo.Render.XOffset); EXPECT_EQ(OffsetY, OffsetInfo.Render.YOffset); // Y Offset should be (CubeFaceIndex * QPitch) % TileHeight EXPECT_EQ(0, OffsetInfo.Render.ZOffset); // Z offset N/A should be 0 } } } pGmmULTClientContext->DestroyResInfoObject(ResourceInfo); } } // ********************************************************************************// /// @brief ULT for Buffer Resource TEST_F(CTestResource, TestBufferLinearResource) { } // ********************************************************************************// /// @brief ULT for Separate Stencil Resource TEST_F(CTestResource, TestSeparateStencil) { const uint32_t HAlign = 8; //Separate Stencil alignment (8x8) const uint32_t VAlign = 8; const uint32_t StencilTileSize[1][2] = {64, 64}; //Stencil is TileW, swizzled (2*w x h/2) onto TileY const uint32_t AllocTileSize[1][2] = {128, 32}; //Allocation-aligned to TileY since some HW units support TileW by WA'ing TileY GMM_RESCREATE_PARAMS gmmParams = {}; gmmParams.NoGfxMemory = 1; gmmParams.Flags.Info.TiledX = 1; //Any input Tiling - changed to TileW? YES, but expected one is TileW gmmParams.Flags.Gpu.SeparateStencil = 1; gmmParams.Format = SetResourceFormat(TEST_BPP_8); //Only R8_UNIT supported, driver assumes so, but creates resource even for other bpps requests (as bpp=8) // Allocate 1x1 surface so that it occupies 1 Tile in X dimension for(uint32_t i = RESOURCE_1D; i <= RESOURCE_CUBE; i++) //SeparateStencil with 2D, cube, 1D, 3D with mip-maps { gmmParams.Type = static_cast(i); gmmParams.BaseWidth64 = 0x1; gmmParams.BaseHeight = 0x1; gmmParams.Depth = 0x1; //Depth !=1 supported for stencil? Supported on all Gens. Gen8 gives only Lod0 for mip-mapped Stencil too GMM_RESOURCE_INFO *ResourceInfo; ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); VerifyResourceHAlign(ResourceInfo, HAlign); VerifyResourceVAlign(ResourceInfo, VAlign); uint32_t ExpectedPitch = StencilTileSize[0][0] * 2; // 2 TileW tiles interleaved on same row VerifyResourcePitch(ResourceInfo, ExpectedPitch); VerifyResourcePitchInTiles(ResourceInfo, 1); // 1 tileY wide if(gmmParams.ArraySize > 1 || gmmParams.Type == RESOURCE_CUBE) { uint32_t ExpectedQPitch = GMM_ULT_ALIGN(gmmParams.BaseHeight, VAlign); //Interleaved rows for TielW-arrangement. No Qpitch for 3d, only for 2d-array and cube on Gen8 //it needs to be in VALign multiple, for Stencil buffer needs it as multiple of 8 VerifyResourceQPitch(ResourceInfo, ExpectedQPitch); // Each face should be VAlign rows apart within a tile } VerifyResourceSize(ResourceInfo, GMM_KBYTE(4)); //1 Tile should be enough pGmmULTClientContext->DestroyResInfoObject(ResourceInfo); } // Allocate 2 tiles in X dimension. for(uint32_t i = RESOURCE_1D; i <= RESOURCE_CUBE; i++) { gmmParams.Type = static_cast(i); //Could we loop over Res_types for speacil allocation types gmmParams.BaseWidth64 = StencilTileSize[0][0] + 0x1; gmmParams.BaseHeight = (gmmParams.Type == RESOURCE_1D) ? 0x1 : (gmmParams.Type == RESOURCE_CUBE) ? gmmParams.BaseWidth64 : StencilTileSize[0][1]; gmmParams.Depth = 0x1; //HW doesn't support Depth/STC for 3D res_type, but driver has no such restriction GMM_RESOURCE_INFO *ResourceInfo; ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); VerifyResourceHAlign(ResourceInfo, HAlign); VerifyResourceVAlign(ResourceInfo, VAlign); uint32_t ExpectedPitch = StencilTileSize[0][0] * 2 * 2; // Requires 2 StencilTiles, further doubled for interleaved rows 2*w = Pitch VerifyResourcePitch(ResourceInfo, ExpectedPitch); VerifyResourcePitchInTiles(ResourceInfo, 2); // 2 tiles wide uint32_t ExpectedQPitch = 0; if(gmmParams.ArraySize > 1 || gmmParams.Type == RESOURCE_CUBE) { ExpectedQPitch = GMM_ULT_ALIGN(gmmParams.BaseHeight, VAlign); //Interleaved rows for TileW-arrangement - but Qpitch calculated w/o interleaving in mind. No Qpitch for 3d, only for 2d-array and cube on Gen8 //GMM_ULT_ALIGN(GMM_ULT_ALIGN(gmmParams.BaseHeight, VAlign)/2, VAlign); //Doesn't HW expect distance in rows between 2 cube-faces (array slices) : It does so, but in logical view not physical view, so not interleaved rows. //it needs to be in VALign multiple, for Stencil buffer needs it as multiple of 8 VerifyResourceQPitch(ResourceInfo, ExpectedQPitch); // Each face should be VAlign rows apart within a tile } VerifyResourceSize(ResourceInfo, // PitchInBytes * Rows where Rows = (__GMM_MAX_CUBE_FACE x QPitch) /2 (Stencil height = halved due to interleaving), then aligned to tile boundary ((gmmParams.Type == RESOURCE_CUBE) ? ExpectedPitch * GMM_ULT_ALIGN(ExpectedQPitch * __GMM_MAX_CUBE_FACE / 2, AllocTileSize[0][1]) : //cube 2 * GMM_KBYTE(4))); pGmmULTClientContext->DestroyResInfoObject(ResourceInfo); } // Allocate 2 tiles in X/Y dimension. for(uint32_t i = RESOURCE_2D; i <= RESOURCE_3D; i++) { gmmParams.Type = static_cast(i); gmmParams.BaseWidth64 = StencilTileSize[0][0] + 0x1; gmmParams.BaseHeight = StencilTileSize[0][1] + 0x1; gmmParams.Depth = 0x1; GMM_RESOURCE_INFO *ResourceInfo; ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); VerifyResourceHAlign(ResourceInfo, HAlign); VerifyResourceVAlign(ResourceInfo, VAlign); uint32_t ExpectedPitch = StencilTileSize[0][0] * 2 * 2; // Requires 2 StencilTiles, double again for interleaved rows 2*w = Pitch, VerifyResourcePitch(ResourceInfo, ExpectedPitch); VerifyResourcePitchInTiles(ResourceInfo, 2); // 2 tile wide VerifyResourceSize(ResourceInfo, 2 * 2 * GMM_KBYTE(4)); pGmmULTClientContext->DestroyResInfoObject(ResourceInfo); } // Allocate multi-tiles in X/Y/Z dimension. for(uint32_t i = RESOURCE_3D; i <= RESOURCE_3D; i++) { gmmParams.Type = static_cast(i); gmmParams.BaseWidth64 = StencilTileSize[0][0] + 0x1; gmmParams.BaseHeight = StencilTileSize[0][1] + 0x1; gmmParams.Depth = StencilTileSize[0][1] + 0x1; GMM_RESOURCE_INFO *ResourceInfo; ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); VerifyResourceHAlign(ResourceInfo, HAlign); VerifyResourceVAlign(ResourceInfo, VAlign); uint32_t ExpectedPitch = StencilTileSize[0][0] * 2 * 2; // Requires 2 StencilTiles, doubled again for interleaved rows 2*w = Pitch, width < 1.5 Tiles VerifyResourcePitch(ResourceInfo, ExpectedPitch); VerifyResourcePitchInTiles(ResourceInfo, 2); // 2 tile wide uint32_t TwoDQPitch, ExpectedQPitch = 0; { TwoDQPitch = GMM_ULT_ALIGN(gmmParams.BaseHeight, VAlign); //Interleaved rows for TileW-arrangement - but Qpitch calculated w/o interleaving in mind. No Qpitch for 3d, only for 2d-array and cube on Gen8 //GMM_ULT_ALIGN(GMM_ULT_ALIGN(gmmParams.BaseHeight, VAlign)/2, VAlign); //Doesn't HW expect distance in rows between 2 cube-faces (array slices) : It does so, but in logical view not physical view, so not interleaved rows. //it needs to be in VALign multiple, for Stencil buffer needs it as multiple of 8 //VerifyResourceQPitch(ResourceInfo, TwoDQPitch); //Gen8 doesn't support QPitch for RES_3D ExpectedQPitch = gmmParams.Depth * TwoDQPitch; //Depth slices arranged as 2D-arrayed slices. } VerifyResourceSize(ResourceInfo, ExpectedPitch * GMM_ULT_ALIGN(ExpectedQPitch / 2, AllocTileSize[0][1])); pGmmULTClientContext->DestroyResInfoObject(ResourceInfo); } //Mip-mapped array case: Stencil QPitch = h0 ie Stencil only has Lod0 //Above limit not there, should have mip-map block height for Qpitch } /// @brief ULT for Hiz Depth buffer Resource TEST_F(CTestResource, TestHiZ) { const uint32_t HAlign = 16; //HiZ alignment (16x8) [Depth 16bit: 8x4; ow 4x4] const uint32_t VAlign = 4; // 8; Need to debug why driver uses VAlign/2 //const uint32_t DepthTileSize[1][2] = { 64, 64 }; //Depth/Stencil buffer should be TileY/Ys/Yf only (16,24,32 bpp only) no 3D or MSAA const uint32_t AllocTileSize[1][2] = {128, 32}; //HiZ is TileY GMM_RESCREATE_PARAMS gmmParams = {}; gmmParams.NoGfxMemory = 1; gmmParams.Flags.Info.TiledX = 1; //Not supported for Depth buffer, but HiZ output is TileY gmmParams.Flags.Gpu.Depth = 1; //GPU Flags= Depth/SeparateStencil + HiZ gmmParams.Flags.Gpu.HiZ = 1; // Allocate 1x1 surface so that it occupies 1 Tile in X dimension for(uint32_t j = TEST_BPP_8; j <= TEST_BPP_128; j++) //Depth bpp doesn't matter, Depth px dimensions decide HiZ size in HW { gmmParams.Format = SetResourceFormat(static_cast(j)); //Only 16,24,32 supported; But driver creates the resource even for other bpps without failing for(uint32_t i = RESOURCE_1D; i <= RESOURCE_CUBE; i++) //3D doesn't support HiZ - test driver returns proper? { gmmParams.Type = static_cast(i); gmmParams.BaseWidth64 = 0x1; gmmParams.BaseHeight = 0x1; gmmParams.Depth = 0x1; GMM_RESOURCE_INFO *ResourceInfo; ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); VerifyResourceHAlign(ResourceInfo, HAlign); VerifyResourceVAlign(ResourceInfo, VAlign); uint32_t ExpectedPitch = AllocTileSize[0][0]; VerifyResourcePitch(ResourceInfo, ExpectedPitch); VerifyResourcePitchInTiles(ResourceInfo, 1); // 1 tileY wide if(gmmParams.ArraySize > 1 || gmmParams.Type == RESOURCE_CUBE) { uint32_t ExpectedQPitch = GMM_ULT_ALIGN(gmmParams.BaseHeight, VAlign); ExpectedQPitch = GMM_ULT_ALIGN(ExpectedQPitch / 2, VAlign); VerifyResourceQPitch(ResourceInfo, ExpectedQPitch); // Each face should be VAlign rows apart within a tile, Turn on verification after clarity } VerifyResourceSize(ResourceInfo, GMM_KBYTE(4)); //1 Tile should be enough pGmmULTClientContext->DestroyResInfoObject(ResourceInfo); } } // Allocate 2 tiles in X dimension. (muti-tiles Tiles in Y dimension for cube/array) for(uint32_t i = RESOURCE_1D; i <= RESOURCE_CUBE; i++) { gmmParams.Type = static_cast(i); gmmParams.BaseWidth64 = AllocTileSize[0][0] + 0x1; gmmParams.BaseHeight = (gmmParams.Type == RESOURCE_1D) ? 0x1 : (gmmParams.Type == RESOURCE_CUBE) ? gmmParams.BaseWidth64 : VAlign / 2; gmmParams.ArraySize = (gmmParams.Type != RESOURCE_3D) ? VAlign : 1; // Gen8 doesn't support 3D-arrays (so HiZ not supported) [test 3d arrays once -- HiZ would fail but ResCreate doesn't?] gmmParams.Depth = 0x1; GMM_RESOURCE_INFO *ResourceInfo; ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); VerifyResourceHAlign(ResourceInfo, HAlign); VerifyResourceVAlign(ResourceInfo, VAlign); uint32_t ExpectedPitch = AllocTileSize[0][0] * 2; VerifyResourcePitch(ResourceInfo, ExpectedPitch); VerifyResourcePitchInTiles(ResourceInfo, 2); // 2 tileY wide uint32_t ExpectedQPitch = 0; if(gmmParams.ArraySize > 1 || gmmParams.Type == RESOURCE_CUBE) { ExpectedQPitch = GMM_ULT_ALIGN(gmmParams.BaseHeight, VAlign); ExpectedQPitch = GMM_ULT_ALIGN(ExpectedQPitch / 2, VAlign); VerifyResourceQPitch(ResourceInfo, ExpectedQPitch); // Each face should be VAlign rows apart within a tile. Turn on verification after clarity } VerifyResourceSize(ResourceInfo, // PitchInBytes * Rows where Rows = (__GMM_MAX_CUBE_FACE x QPitch) /2 (Stencil height = halved due to interleaving), then aligned to tile boundary ((gmmParams.Type == RESOURCE_CUBE) ? ExpectedPitch * GMM_ULT_ALIGN(ExpectedQPitch * gmmParams.ArraySize * __GMM_MAX_CUBE_FACE, AllocTileSize[0][1]) : //cube ((gmmParams.ArraySize > 1) ? ExpectedPitch * GMM_ULT_ALIGN(ExpectedQPitch * gmmParams.ArraySize, AllocTileSize[0][1]) : //array 2 * GMM_KBYTE(4)))); pGmmULTClientContext->DestroyResInfoObject(ResourceInfo); } // Allocate 2 tiles in X/Y dimension (non-arrayed) Multi-tiles for 3D for(uint32_t i = RESOURCE_2D; i <= RESOURCE_3D; i++) { gmmParams.Type = static_cast(i); gmmParams.BaseWidth64 = AllocTileSize[0][0] + 0x1; gmmParams.BaseHeight = 2 * AllocTileSize[0][1] + 0x1; //Half-Depth Height or QPitch (lod!=0), aligned to 8 required by HW gmmParams.Depth = (gmmParams.Type == RESOURCE_2D) ? 0x1 : VAlign + 1; gmmParams.ArraySize = 1; GMM_RESOURCE_INFO *ResourceInfo; ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); VerifyResourceHAlign(ResourceInfo, HAlign); VerifyResourceVAlign(ResourceInfo, VAlign); uint32_t ExpectedPitch = AllocTileSize[0][0] * 2; VerifyResourcePitch(ResourceInfo, ExpectedPitch); VerifyResourcePitchInTiles(ResourceInfo, 2); // 2 tile wide uint32_t TwoDQPitch = 0, ExpectedQPitch = 0; if(gmmParams.Type == RESOURCE_3D) { TwoDQPitch = GMM_ULT_ALIGN(gmmParams.BaseHeight, VAlign); ExpectedQPitch = gmmParams.Depth * GMM_ULT_ALIGN(TwoDQPitch / 2, VAlign); //Depth slices arranged as 2D-arrayed slices. } else { //HiZ for 3D not supported. Driver still allocates like IVB/HSW. (should Qpitch or only overall buffer height be Valigned ?) VerifyResourceSize(ResourceInfo, ((gmmParams.Type == RESOURCE_3D) ? ExpectedPitch * GMM_ULT_ALIGN(ExpectedQPitch, AllocTileSize[0][1]) : 2 * 2 * GMM_KBYTE(4))); } pGmmULTClientContext->DestroyResInfoObject(ResourceInfo); } //Mip-mapped case: } /// @brief ULT for MSAA Resource TEST_F(CTestResource, TestMSAA) { enum MSAA_Samples { MSAA_None, MSAA_2x, MSAA_4x, MSAA_8x, MSAA_16x }; const uint32_t MCSTileSize[1][2] = {128, 32}; //MCS is TileY //Gen8:No mip-map for MSAA (MSS and MCS), No 16x //No MSAA for YUV/compressed formats //Interleaved MSS (IMS) for Depth/Stencil. Arrayed MSS (CMS) for Color RT //QPitch exists for arrayed MSS - gives distance between slices //MSS (Arrayed): px_wL, px_hL = pixel width/height of single sample at Lod L // MSS width = px_wL, MSS height = NumSamples*px_hL //MSS (Interleaved): px_wL, px_hL = pixel width/height of single sample at Lod L // Samples MSS width MSS Height // 2x 4*ceil(px_wL/2) px_hL // 4x 4*ceil(px_wL/2) 4*ceil(px_hL/2) // 8x 8*ceil(px_wL/2) 4*ceil(px_hL/2) // 16x 8*ceil(px_wL/2) 8*ceil(px_hL/2) //MCS (bpp): 2x/4x - bpp_8, 8x - bpp_32, 16x - bpp_64 const uint32_t TestDimensions[3][2] = { {0, 0}, //1x1x1 {1, 0}, //2 Tilesx1 {1, 1}, //2 Tilesx 2 }; uint32_t TestArraySize[2] = {1, 7}; uint32_t HAlign, VAlign, TileDimX, TileDimY, MCSHAlign, MCSVAlign, TileSize; uint32_t ExpectedMCSBpp; std::vector> List; //TEST_TILE_TYPE, TEST_BPP, TEST_RESOURCE_TYPE, Depth or RT, TestDimension index, TestArraySize index auto Size = BuildInputIterator(List, 3, 2, false); // Size of arrays TestDimensions, TestArraySize for(auto element : List) { GMM_RESCREATE_PARAMS gmmParams = {}; gmmParams.Flags.Info = {0}; TEST_TILE_TYPE Tiling = (TEST_TILE_TYPE)std::get<0>(element); TEST_BPP Bpp = (TEST_BPP)std::get<1>(element); TEST_RESOURCE_TYPE ResType = (TEST_RESOURCE_TYPE)std::get<2>(element); bool IsRT = std::get<3>(element); // True for RT, False for Depth int TestDimIdx = std::get<4>(element); //index into TestDimensions array int ArrayIdx = std::get<5>(element); //index into TestArraySize TileSize = GMM_KBYTE(4); //Discard un-supported Tiling/Res_type/bpp for this test if(ResType != TEST_RESOURCE_2D || Tiling > TEST_TILEY //No 1D/3D/Cube. Supported 2D mip-maps/array || (!IsRT && (Tiling == TEST_TILEX || !(Bpp == TEST_BPP_16 || Bpp == TEST_BPP_32)))) //depth supported on 16bit, 32bit formats only continue; SetTileFlag(gmmParams, Tiling); SetResType(gmmParams, ResType); SetResGpuFlags(gmmParams, IsRT); SetResArraySize(gmmParams, TestArraySize[ArrayIdx]); gmmParams.NoGfxMemory = 1; gmmParams.Format = SetResourceFormat(Bpp); for(uint32_t k = MSAA_2x; k < MSAA_16x; k++) //No 16x MSAA on Gen8 { GetAlignmentAndTileDimensionsForMSAA(Bpp, IsRT, Tiling, (TEST_MSAA)k, TileDimX, TileDimY, HAlign, VAlign, ExpectedMCSBpp, MCSHAlign, MCSVAlign); gmmParams.BaseWidth64 = TestDimensions[TestDimIdx][0] * TileDimX + 0x1; gmmParams.BaseHeight = TestDimensions[TestDimIdx][1] * TileDimY + 0x1; gmmParams.Depth = 0x1; //2D Res_type with Depth > 1 doesn't fail, although Tex_cacl doesn't use it gmmParams.MSAA.NumSamples = static_cast(pow((double)2, k)); gmmParams.Flags.Gpu.MCS = 0; gmmParams.ArraySize = 1; //MSS surface GMM_RESOURCE_INFO *MSSResourceInfo; MSSResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); if(MSSResourceInfo) { VerifyResourceHAlign(MSSResourceInfo, HAlign); VerifyResourceVAlign(MSSResourceInfo, VAlign); if(IsRT) //Arrayed MSS { uint32_t ExpectedPitch = 0, ExpectedQPitch = 0; ExpectedPitch = GMM_ULT_ALIGN(GMM_ULT_ALIGN(gmmParams.BaseWidth64, HAlign) * (uint32_t)pow(2.0, Bpp), TileDimX); // Aligned width * bpp, aligned to TileWidth VerifyResourcePitch(MSSResourceInfo, ExpectedPitch); if(Tiling != TEST_LINEAR) VerifyResourcePitchInTiles(MSSResourceInfo, ExpectedPitch / TileDimX); //if (gmmParams.ArraySize > 1) - Arrayed MSS has QPitch { ExpectedQPitch = GMM_ULT_ALIGN(gmmParams.BaseHeight, VAlign); VerifyResourceQPitch(MSSResourceInfo, ExpectedQPitch); } uint32_t ExpectedHeight = GMM_ULT_ALIGN(ExpectedQPitch * gmmParams.MSAA.NumSamples * gmmParams.ArraySize, TileDimY); //Align Height =ExpectedPitch * NumSamples * ExpectedQPitch, to Tile-Height VerifyResourceSize(MSSResourceInfo, GMM_ULT_ALIGN(ExpectedPitch * ExpectedHeight, TileSize)); } else // Interleaved MSS { uint32_t WidthMultiplier, HeightMultiplier; GetInterleaveMSSPattern((TEST_MSAA)k, WidthMultiplier, HeightMultiplier, IsRT, Bpp); gmmParams.BaseWidth64 = WidthMultiplier > 1 ? GMM_ULT_ALIGN(gmmParams.BaseWidth64, 2) : gmmParams.BaseWidth64; gmmParams.BaseHeight = HeightMultiplier > 1 ? GMM_ULT_ALIGN(gmmParams.BaseHeight, 2) : gmmParams.BaseHeight; uint32_t ExpectedPitch = GMM_ULT_ALIGN(GMM_ULT_ALIGN(gmmParams.BaseWidth64 * WidthMultiplier, HAlign) * (uint32_t)pow(2.0, Bpp), TileDimX); //AlignedWidth*bpp, then align to Tile VerifyResourcePitch(MSSResourceInfo, ExpectedPitch); if(Tiling != TEST_LINEAR) { VerifyResourcePitchInTiles(MSSResourceInfo, ExpectedPitch / TileDimX); // 1 tileY wide } uint32_t ExpectedQPitch = GMM_ULT_ALIGN(gmmParams.BaseHeight * HeightMultiplier, VAlign); if(gmmParams.ArraySize > 1) { // it needs to be in VALign multiple VerifyResourceQPitch(MSSResourceInfo, ExpectedQPitch); } uint32_t ExpectedHeight = GMM_ULT_ALIGN(ExpectedQPitch * gmmParams.ArraySize, TileDimY); //Align Height = ExpectedQPitch*ArraySize, to Tile-Height VerifyResourceSize(MSSResourceInfo, GMM_ULT_ALIGN(ExpectedPitch * ExpectedHeight, TileSize)); //ExpectedPitch *ExpectedHeight } } //No MCS surface if MSS creation failed if(MSSResourceInfo) { gmmParams.Flags.Gpu.MCS = 1; GMM_RESOURCE_INFO *MCSResourceInfo; MCSResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); VerifyResourceHAlign(MCSResourceInfo, MCSHAlign); // MCS alignment same as basic RT alignment VerifyResourceVAlign(MCSResourceInfo, MCSVAlign); uint32_t ExpectedPitch = GMM_ULT_ALIGN(GMM_ULT_ALIGN(gmmParams.BaseWidth64, MCSHAlign) * ExpectedMCSBpp, MCSTileSize[0][0]); //AlignedWidth*bpp, then tile-alignment VerifyResourcePitch(MCSResourceInfo, ExpectedPitch); VerifyResourcePitchInTiles(MCSResourceInfo, ExpectedPitch / MCSTileSize[0][0]); uint32_t ExpectedQPitch = gmmParams.BaseHeight; if(gmmParams.ArraySize > 1) { ExpectedQPitch = GMM_ULT_ALIGN(gmmParams.BaseHeight, MCSVAlign); //QPitch only for array VerifyResourceQPitch(MCSResourceInfo, ExpectedQPitch); } uint32_t ExpectedHeight = GMM_ULT_ALIGN(ExpectedQPitch * gmmParams.ArraySize, MCSTileSize[0][1]); VerifyResourceSize(MCSResourceInfo, GMM_ULT_ALIGN(ExpectedPitch * ExpectedHeight, TileSize)); pGmmULTClientContext->DestroyResInfoObject(MCSResourceInfo); } //MCS pGmmULTClientContext->DestroyResInfoObject(MSSResourceInfo); } //NumSamples = k } //Iterate through all input tuples } /// @brief ULT for Plannar 2D Resource - RGBP TEST_F(CTestResource, TestPlanar2D_RGBP) { /* Test planar surfaces where all planes are full-sized */ // YYYYYYYY // YYYYYYYY // YYYYYYYY // YYYYYYYY // UUUUUUUU // UUUUUUUU // UUUUUUUU // UUUUUUUU // VVVVVVVV // VVVVVVVV // VVVVVVVV // VVVVVVVV const TEST_TILE_TYPE TileTypes[] = {TEST_LINEAR, TEST_TILEX, TEST_TILEY}; const uint32_t PlaneRowAlignment = 16; const uint32_t TileSize[3][2] = {{1, 1}, //Linear {512, 8}, // TileX {128, 32}}; // TileY for(uint32_t TileIndex = 0; TileIndex < sizeof(TileTypes) / sizeof(TileTypes[0]); TileIndex++) { TEST_TILE_TYPE Tile = TileTypes[TileIndex]; GMM_RESCREATE_PARAMS gmmParams = {}; gmmParams.Type = RESOURCE_2D; gmmParams.NoGfxMemory = 1; gmmParams.Flags.Gpu.Texture = 1; gmmParams.BaseWidth64 = 0x101; gmmParams.BaseHeight = 0x101; gmmParams.Depth = 0x1; SetTileFlag(gmmParams, static_cast(Tile)); gmmParams.Format = GMM_FORMAT_RGBP; GMM_RESOURCE_INFO *ResourceInfo; ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); uint32_t Pitch, Height; if(Tile != TEST_LINEAR) { Pitch = GMM_ULT_ALIGN(gmmParams.BaseWidth64, TileSize[TileIndex][0]); //Since Tile alignment factor is greater than GMM_IMCx_PLANE_ROW_ALIGNMENT=16 Height = GMM_ULT_ALIGN(gmmParams.BaseHeight, PlaneRowAlignment); Height = GMM_ULT_ALIGN(Height, TileSize[TileIndex][1]) * 3 /*Y, U, V*/; } else { Pitch = GMM_ULT_ALIGN(gmmParams.BaseWidth64, GMM_BYTES(64)); Height = gmmParams.BaseHeight * 3 /*Y, U, V*/; } uint32_t Size = GMM_ULT_ALIGN(Pitch * Height, GMM_KBYTE(4)); VerifyResourcePitch(ResourceInfo, Pitch); if(Tile != TEST_LINEAR) { VerifyResourcePitchInTiles(ResourceInfo, Pitch / TileSize[TileIndex][0]); } VerifyResourceSize(ResourceInfo, Size); VerifyResourceHAlign(ResourceInfo, 0); // Same as any other 2D surface -- tested elsewhere VerifyResourceVAlign(ResourceInfo, 0); // Same as any other 2D surface -- tested elsewhere VerifyResourceQPitch(ResourceInfo, 0); // N/A for planar // Y plane should be at 0,0 EXPECT_EQ(0, ResourceInfo->GetPlanarXOffset(GMM_PLANE_Y)); EXPECT_EQ(0, ResourceInfo->GetPlanarYOffset(GMM_PLANE_Y)); // U plane should be at end of Y plane EXPECT_EQ(0, ResourceInfo->GetPlanarXOffset(GMM_PLANE_U)); EXPECT_EQ(Height / 3, ResourceInfo->GetPlanarYOffset(GMM_PLANE_U)); // V plane should be at end of U plane EXPECT_EQ(0, ResourceInfo->GetPlanarXOffset(GMM_PLANE_V)); EXPECT_EQ(2 * (Height / 3), ResourceInfo->GetPlanarYOffset(GMM_PLANE_V)); pGmmULTClientContext->DestroyResInfoObject(ResourceInfo); } } /// @brief ULT for Plannar 2D Resource Unaligned - RGBP TEST_F(CTestResource, TestPlanar2D_RGBP_Unaligned) { /* Test planar surfaces where all planes are full-sized */ // YYYYYYYY // YYYYYYYY // YYYYYYYY // YYYYYYYY // UUUUUUUU // UUUUUUUU // UUUUUUUU // UUUUUUUU // VVVVVVVV // VVVVVVVV // VVVVVVVV // VVVVVVVV const TEST_TILE_TYPE TileTypes[] = {TEST_LINEAR, TEST_TILEX, TEST_TILEY}; const uint32_t PlaneRowAlignment = 16; const uint32_t TileSize[3][2] = {{1, 1}, //Linear {512, 8}, // TileX {128, 32}}; // TileY for(uint32_t TileIndex = 0; TileIndex < sizeof(TileTypes) / sizeof(TileTypes[0]); TileIndex++) { TEST_TILE_TYPE Tile = TileTypes[TileIndex]; GMM_RESCREATE_PARAMS gmmParams = {}; gmmParams.Type = RESOURCE_2D; gmmParams.NoGfxMemory = 1; gmmParams.Flags.Gpu.Texture = 1; gmmParams.BaseWidth64 = 480; gmmParams.BaseHeight = 300; gmmParams.Depth = 0x1; SetTileFlag(gmmParams, static_cast(Tile)); gmmParams.Format = GMM_FORMAT_RGBP; GMM_RESOURCE_INFO *ResourceInfo; ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); uint32_t Pitch, Height; if(Tile != TEST_LINEAR) { Pitch = GMM_ULT_ALIGN(gmmParams.BaseWidth64, TileSize[TileIndex][0]); //Since Tile alignment factor is greater than GMM_IMCx_PLANE_ROW_ALIGNMENT=16 Height = GMM_ULT_ALIGN(gmmParams.BaseHeight, PlaneRowAlignment); Height = GMM_ULT_ALIGN(Height, TileSize[TileIndex][1]) * 3 /*Y, U, V*/; } else { Pitch = GMM_ULT_ALIGN(gmmParams.BaseWidth64, GMM_BYTES(64)); Height = gmmParams.BaseHeight * 3 /*Y, U, V*/; } uint32_t Size = GMM_ULT_ALIGN(Pitch * Height, GMM_KBYTE(4)); VerifyResourcePitch(ResourceInfo, Pitch); if(Tile != TEST_LINEAR) { VerifyResourcePitchInTiles(ResourceInfo, Pitch / TileSize[TileIndex][0]); } VerifyResourceSize(ResourceInfo, Size); VerifyResourceHAlign(ResourceInfo, 0); // Same as any other 2D surface -- tested elsewhere VerifyResourceVAlign(ResourceInfo, 0); // Same as any other 2D surface -- tested elsewhere VerifyResourceQPitch(ResourceInfo, 0); // N/A for planar // Y plane should be at 0,0 EXPECT_EQ(0, ResourceInfo->GetPlanarXOffset(GMM_PLANE_Y)); EXPECT_EQ(0, ResourceInfo->GetPlanarYOffset(GMM_PLANE_Y)); // U plane should be at end of Y plane EXPECT_EQ(0, ResourceInfo->GetPlanarXOffset(GMM_PLANE_U)); EXPECT_EQ(Height / 3, ResourceInfo->GetPlanarYOffset(GMM_PLANE_U)); // V plane should be at end of U plane EXPECT_EQ(0, ResourceInfo->GetPlanarXOffset(GMM_PLANE_V)); EXPECT_EQ(2 * (Height / 3), ResourceInfo->GetPlanarYOffset(GMM_PLANE_V)); //Resource Offset //Y PLANE GMM_REQ_OFFSET_INFO OffsetInfo = {}; OffsetInfo.ReqRender = 1; OffsetInfo.MipLevel = 0; //Mip 0 OffsetInfo.Plane = GMM_PLANE_Y; ResourceInfo->GetOffset(OffsetInfo); EXPECT_EQ(0, OffsetInfo.Render.Offset64); //U PLANE OffsetInfo.ReqRender = 1; OffsetInfo.MipLevel = 0; //Mip 0 OffsetInfo.Plane = GMM_PLANE_U; ResourceInfo->GetOffset(OffsetInfo); EXPECT_EQ(Pitch * (Height / 3), OffsetInfo.Render.Offset64); // V PLANE OffsetInfo.ReqRender = 1; OffsetInfo.MipLevel = 0; //Mip 0 OffsetInfo.Plane = GMM_PLANE_V; ResourceInfo->GetOffset(OffsetInfo); EXPECT_EQ(2 * Pitch * (Height / 3), OffsetInfo.Render.Offset64); pGmmULTClientContext->DestroyResInfoObject(ResourceInfo); } } /// @brief ULT for Plannar 2D Resource - MFX_JPEG_YUV422V TEST_F(CTestResource, TestPlanar2D_MFX_JPEG_YUV422V) { /* Test planar surfaces where both U and V are half the size of Y */ // YYYYYYYY // YYYYYYYY // YYYYYYYY // YYYYYYYY // UUUUUUUU // UUUUUUUU // VVVVVVVV // VVVVVVVV const TEST_TILE_TYPE TileTypes[] = {TEST_LINEAR, TEST_TILEX, TEST_TILEY}; const uint32_t PlaneRowAlignment = 16; const uint32_t TileSize[3][2] = {{1, 1}, //Linear {512, 8}, // TileX {128, 32}}; // TileY for(uint32_t TileIndex = 0; TileIndex < sizeof(TileTypes) / sizeof(TileTypes[0]); TileIndex++) { TEST_TILE_TYPE Tile = TileTypes[TileIndex]; GMM_RESCREATE_PARAMS gmmParams = {}; gmmParams.Type = RESOURCE_2D; gmmParams.NoGfxMemory = 1; gmmParams.Flags.Gpu.Texture = 1; gmmParams.BaseWidth64 = 0x101; gmmParams.BaseHeight = 0x101; gmmParams.Depth = 0x1; SetTileFlag(gmmParams, static_cast(Tile)); gmmParams.Flags.Info.Linear = 1; // GmmLib needs linear to be set as fallback for all planar surfaces gmmParams.Format = GMM_FORMAT_MFX_JPEG_YUV422V; GMM_RESOURCE_INFO *ResourceInfo; ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); uint32_t Pitch, Height; uint32_t YHeight, VHeight; if(Tile != TEST_LINEAR) { Pitch = GMM_ULT_ALIGN(gmmParams.BaseWidth64, TileSize[TileIndex][0]); YHeight = GMM_ULT_ALIGN(gmmParams.BaseHeight, PlaneRowAlignment); YHeight = GMM_ULT_ALIGN(YHeight, TileSize[TileIndex][1]); VHeight = GMM_ULT_ALIGN(GMM_ULT_ALIGN(gmmParams.BaseHeight, 2) / 2, PlaneRowAlignment); VHeight = GMM_ULT_ALIGN(VHeight, TileSize[TileIndex][1]); } else { Pitch = GMM_ULT_ALIGN(gmmParams.BaseWidth64, GMM_BYTES(64)); YHeight = GMM_ULT_ALIGN(gmmParams.BaseHeight, PlaneRowAlignment); VHeight = GMM_ULT_ALIGN(GMM_ULT_ALIGN(gmmParams.BaseHeight, 2) / 2, PlaneRowAlignment); } Height = YHeight + 2 * VHeight; uint32_t Size = GMM_ULT_ALIGN(Pitch * Height, GMM_KBYTE(4)); VerifyResourcePitch(ResourceInfo, Pitch); if(Tile != TEST_LINEAR) { VerifyResourcePitchInTiles(ResourceInfo, Pitch / TileSize[TileIndex][0]); } VerifyResourceSize(ResourceInfo, Size); VerifyResourceHAlign(ResourceInfo, 0); // Same as any other 2D surface -- tested elsewhere VerifyResourceVAlign(ResourceInfo, 0); // Same as any other 2D surface -- tested elsewhere VerifyResourceQPitch(ResourceInfo, 0); // N/A for planar // Y plane should be at 0,0 EXPECT_EQ(0, ResourceInfo->GetPlanarXOffset(GMM_PLANE_Y)); EXPECT_EQ(0, ResourceInfo->GetPlanarYOffset(GMM_PLANE_Y)); // U plane should be at end of Y plane EXPECT_EQ(0, ResourceInfo->GetPlanarXOffset(GMM_PLANE_U)); EXPECT_EQ(YHeight, ResourceInfo->GetPlanarYOffset(GMM_PLANE_U)); // V plane should be at end of U plane EXPECT_EQ(0, ResourceInfo->GetPlanarXOffset(GMM_PLANE_V)); EXPECT_EQ(YHeight + VHeight, ResourceInfo->GetPlanarYOffset(GMM_PLANE_V)); pGmmULTClientContext->DestroyResInfoObject(ResourceInfo); } } /// @brief ULT for Plannar 2D Resource - MFX_JPEG_YUV411R TEST_F(CTestResource, TestPlanar2D_MFX_JPEG_YUV411R) { /* Test planar surfaces where both U and V are quarter the size of Y */ //YYYYYYYY //YYYYYYYY //YYYYYYYY //YYYYYYYY //UUUUUUUU //VVVVVVVV const TEST_TILE_TYPE TileTypes[] = {TEST_LINEAR, TEST_TILEX, TEST_TILEY}; const uint32_t PlaneRowAlignment = 16; const uint32_t TileSize[3][2] = {{1, 1}, //Linear {512, 8}, // TileX {128, 32}}; // TileY for(uint32_t TileIndex = 0; TileIndex < sizeof(TileTypes) / sizeof(TileTypes[0]); TileIndex++) { TEST_TILE_TYPE Tile = TileTypes[TileIndex]; GMM_RESCREATE_PARAMS gmmParams = {}; gmmParams.Type = RESOURCE_2D; gmmParams.NoGfxMemory = 1; gmmParams.Flags.Gpu.Texture = 1; gmmParams.BaseWidth64 = 0x101; gmmParams.BaseHeight = 0x101; gmmParams.Depth = 0x1; SetTileFlag(gmmParams, static_cast(Tile)); gmmParams.Format = GMM_FORMAT_MFX_JPEG_YUV411R_TYPE; GMM_RESOURCE_INFO *ResourceInfo; ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); uint32_t Pitch, Height; uint32_t YHeight, VHeight; if(Tile != TEST_LINEAR) { Pitch = GMM_ULT_ALIGN(gmmParams.BaseWidth64, TileSize[TileIndex][0]); YHeight = GMM_ULT_ALIGN(gmmParams.BaseHeight, PlaneRowAlignment); YHeight = GMM_ULT_ALIGN(YHeight, TileSize[TileIndex][1]); VHeight = GMM_ULT_ALIGN(GMM_ULT_ALIGN(gmmParams.BaseHeight, 4) / 4, PlaneRowAlignment); VHeight = GMM_ULT_ALIGN(VHeight, TileSize[TileIndex][1]); } else { Pitch = GMM_ULT_ALIGN(gmmParams.BaseWidth64, GMM_BYTES(64)); YHeight = GMM_ULT_ALIGN(gmmParams.BaseHeight, PlaneRowAlignment); VHeight = GMM_ULT_ALIGN(GMM_ULT_ALIGN(gmmParams.BaseHeight, 4) / 4, PlaneRowAlignment); } Height = YHeight + 2 * VHeight; uint32_t Size = GMM_ULT_ALIGN(Pitch * Height, GMM_KBYTE(4)); VerifyResourcePitch(ResourceInfo, Pitch); if(Tile != TEST_LINEAR) { VerifyResourcePitchInTiles(ResourceInfo, Pitch / TileSize[TileIndex][0]); } VerifyResourceSize(ResourceInfo, Size); VerifyResourceHAlign(ResourceInfo, 0); // Same as any other 2D surface -- tested elsewhere VerifyResourceVAlign(ResourceInfo, 0); // Same as any other 2D surface -- tested elsewhere VerifyResourceQPitch(ResourceInfo, 0); // N/A for planar // Y plane should be at 0,0 EXPECT_EQ(0, ResourceInfo->GetPlanarXOffset(GMM_PLANE_Y)); EXPECT_EQ(0, ResourceInfo->GetPlanarYOffset(GMM_PLANE_Y)); // U plane should be at end of Y plane EXPECT_EQ(0, ResourceInfo->GetPlanarXOffset(GMM_PLANE_U)); EXPECT_EQ(YHeight, ResourceInfo->GetPlanarYOffset(GMM_PLANE_U)); // V plane should be at end of U plane EXPECT_EQ(0, ResourceInfo->GetPlanarXOffset(GMM_PLANE_V)); EXPECT_EQ(YHeight + VHeight, ResourceInfo->GetPlanarYOffset(GMM_PLANE_V)); pGmmULTClientContext->DestroyResInfoObject(ResourceInfo); } } /// @brief ULT for Plannar 2D Resource - NV12 TEST_F(CTestResource, TestPlanar2D_NV12) { /* Test planar surface with hybrid UV planes where UV plane is half the size of Y and U/V data is packed together */ // YYYYYYYY // YYYYYYYY // YYYYYYYY // YYYYYYYY // [UV-Packing] const TEST_TILE_TYPE TileTypes[] = {TEST_LINEAR, TEST_TILEX, TEST_TILEY}; const uint32_t TileSize[3][2] = {{1, 1}, //Linear {512, 8}, // TileX {128, 32}}; // TileY for(uint32_t TileIndex = 0; TileIndex < sizeof(TileTypes) / sizeof(TileTypes[0]); TileIndex++) { TEST_TILE_TYPE Tile = TileTypes[TileIndex]; GMM_RESCREATE_PARAMS gmmParams = {}; gmmParams.Type = RESOURCE_2D; gmmParams.NoGfxMemory = 1; gmmParams.Flags.Gpu.Texture = 1; gmmParams.BaseWidth64 = 0x100; gmmParams.BaseHeight = 0x100; gmmParams.Depth = 0x1; SetTileFlag(gmmParams, static_cast(Tile)); gmmParams.Format = GMM_FORMAT_NV12; GMM_RESOURCE_INFO *ResourceInfo; ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); uint32_t Pitch, Height; if(Tile != TEST_LINEAR) { Pitch = GMM_ULT_ALIGN(gmmParams.BaseWidth64, TileSize[TileIndex][0]); Height = GMM_ULT_ALIGN(gmmParams.BaseHeight, TileSize[TileIndex][1]) + GMM_ULT_ALIGN(gmmParams.BaseHeight / 2, TileSize[TileIndex][1]); } else { Pitch = GMM_ULT_ALIGN(gmmParams.BaseWidth64, TileSize[TileIndex][0]); Height = GMM_ULT_ALIGN(gmmParams.BaseHeight /*Y*/ + gmmParams.BaseHeight / 2 /*UV*/, TileSize[TileIndex][1]); } uint32_t Size = GMM_ULT_ALIGN(Pitch * Height, GMM_KBYTE(4)); VerifyResourcePitch(ResourceInfo, Pitch); if(Tile != TEST_LINEAR) { VerifyResourcePitchInTiles(ResourceInfo, Pitch / TileSize[TileIndex][0]); } VerifyResourceSize(ResourceInfo, Size); VerifyResourceHAlign(ResourceInfo, 0); // Same as any other 2D surface -- tested elsewhere VerifyResourceVAlign(ResourceInfo, 0); // Same as any other 2D surface -- tested elsewhere VerifyResourceQPitch(ResourceInfo, 0); // N/A for planar // Y plane should be at 0,0 EXPECT_EQ(0, ResourceInfo->GetPlanarXOffset(GMM_PLANE_Y)); EXPECT_EQ(0, ResourceInfo->GetPlanarYOffset(GMM_PLANE_Y)); // U/V plane should be at end of Y plane EXPECT_EQ(0, ResourceInfo->GetPlanarXOffset(GMM_PLANE_U)); EXPECT_EQ(0, ResourceInfo->GetPlanarXOffset(GMM_PLANE_V)); if(Tile != TEST_LINEAR) { EXPECT_EQ(GMM_ULT_ALIGN(gmmParams.BaseHeight, TileSize[TileIndex][1]), ResourceInfo->GetPlanarYOffset(GMM_PLANE_U)); EXPECT_EQ(GMM_ULT_ALIGN(gmmParams.BaseHeight, TileSize[TileIndex][1]), ResourceInfo->GetPlanarYOffset(GMM_PLANE_V)); } else { EXPECT_EQ(gmmParams.BaseHeight, ResourceInfo->GetPlanarYOffset(GMM_PLANE_U)); EXPECT_EQ(gmmParams.BaseHeight, ResourceInfo->GetPlanarYOffset(GMM_PLANE_V)); } pGmmULTClientContext->DestroyResInfoObject(ResourceInfo); } } /// @brief ULT for Planar 2D Resource - IMC4 TEST_F(CTestResource, TestPlanar2D_IMC4) { /* Test planar surface V surface is on the right of U */ // YYYYYYYY // YYYYYYYY // YYYYYYYY // YYYYYYYY // UUUUVVVV // UUUUVVVV const TEST_TILE_TYPE TileTypes[] = {TEST_LINEAR, TEST_TILEX, TEST_TILEY}; const uint32_t PlaneRowAlignment = 16; const uint32_t TileSize[3][2] = {{1, 1}, //Linear {512, 8}, // TileX {128, 32}}; // TileY for(uint32_t TileIndex = 0; TileIndex < sizeof(TileTypes) / sizeof(TileTypes[0]); TileIndex++) { TEST_TILE_TYPE Tile = TileTypes[TileIndex]; GMM_RESCREATE_PARAMS gmmParams = {}; gmmParams.Type = RESOURCE_2D; gmmParams.NoGfxMemory = 1; gmmParams.Flags.Gpu.Texture = 1; gmmParams.BaseWidth64 = 0x101; gmmParams.BaseHeight = 0x101; gmmParams.Depth = 0x1; SetTileFlag(gmmParams, static_cast(Tile)); gmmParams.Format = GMM_FORMAT_IMC4; GMM_RESOURCE_INFO *ResourceInfo; ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); uint32_t Pitch, Height; uint32_t YHeight, VHeight; if(Tile != TEST_LINEAR) { Pitch = GMM_ULT_ALIGN(gmmParams.BaseWidth64, TileSize[TileIndex][0]); if(Pitch / TileSize[TileIndex][0] % 2) { Pitch += TileSize[TileIndex][0]; } YHeight = GMM_ULT_ALIGN(gmmParams.BaseHeight, PlaneRowAlignment); VHeight = YHeight / 2; YHeight = GMM_ULT_ALIGN(YHeight, TileSize[TileIndex][1]); VHeight = GMM_ULT_ALIGN(VHeight, TileSize[TileIndex][1]); // No need of PlaneRowAlignment since last plane } else { Pitch = GMM_ULT_ALIGN(gmmParams.BaseWidth64, GMM_BYTES(64)); YHeight = GMM_ULT_ALIGN(gmmParams.BaseHeight, PlaneRowAlignment); VHeight = YHeight / 2; } Height = YHeight + VHeight; uint32_t Size = GMM_ULT_ALIGN(Pitch * Height, GMM_KBYTE(4)); VerifyResourcePitch(ResourceInfo, Pitch); if(Tile != TEST_LINEAR) { VerifyResourcePitchInTiles(ResourceInfo, Pitch / TileSize[TileIndex][0]); } VerifyResourceSize(ResourceInfo, Size); VerifyResourceHAlign(ResourceInfo, 0); // Same as any other 2D surface -- tested elsewhere VerifyResourceVAlign(ResourceInfo, 0); // Same as any other 2D surface -- tested elsewhere VerifyResourceQPitch(ResourceInfo, 0); // N/A for planar // Y plane should be at 0,0 EXPECT_EQ(0, ResourceInfo->GetPlanarXOffset(GMM_PLANE_Y)); EXPECT_EQ(0, ResourceInfo->GetPlanarYOffset(GMM_PLANE_Y)); // U plane should be at end of Y plane EXPECT_EQ(0, ResourceInfo->GetPlanarXOffset(GMM_PLANE_U)); EXPECT_EQ(Pitch / 2, ResourceInfo->GetPlanarXOffset(GMM_PLANE_V)); if(Tile != TEST_LINEAR) { EXPECT_EQ(YHeight, ResourceInfo->GetPlanarYOffset(GMM_PLANE_U)); EXPECT_EQ(YHeight, ResourceInfo->GetPlanarYOffset(GMM_PLANE_V)); } else { EXPECT_EQ(YHeight, ResourceInfo->GetPlanarYOffset(GMM_PLANE_U)); EXPECT_EQ(YHeight, ResourceInfo->GetPlanarYOffset(GMM_PLANE_V)); } pGmmULTClientContext->DestroyResInfoObject(ResourceInfo); } } /// @brief ULT for Planar 2D Resource - YV12 TEST_F(CTestResource, TestPlanar2D_YV12) { /* Test planar surface V surface follows U surface linearly */ // YYYYYYYY // YYYYYYYY // YYYYYYYY // YYYYYYYY // VVVVVV.. <-- V and U planes follow the Y plane, as linear // ..UUUUUU arrays--without respect to pitch. GMM_RESCREATE_PARAMS gmmParams = {}; gmmParams.Type = RESOURCE_2D; gmmParams.NoGfxMemory = 1; gmmParams.Flags.Gpu.Texture = 1; gmmParams.BaseWidth64 = 0x100; gmmParams.BaseHeight = 0x100; gmmParams.Depth = 0x1; gmmParams.Flags.Info.Linear = 1; // Linear only since UV plane doesn't have a pitch gmmParams.Format = GMM_FORMAT_YV12; GMM_RESOURCE_INFO *ResourceInfo; ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); uint32_t Pitch = gmmParams.BaseWidth64; uint32_t SizeOfY = Pitch * gmmParams.BaseHeight; uint32_t Height = (SizeOfY /*Y*/ + SizeOfY / 4 /*V*/ + SizeOfY / 4 /*U*/) / Pitch; uint32_t Size = GMM_ULT_ALIGN(Pitch * Height, GMM_KBYTE(4)); VerifyResourcePitch(ResourceInfo, Pitch); VerifyResourcePitchInTiles(ResourceInfo, 0); // N/A for linear VerifyResourceSize(ResourceInfo, Size); VerifyResourceHAlign(ResourceInfo, 0); // Same as any other 2D surface -- tested elsewhere VerifyResourceVAlign(ResourceInfo, 0); // Same as any other 2D surface -- tested elsewhere VerifyResourceQPitch(ResourceInfo, 0); // N/A for planar // Y plane should be at 0,0 EXPECT_EQ(0, ResourceInfo->GetPlanarXOffset(GMM_PLANE_Y)); EXPECT_EQ(0, ResourceInfo->GetPlanarYOffset(GMM_PLANE_Y)); // V plane follows Y EXPECT_EQ(0, ResourceInfo->GetPlanarXOffset(GMM_PLANE_V)); EXPECT_EQ(gmmParams.BaseHeight, ResourceInfo->GetPlanarYOffset(GMM_PLANE_V)); // U plane should be at end of V plane uint32_t UByteOffset = SizeOfY /* Y */ + SizeOfY / 4; /* Size of V = 1/4 of Y */ EXPECT_EQ(UByteOffset % Pitch, ResourceInfo->GetPlanarXOffset(GMM_PLANE_U)); EXPECT_EQ(UByteOffset / Pitch, ResourceInfo->GetPlanarYOffset(GMM_PLANE_U)); pGmmULTClientContext->DestroyResInfoObject(ResourceInfo); } /// @brief ULT for Unified aux surface TEST_F(CTestResource, TestUnifiedAuxSurface) { uint32_t TileSize[] = {128, 32}; GMM_RESCREATE_PARAMS gmmParams = {}; gmmParams.Type = RESOURCE_2D; gmmParams.NoGfxMemory = 1; gmmParams.Flags.Gpu.Texture = 1; gmmParams.Flags.Gpu.CCS = 1; gmmParams.Flags.Gpu.UnifiedAuxSurface = 1; gmmParams.BaseWidth64 = 0x100; gmmParams.BaseHeight = 0x100; gmmParams.Depth = 0x1; SetTileFlag(gmmParams, TEST_TILEY); for(uint32_t bpp = TEST_BPP_32; bpp <= TEST_BPP_128; bpp++) // 32/64/128 only { gmmParams.Format = SetResourceFormat(static_cast(bpp)); GMM_RESOURCE_INFO *ResourceInfo; ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); uint64_t Pitch = GMM_ULT_ALIGN(gmmParams.BaseWidth64 * GetBppValue(static_cast(bpp)), TileSize[0]); uint64_t Size = Pitch * GMM_ULT_ALIGN(gmmParams.BaseHeight, TileSize[1]); Size = GMM_ULT_ALIGN(Size, PAGE_SIZE); VerifyResourcePitch(ResourceInfo, Pitch); VerifyResourcePitchInTiles(ResourceInfo, Pitch / TileSize[0]); VerifyResourceSize(ResourceInfo, Size); VerifyResourceHAlign(ResourceInfo, 0); // Same as any other 2D surface -- tested elsewhere VerifyResourceVAlign(ResourceInfo, 0); // Same as any other 2D surface -- tested elsewhere VerifyResourceQPitch(ResourceInfo, 0); // N/A for non-arrayed uint32_t AuxPitch = Pitch; switch(bpp) { case TEST_BPP_32: AuxPitch /= 8; break; case TEST_BPP_64: AuxPitch /= 4; break; case TEST_BPP_128: AuxPitch /= 2; break; } uint64_t AuxSize = AuxPitch * GMM_ULT_ALIGN(gmmParams.BaseHeight, TileSize[1]); AuxSize = GMM_ULT_ALIGN(AuxSize, PAGE_SIZE); // Verify unified aux info EXPECT_EQ(AuxSize, ResourceInfo->GetSizeAuxSurface(GMM_AUX_CCS)); if(ResourceInfo->Is64KBPageSuitable()) { EXPECT_EQ(GMM_ULT_ALIGN(Size, 64 * PAGE_SIZE) + AuxSize, ResourceInfo->GetSizeSurface()); } else { EXPECT_EQ(Size + AuxSize, ResourceInfo->GetSizeSurface()); } EXPECT_EQ(256, ResourceInfo->GetAuxHAlign()); EXPECT_EQ(128, ResourceInfo->GetAuxVAlign()); EXPECT_EQ(0, ResourceInfo->GetAuxQPitch()); EXPECT_EQ(AuxPitch, ResourceInfo->GetUnifiedAuxPitch()); EXPECT_EQ(AuxPitch / TileSize[0], ResourceInfo->GetRenderAuxPitchTiles()); EXPECT_EQ(Size, ResourceInfo->GetUnifiedAuxSurfaceOffset(GMM_AUX_CCS)); pGmmULTClientContext->DestroyResInfoObject(ResourceInfo); } } /// @brief ULT for Compressed Resource TEST_F(CTestResource, TestCompressedSurface) { uint32_t TileSize[] = {128, 32}; uint32_t CompBlock[] = {4, 4}; GMM_RESCREATE_PARAMS gmmParams = {}; gmmParams.Type = RESOURCE_2D; gmmParams.NoGfxMemory = 1; gmmParams.Flags.Gpu.Texture = 1; gmmParams.BaseWidth64 = 0x100; gmmParams.BaseHeight = 0x100; gmmParams.Depth = 0x1; SetTileFlag(gmmParams, TEST_TILEY); //TODO: Programatically test all compression formats. gmmParams.Format = GMM_FORMAT_BC1_UNORM; // BC1 is 4x4 compression block, 64bpe GMM_RESOURCE_INFO *ResourceInfo; ResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); uint64_t Pitch = GMM_ULT_ALIGN(gmmParams.BaseWidth64 / CompBlock[0] * GetBppValue(TEST_BPP_64), TileSize[0]); uint64_t Size = Pitch * GMM_ULT_ALIGN(gmmParams.BaseHeight / CompBlock[1], TileSize[1]); Size = GMM_ULT_ALIGN(Size, PAGE_SIZE); VerifyResourcePitch(ResourceInfo, Pitch); VerifyResourcePitchInTiles(ResourceInfo, Pitch / TileSize[0]); VerifyResourceSize(ResourceInfo, Size); VerifyResourceHAlign(ResourceInfo, 0); // Same as any other 2D surface -- tested elsewhere VerifyResourceVAlign(ResourceInfo, 0); // Same as any other 2D surface -- tested elsewhere VerifyResourceQPitch(ResourceInfo, 0); // N/A for non-arrayed pGmmULTClientContext->DestroyResInfoObject(ResourceInfo); } gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/ULT/GmmResourceULT.h000066400000000000000000000562431466655022700235170ustar00rootroot00000000000000/*============================================================================== Copyright(c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ============================================================================*/ #pragma once #include "GmmCommonULT.h" //=========================================================================== // typedef: // TEST_RESOURCE_TYPE_ENUM // // Description: // Decribes Resource types to test // when editing/adding existing/new enum, make sure to update corresponding // string array CTestResource::TestResourceTypeStr[]. //---------------------------------------------------------------------------- typedef enum TEST_RESOURCE_TYPE_ENUM { TEST_RESOURCE_1D, TEST_RESOURCE_2D, TEST_RESOURCE_3D, TEST_RESOURCE_CUBE, TEST_RESOURCE_BUFFER, TEST_RESOURCE_MAX }TEST_RESOURCE_TYPE; //=========================================================================== // typedef: // TEST_RESOURCE_TYPE_ENUM // // Description: // Decribes Resource Tile Types to test . // when editing/adding existing/new enum, make sure to update corresponding // string array CTestResource::TestTileTypeStr[]. //---------------------------------------------------------------------------- typedef enum TEST_TILE_TYPE_ENUM { TEST_LINEAR, TEST_TILEX, TEST_TILEY, TEST_TILEYS, TEST_TILEYF, TEST_TILEY_MAX = TEST_TILEYF, TEST_TILE4, TEST_TILE64, TEST_TILE_MAX }TEST_TILE_TYPE; //=========================================================================== // typedef: // TEST_BPP_ENUM // // Description: // Decribes BPP to test - 8, 16, 32, 64, 128 (Ignore 24/96 until need arises) // when editing/adding existing/new enum, make sure to update corresponding // string array CTestResource::TestBppStr[]. //---------------------------------------------------------------------------- typedef enum TEST_BPP_ENUM { TEST_BPP_8, TEST_BPP_16, TEST_BPP_32, TEST_BPP_64, TEST_BPP_128, TEST_BPP_MAX }TEST_BPP; typedef enum TEST_MSAA_Samples { MSAA_None, MSAA_2x, MSAA_4x, MSAA_8x, MSAA_16x, TEST_MSAA_MAX = MSAA_16x //Should be equal to last MSAA type } TEST_MSAA; //=========================================================================== // GmmLib ULT macros for size alignment. Compitable with 64-bit numbers. //--------------------------------------------------------------------------- #define GMM_ULT_ALIGN(x, a) (((x) + ((a) - 1)) - (((x) + ((a) - 1)) & ((a) - 1))) // Alt implementation with bitwise not (~) has issue with uint32 align used with 64-bit value, since ~'ed value will remain 32-bit. #define GMM_ULT_ALIGN_FLOOR(x, a) ((x) - ((x) & ((a) - 1))) #define GMM_ULT_MAX(a, b) ((a) > (b)) ? (a) : (b) #define GMM_ULT_MIN(a,b) (((a) < (b)) ? (a) : (b)) #define GMM_ULT_ALIGN_NP2(x, a) (((a) > 0) ? ((x) + (((a) - 1) - (((x) + ((a) - 1)) % (a)))) : (x)) //Next power of 2 #define GMM_ULT_MAX_MIPMAP 15 #define GMM_ULT_MAX_MIPTAIL_SLOTS 15 ////////////////////////////////////////////////////////////////////////// // typdef: // TEST_MIPTAIL_SLOT_OFFSET_REC // // Description: // Structure to hold the offset of the mip resources for unit level testing ////////////////////////////////////////////////////////////////////////// typedef struct TEST_MIPTAIL_SLOT_OFFSET_REC { uint32_t X; uint32_t Y; uint32_t Z; }TEST_MIPTAIL_SLOT_OFFSET; ///////////////////////////////////////////////////////////////////////// /// Fixture class for Resource. - This is Resource Test Case to test /// all generic resource types, tile types, bpp and special allocations. /// Contains Base implementation and inherits CommonULT class ///////////////////////////////////////////////////////////////////////// class CTestResource : public CommonULT { protected: ///////////////////////////////////////////////////////////////////////////////////// /// Returns GMM format for given test BPP input. /// /// @param[in] Bpp: test Bpp value /// /// @return ::GMM_RESOURCE_FORMAT ///////////////////////////////////////////////////////////////////////////////////// GMM_RESOURCE_FORMAT SetResourceFormat(TEST_BPP Bpp) { switch (Bpp) { case TEST_BPP_8: return GMM_FORMAT_GENERIC_8BIT; case TEST_BPP_16: return GMM_FORMAT_GENERIC_16BIT; case TEST_BPP_32: return GMM_FORMAT_GENERIC_32BIT; case TEST_BPP_64: return GMM_FORMAT_GENERIC_64BIT; case TEST_BPP_128: return GMM_FORMAT_GENERIC_128BIT; default: break; } return GMM_FORMAT_INVALID; } ///////////////////////////////////////////////////////////////////////////////////// /// Returns Bpp (bytes per pixel) for a given bpp (bits per pixel) enum. /// /// @param[in] bpp: test bpp value /// /// @return Bytes per pixel ///////////////////////////////////////////////////////////////////////////////////// uint32_t GetBppValue(TEST_BPP bpp) { uint32_t Bpp = 0; switch (bpp) { case TEST_BPP_8: Bpp = 8; break; case TEST_BPP_16: Bpp = 16; break; case TEST_BPP_32: Bpp = 32; break; case TEST_BPP_64: Bpp = 64; break; case TEST_BPP_128: Bpp = 128; break; default: break; } return Bpp >> 3; } ///////////////////////////////////////////////////////////////////////////////////// /// Set the tile flag in Gmm ResCreate Params /// /// @param[in] Parms: Gmm Rescreate params /// @param[in] Tile: Tile Type /// ///////////////////////////////////////////////////////////////////////////////////// void SetTileFlag(GMM_RESCREATE_PARAMS &Params, TEST_TILE_TYPE Tile) { switch (Tile) { case TEST_LINEAR: Params.Flags.Info.Linear = 1; break; case TEST_TILEX: Params.Flags.Info.TiledX = 1; break; case TEST_TILEY: if (pGfxAdapterInfo->SkuTable.FtrTileY) { Params.Flags.Info.TiledY = 1; } else { Params.Flags.Info.Tile4 = 1; } break; case TEST_TILEYF: Params.Flags.Info.TiledY = 1; Params.Flags.Info.TiledYf = 1; break; case TEST_TILEYS: if (pGfxAdapterInfo->SkuTable.FtrTileY) { Params.Flags.Info.TiledY = 1; Params.Flags.Info.TiledYs = 1; } else { Params.Flags.Info.Tile64 = 1; } break; default: break; } } ///////////////////////////////////////////////////////////////////////////////////// /// Set the tile flag in Gmm Custom ResCreate Params /// /// @param[in] Parms: Gmm Rescreate params /// @param[in] Tile: Tile Type /// ///////////////////////////////////////////////////////////////////////////////////// void SetTileFlag_Custom(GMM_RESCREATE_CUSTOM_PARAMS& Params, TEST_TILE_TYPE Tile) { switch (Tile) { case TEST_LINEAR: Params.Flags.Info.Linear = 1; break; case TEST_TILEX: Params.Flags.Info.TiledX = 1; break; case TEST_TILEY: if (pGfxAdapterInfo->SkuTable.FtrTileY) { Params.Flags.Info.TiledY = 1; } else { Params.Flags.Info.Tile4 = 1; } break; case TEST_TILEYF: Params.Flags.Info.TiledY = 1; Params.Flags.Info.TiledYf = 1; break; case TEST_TILEYS: if (pGfxAdapterInfo->SkuTable.FtrTileY) { Params.Flags.Info.TiledY = 1; Params.Flags.Info.TiledYs = 1; } else { Params.Flags.Info.Tile64 = 1; } break; default: break; } } ///////////////////////////////////////////////////////////////////////////////////// /// Sets Resource Type in GmmParams /// /// @param[in] Params: GmmParams /// @param[in] ResType: Resource type /// ///////////////////////////////////////////////////////////////////////////////////// void SetResType(GMM_RESCREATE_PARAMS& Params, TEST_RESOURCE_TYPE ResType) { Params.Type = static_cast((ResType == TEST_RESOURCE_BUFFER) ? ResType + 2 : ResType + 1); } ///////////////////////////////////////////////////////////////////////////////////// /// Sets RenderTarget or Depth Gpu Flags in GmmParams /// /// @param[in] Params: GmmParams /// @param[in] IsRT: true for RT, false for Depth /// ///////////////////////////////////////////////////////////////////////////////////// void SetResGpuFlags(GMM_RESCREATE_PARAMS& Params, bool IsRT) { if (IsRT) { Params.Flags.Gpu.Depth = 0; Params.Flags.Gpu.RenderTarget = 1; } else { Params.Flags.Gpu.Depth = 1; Params.Flags.Gpu.RenderTarget = 0; } } ///////////////////////////////////////////////////////////////////////////////////// /// Sets ArraySize in GmmParams /// /// @param[in] Params: GmmParams /// @param[in] Size: Array Size /// ///////////////////////////////////////////////////////////////////////////////////// void SetResArraySize(GMM_RESCREATE_PARAMS& Params, int Size) { Params.ArraySize = Size; } ///////////////////////////////////////////////////////////////////////////////////// /// Get the Tile dimension and H/V Align for MSS and MCS surfaces /// /// @param[in] Bpp: bits per pixel /// @param[in] isRT: Request is for RT or Depth MSS /// @param[in] Tiling: Tile Type /// @param[in] MSAA: Num of Samples /// @param[out] HAlign: H Align for MSS /// @param[out] VAlign: V Align for MSS /// @param[out] TileDimX: Tile Width for given Tile, Resource, bpp /// @param[out] TileDimY: Tile Height for given Tile, Resource, bpp /// @param[out] MCSHAlign: H Align for MCS /// @param[out] MCSVAlign: V Align for MCS /// ///////////////////////////////////////////////////////////////////////////////////// void GetAlignmentAndTileDimensionsForMSAA(TEST_BPP Bpp, bool isRT, TEST_TILE_TYPE Tiling, TEST_MSAA MSAA, uint32_t& TileDimX, uint32_t& TileDimY, uint32_t& HAlign, uint32_t& VAlign, uint32_t& ExpectedMCSBpp, uint32_t &MCSHAlign, uint32_t &MCSVAlign) { const uint32_t MSSTileSize[TEST_TILE_MAX][TEST_BPP_MAX][2] = { {{64, 1}, {64, 1}, {64, 1}, {64, 1}, {64, 1}}, //Linear - no Tile Size, but min PitchAlign = 64 {{512, 8}, {512, 8}, {512, 8}, {512, 8}, {512, 8}}, //TileX {{128, 32}, {128, 32}, {128, 32}, {128, 32}, {128, 32}}, //TileY {{256, 256}, {512, 128}, {512, 128}, {1024, 64}, {1024, 64}}, //TileYs {{64, 64}, {128, 32}, {128, 32}, {256, 16}, {256, 16}}, //TileYf {{128, 32}, {128, 32}, {128, 32}, {128, 32}, {128, 32}}, //Tile4 {{256, 256}, {512, 128}, {512, 128}, {1024, 64}, {1024, 64}} //Tile64 }; uint32_t WMul = 1, HMul = 1; HAlign = 16; // RT H/VAlign VAlign = 4; if (!isRT) { HAlign = (Bpp == TEST_BPP_16) ? 8 : 4; //Depth 16bit = 8x4, ow 4x4 VAlign = 4; MCSHAlign = 4; //MCS uses base H/VAlign for 8bpp } uint32_t Tile[2] = {MSSTileSize[Tiling][Bpp][0], MSSTileSize[Tiling][Bpp][1]}; if (Tiling == TEST_TILEYS || Tiling == TEST_TILEYF || Tiling == TEST_TILE64) { GetInterleaveMSSPattern(MSAA, WMul, HMul, isRT, Bpp); //Std Tiling interleaves MSAA into 1x, decreasing std Tile size for MSAA'd sample //Std Tiling types should have std size alignment always Tile[0] = HAlign = (isRT) ? (MSSTileSize[Tiling][Bpp][0] / WMul) : MSSTileSize[Tiling][Bpp][0]; Tile[1] = VAlign = (isRT) ? (MSSTileSize[Tiling][Bpp][1] / HMul) : MSSTileSize[Tiling][Bpp][1]; HAlign /= pow(2.0, Bpp); //Unit alignment in pixels } TileDimX = Tile[0]; TileDimY = Tile[1]; ExpectedMCSBpp = (MSAA == MSAA_2x || MSAA == MSAA_4x) ? 1 : (MSAA == MSAA_8x) ? 4 : 8; uint32_t ExpectedMcsBppIdx = log2(ExpectedMCSBpp); MCSHAlign = isRT ? HAlign : MCSHAlign; //MCS uses base H/V ALign for 8bpp MCSVAlign = VAlign; MCSHAlign = (isRT && (Tiling == TEST_TILEYS || Tiling == TEST_TILEYF)) ? MSSTileSize[Tiling][ExpectedMcsBppIdx][0] / (WMul * ExpectedMCSBpp) : //Std Tile dim in pixels (Tiling == TEST_TILEYS || Tiling == TEST_TILEYF) ? MSSTileSize[Tiling][ExpectedMcsBppIdx][0] / ExpectedMCSBpp : MCSHAlign; //For legacy tile, MCS alignment is base (RT or Depth) alignment MCSVAlign = (isRT && (Tiling == TEST_TILEYS || Tiling == TEST_TILEYF)) ? MSSTileSize[Tiling][ExpectedMcsBppIdx][1] / HMul : (Tiling == TEST_TILEYS || Tiling == TEST_TILEYF) ? MSSTileSize[Tiling][ExpectedMcsBppIdx][1] : MCSVAlign; } ///////////////////////////////////////////////////////////////////////////////////// /// Get the interleave pattern for given Num Samples /// /// @param[in] MSAA: Num of Samples /// @param[in] IsRT: !RT means Depth resource /// @param[out] WidthMultiplier: Number of samples arranged side-by-side /// @param[out] HeightMultiplier: Number of samples arranged top-bottom /// ///////////////////////////////////////////////////////////////////////////////////// void GetInterleaveMSSPattern(TEST_MSAA MSAA, uint32_t &WidthMultiplier, uint32_t &HeightMultiplier, bool IsRT, TEST_BPP Bpp) { WidthMultiplier = 1; HeightMultiplier = 1; switch (MSAA) { case MSAA_2x: if (IsRT && pGfxAdapterInfo->SkuTable.FtrXe2PlusTiling && (Bpp == TEST_BPP_128)) { HeightMultiplier = 2; } else { WidthMultiplier = 2; } break; case MSAA_4x: WidthMultiplier = 2; HeightMultiplier = 2; break; case MSAA_8x: WidthMultiplier = 4; HeightMultiplier = 2; if (IsRT && pGfxAdapterInfo->SkuTable.FtrXe2PlusTiling && ((Bpp == TEST_BPP_8) || (Bpp == TEST_BPP_32))) { WidthMultiplier = 2; HeightMultiplier = 4; } else if (IsRT && !pGfxAdapterInfo->SkuTable.FtrTileY && !pGfxAdapterInfo->SkuTable.FtrXe2PlusTiling) { WidthMultiplier = 2; HeightMultiplier = 2; } break; case MSAA_16x: WidthMultiplier = 4; HeightMultiplier = 4; if (IsRT && pGfxAdapterInfo->SkuTable.FtrXe2PlusTiling && (Bpp == TEST_BPP_64)) { WidthMultiplier = 8; HeightMultiplier = 2; } else if (IsRT && !pGfxAdapterInfo->SkuTable.FtrTileY && !pGfxAdapterInfo->SkuTable.FtrXe2PlusTiling) { WidthMultiplier = 2; HeightMultiplier = 2; } break; default: break; } } ///////////////////////////////////////////////////////////////////////////////////// /// Verifies if HAlign matches the expected value. Fails test if value doesn't match /// /// @param[in] ResourceInfo: ResourceInfo returned by GmmLib /// @param[in] ExpectedValue: expected value to check against ///////////////////////////////////////////////////////////////////////////////////// template void VerifyResourceHAlign(GMM_RESOURCE_INFO *ResourceInfo, uint32_t ExpectedValue) { if(Verify) { EXPECT_EQ(ExpectedValue, ResourceInfo->GetHAlign()); } } ///////////////////////////////////////////////////////////////////////////////////// /// Verifies if HAlign matches the expected value. Fails test if value doesn't match /// /// @param[in] ResourceInfo: ResourceInfo returned by GmmLib /// @param[in] ExpectedValue: expected value to check against ///////////////////////////////////////////////////////////////////////////////////// template void VerifyResourceVAlign(GMM_RESOURCE_INFO *ResourceInfo, uint32_t ExpectedValue) { if(Verify) { EXPECT_EQ(ExpectedValue, ResourceInfo->GetVAlign()); } } ///////////////////////////////////////////////////////////////////////////////////// /// Verifies if Pitch (in bytes) matches the expected value. Fails test if value /// doesn't match /// /// @param[in] ResourceInfo: ResourceInfo returned by GmmLib /// @param[in] ExpectedValue: expected value to check against ///////////////////////////////////////////////////////////////////////////////////// template void VerifyResourcePitch(GMM_RESOURCE_INFO *ResourceInfo, uint32_t ExpectedValue) { if(Verify) { EXPECT_EQ(ExpectedValue, ResourceInfo->GetRenderPitch()); } } ///////////////////////////////////////////////////////////////////////////////////// /// Verifies if Pitch in tiles matches the expected value. Fails test if value /// doesn't match /// /// @param[in] ResourceInfo: ResourceInfo returned by GmmLib /// @param[in] ExpectedValue: expected value to check against ///////////////////////////////////////////////////////////////////////////////////// template void VerifyResourcePitchInTiles(GMM_RESOURCE_INFO *ResourceInfo, uint32_t ExpectedValue) { if(Verify) { EXPECT_EQ(ExpectedValue, ResourceInfo->GetRenderPitchTiles()); } } ///////////////////////////////////////////////////////////////////////////////////// /// Verifies if Size matches the expected value. Fails test if value doesn't match /// /// @param[in] ResourceInfo: ResourceInfo returned by GmmLib /// @param[in] ExpectedValue: expected value to check against ///////////////////////////////////////////////////////////////////////////////////// template void VerifyResourceSize(GMM_RESOURCE_INFO *ResourceInfo, uint64_t ExpectedValue) { if(Verify) { EXPECT_EQ(ExpectedValue, ResourceInfo->GetSizeMainSurface()); } } ///////////////////////////////////////////////////////////////////////////////////// /// Verifies if AuxCCSize matches the expected value. Fails test if value doesn't match /// /// @param[in] ResourceInfo: ResourceInfo returned by GmmLib /// @param[in] ExpectedValue: expected value to check against ///////////////////////////////////////////////////////////////////////////////////// template void VerifyResourceAuxCCSize(GMM_RESOURCE_INFO *ResourceInfo, uint64_t ExpectedValue) { if(Verify) { EXPECT_EQ(ExpectedValue, ResourceInfo->GetSizeAuxSurface(GMM_AUX_CC)); } } ///////////////////////////////////////////////////////////////////////////////////// /// Verifies if QPitch matches the expected value. Fails test if value doesn't match /// /// @param[in] ResourceInfo: ResourceInfo returned by GmmLib /// @param[in] ExpectedValue: expected value to check against ///////////////////////////////////////////////////////////////////////////////////// template void VerifyResourceQPitch(GMM_RESOURCE_INFO *ResourceInfo, uint64_t ExpectedValue) { if(Verify) { EXPECT_EQ(ExpectedValue, ResourceInfo->GetQPitch()); } } ///////////////////////////////////////////////////////////////////////////////////// /// Verifies if Tile4 info flag is set or not. Fails test if Tile4 flag is not set /// /// @param[in] ResourceInfo: ResourceInfo returned by GmmLib /// @param[in] ExpectedValue: expected value to check against ///////////////////////////////////////////////////////////////////////////////////// template void VerifyResourceTile4(GMM_RESOURCE_INFO *ResourceInfo, bool ExpectedValue) { if(Verify) { EXPECT_EQ(true, (GMM_IS_4KB_TILE(ResourceInfo->GetResFlags()))); } } public: CTestResource(); ~CTestResource(); static void SetUpTestCase(); static void TearDownTestCase(); }; ///////////////////////////////////////////////////////////////////////// /// Fixture class for Resources targeted for CpuBlt. This is CpuBlt resource /// test case. Inherits CTestResource class. /// @see CTestResource class ///////////////////////////////////////////////////////////////////////// class CTestCpuBltResource : public CTestResource { public: CTestCpuBltResource(); ~CTestCpuBltResource(); static void SetUpTestCase(); static void TearDownTestCase(); }; ///////////////////////////////////////////////////////////////////////// /// Helper function - builds list of input tuples /// /// @param[in/out] List: vector of tuple /// @param[in] maxTestDimension: Number of elements in TestDimensions[] /// @param[in] TestArray: Number fo elements in TestArraySize /// /// @return Number of tuples in the list /// @see GmmGen9ResourceULT.cpp ///////////////////////////////////////////////////////////////////////// int BuildInputIterator(std::vector> &List, int maxTestDimension, int TestArray, bool XEHPPlus); gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/ULT/GmmULT.cpp000066400000000000000000000027301466655022700223320ustar00rootroot00000000000000/*============================================================================== Copyright(c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ============================================================================*/ #include "stdafx.h" using namespace std; int g_argc; char **g_argv; int main(int argc, char *argv[]) { int FailCount = 0; testing::InitGoogleTest(&argc, argv); g_argc = argc; g_argv = argv; FailCount += RUN_ALL_TESTS(); return FailCount; } gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/ULT/GmmXe2_LPGResourceULT.cpp000066400000000000000000000302221466655022700251200ustar00rootroot00000000000000/*============================================================================== Copyright(c) 2024 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ============================================================================*/ #include "GmmXe2_LPGResourceULT.h" using namespace std; ///////////////////////////////////////////////////////////////////////////////////// /// Sets up common environment for Resource fixture tests. this is called once per /// test case before executing all tests under resource fixture test case. // It also calls SetupTestCase from CommonULT to initialize global context and others. /// /// ///////////////////////////////////////////////////////////////////////////////////// void CTestXe2_LPGResource::SetUpTestCase() { } ///////////////////////////////////////////////////////////////////////////////////// /// cleans up once all the tests finish execution. It also calls TearDownTestCase /// from CommonULT to destroy global context and others. /// ///////////////////////////////////////////////////////////////////////////////////// void CTestXe2_LPGResource::TearDownTestCase() { } void CTestXe2_LPGResource::SetUp_Xe2Variant(PRODUCT_FAMILY platform) { printf("%s\n", __FUNCTION__); if (platform == IGFX_BMG) { GfxPlatform.eProductFamily = IGFX_BMG; GfxPlatform.eRenderCoreFamily = IGFX_XE2_HPG_CORE; } else if (platform == IGFX_LUNARLAKE) { GfxPlatform.eProductFamily = IGFX_LUNARLAKE; GfxPlatform.eRenderCoreFamily = IGFX_XE2_LPG_CORE; } pGfxAdapterInfo = (ADAPTER_INFO*)malloc(sizeof(ADAPTER_INFO)); if (pGfxAdapterInfo) { memset(pGfxAdapterInfo, 0, sizeof(ADAPTER_INFO)); pGfxAdapterInfo->SkuTable.FtrLinearCCS = 1; //legacy y =>0 pGfxAdapterInfo->SkuTable.FtrStandardMipTailFormat = 1; pGfxAdapterInfo->SkuTable.FtrTileY = 0; pGfxAdapterInfo->SkuTable.FtrXe2PlusTiling = 1; pGfxAdapterInfo->SkuTable.FtrXe2Compression = 1; pGfxAdapterInfo->SkuTable.FtrFlatPhysCCS = 1; pGfxAdapterInfo->SkuTable.FtrLocalMemory = 0; pGfxAdapterInfo->SkuTable.FtrDiscrete = 0; pGfxAdapterInfo->SkuTable.FtrE2ECompression = 1; if (platform == IGFX_BMG) { pGfxAdapterInfo->SkuTable.FtrLocalMemory = 1; pGfxAdapterInfo->SkuTable.FtrDiscrete = 1; } if (platform == IGFX_LUNARLAKE || platform == IGFX_BMG) { pGfxAdapterInfo->WaTable.Wa_14018976079 = 1; pGfxAdapterInfo->WaTable.Wa_14018984349 = 1; pGfxAdapterInfo->SkuTable.FtrL3TransientDataFlush = 1; } CommonULT::SetUpTestCase(); } } void CTestXe2_LPGResource::TearDown_Xe2Variant() { printf("%s\n", __FUNCTION__); CommonULT::TearDownTestCase(); } TEST_F(CTestXe2_LPGResource, TestMSAA_BMG) { SetUp_Xe2Variant(IGFX_BMG); TestMSAA(); TearDown_Xe2Variant(); } TEST_F(CTestXe2_LPGResource, TestMSAA_LNL) { SetUp_Xe2Variant(IGFX_LUNARLAKE); TestMSAA(); TearDown_Xe2Variant(); } /// @brief ULT for MSAA Resource - Depth and Colour MSAA verification for Tile64 resources // Note: Verify with and without FtrXe2PlusTiling in Setup, Default: FtrXe2PlusTiling void CTestXe2_LPGResource::TestMSAA() { GMM_GFX_SIZE_T AuxCC, AuxCCS, AuxMCS; const uint32_t TestDimensions[4][2] = { //Input dimensions in #Tiles {16, 4}, //occupies single tile for Depth for all MSAAs and BPPs, multiple tiles for colours {128, 128}, // crosses a tile for > 4X MSAA for depth {128, 257}, // Crosses a tile in Y direction and for >4X MSAA, crosses in X direction too for depth {1, 1}, }; uint32_t TestArraySize[2] = {1, 5}; uint32_t MinPitch = 32; uint32_t HAlign, VAlign, TileDimX, TileDimY, MCSHAlign, MCSVAlign, TileSize; uint32_t ExpectedMCSBpp; std::vector> List; //TEST_TILE_TYPE, TEST_BPP, TEST_RESOURCE_TYPE, Depth or RT, TestDimension index, ArraySize auto Size = BuildInputIterator(List, 4, 2, true); // Size of arrays TestDimensions, TestArraySize for(auto element : List) { GMM_RESCREATE_PARAMS gmmParams = {}; gmmParams.Flags.Info = {0}; TEST_TILE_TYPE Tiling = (TEST_TILE_TYPE)std::get<0>(element); TEST_BPP Bpp = (TEST_BPP)std::get<1>(element); TEST_RESOURCE_TYPE ResType = (TEST_RESOURCE_TYPE)std::get<2>(element); bool IsRT = std::get<3>(element); // True for RT, False for Depth int TestDimIdx = std::get<4>(element); //index into TestDimensions array int ArrayIdx = std::get<5>(element); //index into TestArraySize TileSize = (Tiling == TEST_TILE64) ? GMM_KBYTE(64) : GMM_KBYTE(4); //Discard un-supported Tiling/Res_type/bpp for this test if((ResType != TEST_RESOURCE_2D) || //No 1D/3D/Cube. Supported 2D mip-maps/array // depth tested outside this function due to diff in halign/valign (Tiling != TEST_TILE64)) // MSAA not supported on Tile4 continue; SetTileFlag(gmmParams, Tiling); SetResType(gmmParams, ResType); SetResGpuFlags(gmmParams, IsRT); SetResArraySize(gmmParams, TestArraySize[ArrayIdx]); gmmParams.NoGfxMemory = 1; gmmParams.Format = SetResourceFormat(Bpp); for(uint32_t k = MSAA_2x; k <= MSAA_16x; k++) { GetAlignmentAndTileDimensionsForMSAA(Bpp, IsRT, Tiling, (TEST_MSAA)k, TileDimX, TileDimY, HAlign, VAlign, ExpectedMCSBpp, MCSHAlign, MCSVAlign); gmmParams.BaseWidth64 = TestDimensions[TestDimIdx][0] * (unsigned int)pow(2.0, Bpp); gmmParams.BaseHeight = TestDimensions[TestDimIdx][1]; gmmParams.Depth = 0x1; gmmParams.MSAA.NumSamples = static_cast(pow((double)2, k)); gmmParams.Flags.Gpu.MCS = 1; gmmParams.Flags.Gpu.CCS = 1; gmmParams.Flags.Gpu.UnifiedAuxSurface = 1; gmmParams.Flags.Gpu.IndirectClearColor = 1; //MSS surface GMM_RESOURCE_INFO *MSSResourceInfo; MSSResourceInfo = pGmmULTClientContext->CreateResInfoObject(&gmmParams); if(MSSResourceInfo) { VerifyResourceHAlign(MSSResourceInfo, HAlign); VerifyResourceVAlign(MSSResourceInfo, VAlign); if (gmmParams.Flags.Gpu.IndirectClearColor && pGfxAdapterInfo->SkuTable.FtrXe2Compression && (gmmParams.MSAA.NumSamples > 1)) { AuxCC = MSSResourceInfo->GetUnifiedAuxSurfaceOffset(GMM_AUX_CC); AuxMCS = MSSResourceInfo->GetUnifiedAuxSurfaceOffset(GMM_AUX_MCS); AuxCCS = MSSResourceInfo->GetUnifiedAuxSurfaceOffset(GMM_AUX_CCS); EXPECT_EQ(AuxCC, AuxMCS); EXPECT_EQ(AuxCCS, 0); AuxCC = MSSResourceInfo->GetSizeAuxSurface(GMM_AUX_CC); AuxMCS = MSSResourceInfo->GetSizeAuxSurface(GMM_AUX_MCS); AuxCCS = MSSResourceInfo->GetSizeAuxSurface(GMM_AUX_CCS); EXPECT_EQ(AuxCC, AuxMCS); EXPECT_EQ(AuxCCS, 0); } if(IsRT) //Arrayed MSS { uint32_t ExpectedPitch = 0, ExpectedQPitch = 0, ExpectedHeight = 0; ExpectedPitch = GMM_ULT_ALIGN(GMM_ULT_ALIGN(gmmParams.BaseWidth64, HAlign) * (unsigned int)pow(2.0, Bpp), TileDimX); // Aligned width * bpp, aligned to TileWidth ExpectedPitch = GFX_MAX(ExpectedPitch, MinPitch); VerifyResourcePitch(MSSResourceInfo, ExpectedPitch); if(Tiling != TEST_LINEAR) VerifyResourcePitchInTiles(MSSResourceInfo, ExpectedPitch / TileDimX); ExpectedQPitch = GMM_ULT_ALIGN(gmmParams.BaseHeight, VAlign); if(gmmParams.ArraySize > 1) //Gen9: Qpitch is distance between array slices (not sample slices) { VerifyResourceQPitch(MSSResourceInfo, ExpectedQPitch); } ExpectedHeight = GMM_ULT_ALIGN(ExpectedQPitch * gmmParams.MSAA.NumSamples * gmmParams.ArraySize, TileDimY); // For Tile64 layout prior to Xe2Tiling, MSAA8x and 16x follows MSAA4x. MSAA4x*2 for MSAA8x and MSAA4x*4 for MSAA16x. // Height getting multiplied by numsamples here is good enough for these special layouts too VerifyResourceSize(MSSResourceInfo, GMM_ULT_ALIGN(ExpectedPitch * ExpectedHeight, TileSize)); } else { uint32_t WidthMultiplier, HeightMultiplier; GetInterleaveMSSPattern((TEST_MSAA)k, WidthMultiplier, HeightMultiplier, IsRT, Bpp); gmmParams.BaseWidth64 = WidthMultiplier > 1 ? GMM_ULT_ALIGN(gmmParams.BaseWidth64, 2) : gmmParams.BaseWidth64; gmmParams.BaseHeight = HeightMultiplier > 1 ? GMM_ULT_ALIGN(gmmParams.BaseHeight, 2) : gmmParams.BaseHeight; uint32_t ExpectedPitch = GMM_ULT_ALIGN(GMM_ULT_ALIGN(gmmParams.BaseWidth64 * WidthMultiplier, HAlign) * (uint32_t)pow(2.0, Bpp), TileDimX); VerifyResourcePitch(MSSResourceInfo, ExpectedPitch); if(Tiling != TEST_LINEAR) { VerifyResourcePitchInTiles(MSSResourceInfo, ExpectedPitch / TileDimX); } uint64_t ExpectedQPitch = GMM_ULT_ALIGN(gmmParams.BaseHeight * HeightMultiplier, VAlign); uint32_t ExpandedArraySize = gmmParams.ArraySize * (((MSSResourceInfo->GetTileType() == GMM_TILED_64) && !pGfxAdapterInfo->SkuTable.FtrTileY && !pGfxAdapterInfo->SkuTable.FtrXe2PlusTiling && (gmmParams.MSAA.NumSamples == 16)) ? 4 : // MSAA x8/x16 stored as pseudo array planes each with 4x samples ((MSSResourceInfo->GetTileType() == GMM_TILED_64) && !pGfxAdapterInfo->SkuTable.FtrTileY && !pGfxAdapterInfo->SkuTable.FtrXe2PlusTiling && (gmmParams.MSAA.NumSamples == 8)) ? 2 : 1); if(ExpandedArraySize > 1) { VerifyResourceQPitch(MSSResourceInfo, ExpectedQPitch); } uint64_t ExpectedHeight = GMM_ULT_ALIGN(ExpectedQPitch * ExpandedArraySize, TileDimY); //Align Height = ExpectedQPitch*ArraySize, to Tile-Height VerifyResourceSize(MSSResourceInfo, GMM_ULT_ALIGN(ExpectedPitch * ExpectedHeight, TileSize)); //ExpectedPitch *ExpectedHeight } } pGmmULTClientContext->DestroyResInfoObject(MSSResourceInfo); } //NumSamples = k } //Iterate through all Input types{ } gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/ULT/GmmXe2_LPGResourceULT.h000066400000000000000000000030241466655022700245650ustar00rootroot00000000000000/*============================================================================== Copyright(c) 2024 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ============================================================================*/ #pragma once #include "GmmGen12dGPUResourceULT.h" class CTestXe2_LPGResource : public CTestGen12dGPUResource { protected: virtual void SetUp_Xe2Variant(PRODUCT_FAMILY platform); virtual void TearDown_Xe2Variant(); virtual void TestMSAA(); public: static void SetUpTestCase(); static void TearDownTestCase(); };gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/ULT/GmmXe_LPGCachePolicyULT.cpp000066400000000000000000000312171466655022700254370ustar00rootroot00000000000000/*============================================================================== Copyright(c) 2022 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ============================================================================*/ #include "GmmXe_LPGCachePolicyULT.h" using namespace std; ///////////////////////////////////////////////////////////////////////////////////// /// Sets up common environment for Cache Policy fixture tests. this is called once per /// test case before executing all tests under resource fixture test case. /// It also calls SetupTestCase from CommonULT to initialize global context and others. /// ///////////////////////////////////////////////////////////////////////////////////// void CTestXe_LPGCachePolicy::SetUpTestCase() { } ///////////////////////////////////////////////////////////////////////////////////// /// cleans up once all the tests finish execution. It also calls TearDownTestCase /// from CommonULT to destroy global context and others. /// ///////////////////////////////////////////////////////////////////////////////////// void CTestXe_LPGCachePolicy::TearDownTestCase() { } void CTestXe_LPGCachePolicy::SetUpXe_LPGVariant(PRODUCT_FAMILY platform) { printf("%s\n", __FUNCTION__); GfxPlatform.eProductFamily = platform; if (platform == IGFX_LUNARLAKE) { GfxPlatform.eRenderCoreFamily = IGFX_XE2_LPG_CORE; } else if (platform >= IGFX_BMG) { GfxPlatform.eRenderCoreFamily = IGFX_XE2_HPG_CORE; } else { GfxPlatform.eRenderCoreFamily = IGFX_XE_HPG_CORE; } pGfxAdapterInfo = (ADAPTER_INFO *)malloc(sizeof(ADAPTER_INFO)); if(pGfxAdapterInfo) { memset(pGfxAdapterInfo, 0, sizeof(ADAPTER_INFO)); pGfxAdapterInfo->SkuTable.FtrLinearCCS = 1; //legacy y =>0 - test both pGfxAdapterInfo->SkuTable.FtrStandardMipTailFormat = 1; pGfxAdapterInfo->SkuTable.FtrTileY = 0; pGfxAdapterInfo->SkuTable.FtrLocalMemory = 0; pGfxAdapterInfo->SkuTable.FtrDiscrete = 0; pGfxAdapterInfo->SkuTable.FtrIA32eGfxPTEs = 1; pGfxAdapterInfo->SkuTable.FtrL4Cache = 1; pGfxAdapterInfo->SkuTable.FtrL3TransientDataFlush = 0; if (platform == IGFX_BMG) { pGfxAdapterInfo->SkuTable.FtrLocalMemory = 1; pGfxAdapterInfo->SkuTable.FtrDiscrete = 1; } if (platform >= IGFX_BMG) { pGfxAdapterInfo->SkuTable.FtrL3TransientDataFlush = 1; pGfxAdapterInfo->WaTable.Wa_14018976079 = 1; pGfxAdapterInfo->WaTable.Wa_14018984349 = 1; } CommonULT::SetUpTestCase(); } } void CTestXe_LPGCachePolicy::TearDownXe_LPGVariant() { printf("%s\n", __FUNCTION__); CommonULT::TearDownTestCase(); } /***********************XeLPG***********************************/ TEST_F(CTestXe_LPGCachePolicy, TestXe_LPGCachePolicy_FtrL4CacheEnabled) { SetUpXe_LPGVariant(IGFX_METEORLAKE); CheckVirtualL3CachePolicy(); CheckPAT(); TearDownXe_LPGVariant(); } /***********************Xe2_HPG***********************************/ TEST_F(CTestXe_LPGCachePolicy, TestXe2_HPGCachePolicy_FtrL4CacheEnabled) { SetUpXe_LPGVariant(IGFX_BMG); CheckXe2_HPGVirtualL3CachePolicy(); CheckPAT(); // Has both L3 and PAT within Check_Xe2_HPG_PATCompressed(); TearDownXe_LPGVariant(); } TEST_F(CTestXe_LPGCachePolicy, TestXe2_LPGCachePolicy_FtrL4CacheEnabled) { SetUpXe_LPGVariant(IGFX_LUNARLAKE); CheckXe2_HPGVirtualL3CachePolicy(); CheckPAT(); // Has both L3 and PAT within Check_Xe2_HPG_PATCompressed(); TearDownXe_LPGVariant(); } void CTestXe_LPGCachePolicy::CheckVirtualL3CachePolicy() { const uint32_t L4_WB_CACHEABLE = 0x0; const uint32_t L4_WT_CACHEABLE = 0x1; const uint32_t L4_UNCACHEABLE = 0x3; const uint32_t L3_WB_CACHEABLE = 0x3; const uint32_t L3_UNCACHEABLE = 0x1; for(uint32_t MocsIndex = 0; MocsIndex < GMM_XE_NUM_MOCS_ENTRIES; MocsIndex++) { GMM_CACHE_POLICY_TBL_ELEMENT Mocs = pGmmULTClientContext->GetCachePolicyTlbElement(MocsIndex); //printf("Xe LPG: MocsIndex: %d --> Global Index: [0x%x]\n", MocsIndex, Mocs.LeCC.Xe_LPG.DwordValue); //printf("Xe LPG: MocsIndex: %d --> L3 Index: [0x%x]\n", MocsIndex, Mocs.L3.UshortValue); } // Check Usage MOCS index against MOCS settings for(uint32_t Usage = GMM_RESOURCE_USAGE_UNKNOWN; Usage < GMM_RESOURCE_USAGE_MAX; Usage++) { GMM_CACHE_POLICY_ELEMENT ClientRequest = pGmmULTClientContext->GetCachePolicyElement((GMM_RESOURCE_USAGE_TYPE)Usage); uint32_t AssignedMocsIdx = ClientRequest.MemoryObjectOverride.XE_LPG.Index; GMM_CACHE_POLICY_TBL_ELEMENT Mocs = pGmmULTClientContext->GetCachePolicyTlbElement(AssignedMocsIdx); uint32_t StartMocsIdx = 0; EXPECT_EQ(0, Mocs.L3.ESC) << "Usage# " << Usage << ": ESC is non-zero"; EXPECT_EQ(0, Mocs.L3.SCC) << "Usage# " << Usage << ": SCC is non-zero"; EXPECT_EQ(0, Mocs.L3.Reserved) << "Usage# " << Usage << ": Reserved field is non-zero"; // Check if Mocs Index is not greater than GMM_MAX_NUMBER_MOCS_INDEXES EXPECT_GT(GMM_XE_NUM_MOCS_ENTRIES, AssignedMocsIdx) << "Usage# " << Usage << ": MOCS Index greater than MAX allowed (16)"; EXPECT_EQ(0, Mocs.LeCC.Xe_LPG.Reserved0) << "Usage# " << Usage << ": : Reserved field is non-zero"; EXPECT_EQ(0, Mocs.LeCC.Xe_LPG.Reserved1) << "Usage# " << Usage << ": : Reserved field is non-zero"; EXPECT_EQ(0, Mocs.LeCC.Xe_LPG.Reserved2) << "Usage# " << Usage << ": : Reserved field is non-zero"; EXPECT_EQ(0, Mocs.LeCC.Xe_LPG.Reserved3) << "Usage# " << Usage << ": : Reserved field is non-zero"; EXPECT_EQ(1, Mocs.LeCC.Xe_LPG.igPAT) << "Usage# " << Usage << ": Incorrect igPAT cachebility setting"; //printf("Xe LPG: Usage: %d --> Index: [%d]\n", Usage, AssignedMocsIdx); //L3 if (ClientRequest.L3CC) { EXPECT_EQ(L3_WB_CACHEABLE, Mocs.L3.Cacheability) << "Usage# " << Usage << ": Incorrect L3 cachebility setting"; } else { EXPECT_EQ(L3_UNCACHEABLE, Mocs.L3.Cacheability) << "Usage# " << Usage << ": Incorrect L3 cachebility setting"; } // L4 cache memory- 0: UC, 1:WB, 2: WT switch(ClientRequest.L4CC) { case 0x1: { EXPECT_EQ(L4_WB_CACHEABLE, Mocs.LeCC.Xe_LPG.L4CC) << "Usage# " << Usage << ": Incorrect L4CC cachebility setting"; break; } case 0x2: { EXPECT_EQ(L4_WT_CACHEABLE, Mocs.LeCC.Xe_LPG.L4CC) << "Usage# " << Usage << ": Incorrect L4CC cachebility setting"; break; } default: EXPECT_EQ(L4_UNCACHEABLE, Mocs.LeCC.Xe_LPG.L4CC) << "Usage# " << Usage << ": Incorrect L4CC cachebility setting"; } } } void CTestXe_LPGCachePolicy::CheckPAT() { // Check Usage PAT index against PAT settings for(uint32_t Usage = GMM_RESOURCE_USAGE_UNKNOWN; Usage < GMM_RESOURCE_USAGE_MAX; Usage++) { GMM_CACHE_POLICY_ELEMENT ClientRequest = pGmmULTClientContext->GetCachePolicyElement((GMM_RESOURCE_USAGE_TYPE)Usage); if(ClientRequest.Initialized == false) // undefined resource in platform { continue; } uint32_t PATIndex = pGmmULTClientContext->CachePolicyGetPATIndex(NULL, (GMM_RESOURCE_USAGE_TYPE)Usage, NULL, false); EXPECT_NE(PATIndex, GMM_PAT_ERROR) << "Usage# " << Usage << ": No matching PAT Index"; } } void CTestXe_LPGCachePolicy::Check_Xe2_HPG_PATCompressed() { bool CompressionEnReq = true; // Check Usage PAT index against PAT settings for (uint32_t Usage = GMM_RESOURCE_USAGE_UNKNOWN; Usage < GMM_RESOURCE_USAGE_MAX; Usage++) { GMM_CACHE_POLICY_ELEMENT ClientRequest = pGmmULTClientContext->GetCachePolicyElement((GMM_RESOURCE_USAGE_TYPE)Usage); CompressionEnReq = true; if (ClientRequest.Initialized == false) // undefined resource in platform { continue; } uint32_t PATIndex = pGmmULTClientContext->CachePolicyGetPATIndex(NULL, (GMM_RESOURCE_USAGE_TYPE)Usage, &CompressionEnReq, false); //printf("Xe HPG: Usage: %d --> Compressed PAT Index: [%d], ComEn: [%d]\n", Usage, PATIndex, CompressionEnReq); EXPECT_NE(PATIndex, GMM_PAT_ERROR) << "Usage# " << Usage << ": No matching PAT Index"; } } void CTestXe_LPGCachePolicy::CheckXe2_HPGVirtualL3CachePolicy() { const uint32_t L4_WB_CACHEABLE = 0x0; const uint32_t L4_WT_CACHEABLE = 0x1; const uint32_t L4_UNCACHEABLE = 0x3; const uint32_t L3_WB_CACHEABLE = 0x0; const uint32_t L3_XD_CACHEABLE = pGmmULTClientContext->GetSkuTable().FtrL3TransientDataFlush ? 0x1 : 0x0; const uint32_t L3_UNCACHEABLE = 0x3; // Check Usage MOCS index against MOCS settings for (uint32_t Usage = GMM_RESOURCE_USAGE_UNKNOWN; Usage < GMM_RESOURCE_USAGE_MAX; Usage++) { GMM_CACHE_POLICY_ELEMENT ClientRequest = pGmmULTClientContext->GetCachePolicyElement((GMM_RESOURCE_USAGE_TYPE)Usage); uint32_t AssignedMocsIdx = ClientRequest.MemoryObjectOverride.XE_HP.Index; GMM_CACHE_POLICY_TBL_ELEMENT Mocs = pGmmULTClientContext->GetCachePolicyTlbElement(AssignedMocsIdx); uint32_t StartMocsIdx = 0; EXPECT_EQ(0, Mocs.L3.PhysicalL3.Reserved) << "Usage# " << Usage << ": Reserved field is non-zero"; EXPECT_EQ(0, Mocs.L3.PhysicalL3.Reserved0) << "Usage# " << Usage << ": Reserved field is non-zero"; EXPECT_EQ(0, Mocs.L3.PhysicalL3.L3CLOS) << "Usage# " << Usage << ": L3CLOS field is non-zero"; // Check if Mocs Index is not greater than GMM_MAX_NUMBER_MOCS_INDEXES EXPECT_GT(GMM_XE2_NUM_MOCS_ENTRIES, AssignedMocsIdx) << "Usage# " << Usage << ": MOCS Index greater than MAX allowed (16)"; //printf("Xe HPG: Usage: %d --> Index: [%d]\n", Usage, AssignedMocsIdx); if (ClientRequest.IgnorePAT == true) { EXPECT_EQ(1, Mocs.L3.PhysicalL3.igPAT) << "Usage# " << Usage << ": Incorrect igPAT cachebility setting"; // L4 memory cache 0: UC, 1:WB, 2: WT switch (ClientRequest.L4CC) { case 0x1: { EXPECT_EQ(L4_WB_CACHEABLE, Mocs.L3.PhysicalL3.L4CC) << "Usage# " << Usage << ": Incorrect L4CC cachebility setting"; break; } case 0x2: { EXPECT_EQ(L4_WT_CACHEABLE, Mocs.L3.PhysicalL3.L4CC) << "Usage# " << Usage << ": Incorrect L4CC cachebility setting"; break; } default: EXPECT_EQ(L4_UNCACHEABLE, Mocs.L3.PhysicalL3.L4CC) << "Usage# " << Usage << ": Incorrect L4CC cachebility setting"; } // 0:UC, 1:WB 2:WB_T_Display, 3:WB_T_App switch (ClientRequest.L3CC) { case 0x1: EXPECT_EQ(L3_WB_CACHEABLE, Mocs.L3.PhysicalL3.L3CC) << "Usage# " << Usage << ": Incorrect L3CC cachebility setting"; break; case 0x3: { EXPECT_EQ(L3_XD_CACHEABLE, Mocs.L3.PhysicalL3.L3CC) << "Usage# " << Usage << ": Incorrect L3CC cachebility setting"; break; } default: EXPECT_EQ(L3_UNCACHEABLE, Mocs.L3.PhysicalL3.L3CC) << "Usage# " << Usage << ": Incorrect L3CC cachebility setting"; } } else { EXPECT_EQ(0, Mocs.L3.PhysicalL3.igPAT) << "Usage# " << Usage << ": Incorrect igPAT cachebility setting"; } } } gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/ULT/GmmXe_LPGCachePolicyULT.h000066400000000000000000000032441466655022700251030ustar00rootroot00000000000000/*============================================================================== Copyright(c) 2022 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ============================================================================*/ #pragma once #include "GmmCachePolicyULT.h" class CTestXe_LPGCachePolicy : public CTestCachePolicy { protected: virtual void SetUpXe_LPGVariant(PRODUCT_FAMILY); virtual void TearDownXe_LPGVariant(); virtual void CheckVirtualL3CachePolicy(); virtual void CheckPAT(); virtual void Check_Xe2_HPG_PATCompressed(); virtual void CheckXe2_HPGVirtualL3CachePolicy(); public: static void SetUpTestCase(); static void TearDownTestCase(); }; #pragma once gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/ULT/ReadMe.txt000066400000000000000000000077651466655022700224340ustar00rootroot00000000000000======================================================================== CONSOLE APPLICATION : GmmLibULT Project Overview ======================================================================== GMM ULT for the GMM Cache Policy. GmmLibULT.vcxproj This is the main project file. GmmLibULT.vcxproj.filters This is the filters file for VC++ project. It contains information about the association between the files in your project and the filters. This association is used in the IDE to show grouping of files with similar extensions under a specific node (for e.g. ".cpp" files are associated with the "Source Files" filter). GmmLibULT.cpp This is the main application source file. ///////////////////////////////////////////////////////////////////////////// Other standard files: StdAfx.h, StdAfx.cpp These files are used to build a precompiled header (PCH) file named GmmLibULT.pch and a precompiled types file named StdAfx.obj. ///////////////////////////////////////////////////////////////////////////// Other notes: This ULT is divided into 2 parts. 1. CompileTime ULT - Runs with every Gmmlib build and KMD build How to trigger Test cases through commandline: i. Run all Compile Time TestCases --> GmmULT.exe CTest*.* ii.Run Specific TestCase --> GmmULT.exe CTestGen9CachePolicy.* 2. RunTime ULT - Runnable on Target system. Have to run it manually - not qualified to run on Host/Dev systems How to trigger Test cases through commandline: i. CachePolicy ULT --> GmmULT.exe RTestGen9CachePolicy.* ii. Vulkan Generic Resource --> GmmULT.exe RTestVulkanResource.*Generic* ii. Vulkan Sparse Resource --> GmmULT.exe RTestVulkanResource.*Sparse* To Run the Test on target i. Download Driver along with Test Tools, which has ExCITE DLL or build ExCITE DLL on your dev system with the installed driver source ii. Install driver and copy DLL in either C:\Windows\System32 (for 64-bit app/DLL) or C:\Windows\SysWoW64 or place it in ULT executable Directory iii. Specify commandline and run GMMULT.exe Test Case: > Test Case is defined by FIXTURE class -> Test Case = FIXTURE Class > Ex. class CTestResource : public testing::Test --> CTestResource is FIXTURE class Test: > Test resides in FIXTURE. FIXTURE class has multiple tests > Ex. TEST_F(CTestResource, test2DResource) --> test2DResource is a test of test case - CTestResource SetUp() vs SetUpTestCase() > SetUp() -> gets called for all the tests in a test case. This is per-test setup/tear down > SetUpTestCase() -> When multiple tests in a test case share resource or needs same set up, then instead of repeating set up per test, SetUpTestCase gets called once per test case and all the tests inside a test case, use same set up. To exclude tests from execution > --gtest_filter=POSTIVE_PATTERNS[-NEGATIVE_PATTERNS] > Ex. --gtest_filter=-ABC.*:BCD.* What happens when test/test case is triggered TEST_F(CTestGen9Resource, Test2DTileYResource) --> first instance of test in CTestGen9Resource FIXTURE test case 1. CTestGen9Resource::SetUpTestCase() --> this sets up platform --> This step is skipped if this is subsequence test instances in test case. i. Calls CommonULT::SetUpTestCase() --> GmmInitGlobalContext() and other initialization 2. CTestResource::CTestResource() 3. CTestGen9Resource::CTestGen9Resource() 4. Test_F body --> test execution 5. CTestGen9Resource::~CTestGen9Resource() 6. CTestResource::~CTestResource( ) 7. CommonULT::~CommonULT() --> Destroys Global Context 8. void CTestGen9Resource::TearDownTestCase() --> only if this is last instance of test in test case CompileTime cmdline: $(TargetDir)$(TargetFileName) --gtest_filter=CTestResource.Test2DTileYsResource To debug failures, add the following in the command line argument: --gtest_break_on_failure This will cause an assert to be hit whenever a test fails. You can use the call stack to go back to the failing test and debug. ///////////////////////////////////////////////////////////////////////////// gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/ULT/googletest/000077500000000000000000000000001466655022700226735ustar00rootroot00000000000000gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/ULT/googletest/gtest/000077500000000000000000000000001466655022700240215ustar00rootroot00000000000000gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/ULT/googletest/gtest/gtest.h000066400000000000000000035321461466655022700253360ustar00rootroot00000000000000// Copyright 2005, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // Author: wan@google.com (Zhanyong Wan) // // The Google C++ Testing Framework (Google Test) // // This header file defines the public API for Google Test. It should be // included by any test program that uses Google Test. // // IMPORTANT NOTE: Due to limitation of the C++ language, we have to // leave some internal implementation details in this header file. // They are clearly marked by comments like this: // // // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. // // Such code is NOT meant to be used by a user directly, and is subject // to CHANGE WITHOUT NOTICE. Therefore DO NOT DEPEND ON IT in a user // program! // // Acknowledgment: Google Test borrowed the idea of automatic test // registration from Barthelemy Dagenais' (barthelemy@prologique.com) // easyUnit framework. #ifndef GTEST_INCLUDE_GTEST_GTEST_H_ #define GTEST_INCLUDE_GTEST_GTEST_H_ #if !defined stdt #define stdt std::tr1 #endif #include #include #include // Copyright 2005, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // Authors: wan@google.com (Zhanyong Wan), eefacm@gmail.com (Sean Mcafee) // // The Google C++ Testing Framework (Google Test) // // This header file declares functions and macros used internally by // Google Test. They are subject to change without notice. #ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_INTERNAL_H_ #define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_INTERNAL_H_ // Copyright 2005, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // Authors: wan@google.com (Zhanyong Wan) // // Low-level types and utilities for porting Google Test to various // platforms. They are subject to change without notice. DO NOT USE // THEM IN USER CODE. // // This file is fundamental to Google Test. All other Google Test source // files are expected to #include this. Therefore, it cannot #include // any other Google Test header. #ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PORT_H_ #define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PORT_H_ // The user can define the following macros in the build script to // control Google Test's behavior. If the user doesn't define a macro // in this list, Google Test will define it. // // GTEST_HAS_CLONE - Define it to 1/0 to indicate that clone(2) // is/isn't available. // GTEST_HAS_EXCEPTIONS - Define it to 1/0 to indicate that exceptions // are enabled. // GTEST_HAS_GLOBAL_STRING - Define it to 1/0 to indicate that ::string // is/isn't available (some systems define // ::string, which is different to std::string). // GTEST_HAS_GLOBAL_WSTRING - Define it to 1/0 to indicate that ::string // is/isn't available (some systems define // ::wstring, which is different to std::wstring). // GTEST_HAS_POSIX_RE - Define it to 1/0 to indicate that POSIX regular // expressions are/aren't available. // GTEST_HAS_PTHREAD - Define it to 1/0 to indicate that // is/isn't available. // GTEST_HAS_RTTI - Define it to 1/0 to indicate that RTTI is/isn't // enabled. // GTEST_HAS_STD_WSTRING - Define it to 1/0 to indicate that // std::wstring does/doesn't work (Google Test can // be used where std::wstring is unavailable). // GTEST_HAS_TR1_TUPLE - Define it to 1/0 to indicate tr1::tuple // is/isn't available. // GTEST_HAS_SEH - Define it to 1/0 to indicate whether the // compiler supports Microsoft's "Structured // Exception Handling". // GTEST_HAS_STREAM_REDIRECTION // - Define it to 1/0 to indicate whether the // platform supports I/O stream redirection using // dup() and dup2(). // GTEST_USE_OWN_TR1_TUPLE - Define it to 1/0 to indicate whether Google // Test's own tr1 tuple implementation should be // used. Unused when the user sets // GTEST_HAS_TR1_TUPLE to 0. // GTEST_LANG_CXX11 - Define it to 1/0 to indicate that Google Test // is building in C++11/C++98 mode. // GTEST_LINKED_AS_SHARED_LIBRARY // - Define to 1 when compiling tests that use // Google Test as a shared library (known as // DLL on Windows). // GTEST_CREATE_SHARED_LIBRARY // - Define to 1 when compiling Google Test itself // as a shared library. // This header defines the following utilities: // // Macros indicating the current platform (defined to 1 if compiled on // the given platform; otherwise undefined): // GTEST_OS_AIX - IBM AIX // GTEST_OS_CYGWIN - Cygwin // GTEST_OS_HPUX - HP-UX // GTEST_OS_LINUX - Linux // GTEST_OS_LINUX_ANDROID - Google Android // GTEST_OS_MAC - Mac OS X // GTEST_OS_IOS - iOS // GTEST_OS_IOS_SIMULATOR - iOS simulator // GTEST_OS_NACL - Google Native Client (NaCl) // GTEST_OS_OPENBSD - OpenBSD // GTEST_OS_QNX - QNX // GTEST_OS_SOLARIS - Sun Solaris // GTEST_OS_SYMBIAN - Symbian // GTEST_OS_WINDOWS - Windows (Desktop, MinGW, or Mobile) // GTEST_OS_WINDOWS_DESKTOP - Windows Desktop // GTEST_OS_WINDOWS_MINGW - MinGW // GTEST_OS_WINDOWS_MOBILE - Windows Mobile // GTEST_OS_ZOS - z/OS // // Among the platforms, Cygwin, Linux, Max OS X, and Windows have the // most stable support. Since core members of the Google Test project // don't have access to other platforms, support for them may be less // stable. If you notice any problems on your platform, please notify // googletestframework@googlegroups.com (patches for fixing them are // even more welcome!). // // Note that it is possible that none of the GTEST_OS_* macros are defined. // // Macros indicating available Google Test features (defined to 1 if // the corresponding feature is supported; otherwise undefined): // GTEST_HAS_COMBINE - the Combine() function (for value-parameterized // tests) // GTEST_HAS_DEATH_TEST - death tests // GTEST_HAS_PARAM_TEST - value-parameterized tests // GTEST_HAS_TYPED_TEST - typed tests // GTEST_HAS_TYPED_TEST_P - type-parameterized tests // GTEST_USES_POSIX_RE - enhanced POSIX regex is used. Do not confuse with // GTEST_HAS_POSIX_RE (see above) which users can // define themselves. // GTEST_USES_SIMPLE_RE - our own simple regex is used; // the above two are mutually exclusive. // GTEST_CAN_COMPARE_NULL - accepts untyped NULL in EXPECT_EQ(). // // Macros for basic C++ coding: // GTEST_AMBIGUOUS_ELSE_BLOCKER_ - for disabling a gcc warning. // GTEST_ATTRIBUTE_UNUSED_ - declares that a class' instances or a // variable don't have to be used. // GTEST_DISALLOW_ASSIGN_ - disables operator=. // GTEST_DISALLOW_COPY_AND_ASSIGN_ - disables copy ctor and operator=. // GTEST_MUST_USE_RESULT_ - declares that a function's result must be used. // // Synchronization: // Mutex, MutexLock, ThreadLocal, GetThreadCount() // - synchronization primitives. // GTEST_IS_THREADSAFE - defined to 1 to indicate that the above // synchronization primitives have real implementations // and Google Test is thread-safe; or 0 otherwise. // // Template meta programming: // is_pointer - as in TR1; needed on Symbian and IBM XL C/C++ only. // IteratorTraits - partial implementation of std::iterator_traits, which // is not available in libCstd when compiled with Sun C++. // // Smart pointers: // scoped_ptr - as in TR2. // // Regular expressions: // RE - a simple regular expression class using the POSIX // Extended Regular Expression syntax on UNIX-like // platforms, or a reduced regular exception syntax on // other platforms, including Windows. // // Logging: // GTEST_LOG_() - logs messages at the specified severity level. // LogToStderr() - directs all log messages to stderr. // FlushInfoLog() - flushes informational log messages. // // Stdout and stderr capturing: // CaptureStdout() - starts capturing stdout. // GetCapturedStdout() - stops capturing stdout and returns the captured // string. // CaptureStderr() - starts capturing stderr. // GetCapturedStderr() - stops capturing stderr and returns the captured // string. // // Integer types: // TypeWithSize - maps an integer to a int type. // Int32, UInt32, Int64, UInt64, TimeInMillis // - integers of known sizes. // BiggestInt - the biggest signed integer type. // // Command-line utilities: // GTEST_FLAG() - references a flag. // GTEST_DECLARE_*() - declares a flag. // GTEST_DEFINE_*() - defines a flag. // GetInjectableArgvs() - returns the command line as a vector of strings. // // Environment variable utilities: // GetEnv() - gets the value of an environment variable. // BoolFromGTestEnv() - parses a bool environment variable. // Int32FromGTestEnv() - parses an Int32 environment variable. // StringFromGTestEnv() - parses a string environment variable. #include // for isspace, etc #include // for ptrdiff_t #include #include #include #ifndef _WIN32_WCE # include # include #endif // !_WIN32_WCE #if defined __APPLE__ # include # include #endif #include // NOLINT #include // NOLINT #include // NOLINT #define GTEST_DEV_EMAIL_ "googletestframework@@googlegroups.com" #define GTEST_FLAG_PREFIX_ "gtest_" #define GTEST_FLAG_PREFIX_DASH_ "gtest-" #define GTEST_FLAG_PREFIX_UPPER_ "GTEST_" #define GTEST_NAME_ "Google Test" #define GTEST_PROJECT_URL_ "http://code.google.com/p/googletest/" // Determines the version of gcc that is used to compile this. #ifdef __GNUC__ // 40302 means version 4.3.2. # define GTEST_GCC_VER_ \ (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) #endif // __GNUC__ // Determines the platform on which Google Test is compiled. #ifdef __CYGWIN__ # define GTEST_OS_CYGWIN 1 #elif defined __SYMBIAN32__ # define GTEST_OS_SYMBIAN 1 #elif defined _WIN32 # define GTEST_OS_WINDOWS 1 # ifdef _WIN32_WCE # define GTEST_OS_WINDOWS_MOBILE 1 # elif defined(__MINGW__) || defined(__MINGW32__) # define GTEST_OS_WINDOWS_MINGW 1 # else # define GTEST_OS_WINDOWS_DESKTOP 1 # endif // _WIN32_WCE #elif defined __APPLE__ # define GTEST_OS_MAC 1 # if TARGET_OS_IPHONE # define GTEST_OS_IOS 1 # if TARGET_IPHONE_SIMULATOR # define GTEST_OS_IOS_SIMULATOR 1 # endif # endif #elif defined __linux__ # define GTEST_OS_LINUX 1 # if defined __ANDROID__ # define GTEST_OS_LINUX_ANDROID 1 # endif #elif defined __MVS__ # define GTEST_OS_ZOS 1 #elif defined(__sun) && defined(__SVR4) # define GTEST_OS_SOLARIS 1 #elif defined(_AIX) # define GTEST_OS_AIX 1 #elif defined(__hpux) # define GTEST_OS_HPUX 1 #elif defined __native_client__ # define GTEST_OS_NACL 1 #elif defined __OpenBSD__ # define GTEST_OS_OPENBSD 1 #elif defined __QNX__ # define GTEST_OS_QNX 1 #endif // __CYGWIN__ #ifndef GTEST_LANG_CXX11 // gcc and clang define __GXX_EXPERIMENTAL_CXX0X__ when // -std={c,gnu}++{0x,11} is passed. The C++11 standard specifies a // value for __cplusplus, and recent versions of clang, gcc, and // probably other compilers set that too in C++11 mode. # if __GXX_EXPERIMENTAL_CXX0X__ || __cplusplus >= 201103L // Compiling in at least C++11 mode. # define GTEST_LANG_CXX11 1 # else # define GTEST_LANG_CXX11 0 # endif #endif // Brings in definitions for functions used in the testing::internal::posix // namespace (read, write, close, chdir, isatty, stat). We do not currently // use them on Windows Mobile. #if !GTEST_OS_WINDOWS // This assumes that non-Windows OSes provide unistd.h. For OSes where this // is not the case, we need to include headers that provide the functions // mentioned above. # include # include #elif !GTEST_OS_WINDOWS_MOBILE # include # include #endif #if GTEST_OS_LINUX_ANDROID // Used to define __ANDROID_API__ matching the target NDK API level. # include // NOLINT #endif // Defines this to true iff Google Test can use POSIX regular expressions. #ifndef GTEST_HAS_POSIX_RE # if GTEST_OS_LINUX_ANDROID // On Android, is only available starting with Gingerbread. # define GTEST_HAS_POSIX_RE (__ANDROID_API__ >= 9) # else # define GTEST_HAS_POSIX_RE (!GTEST_OS_WINDOWS) # endif #endif #if GTEST_HAS_POSIX_RE // On some platforms, needs someone to define size_t, and // won't compile otherwise. We can #include it here as we already // included , which is guaranteed to define size_t through // . # include // NOLINT # define GTEST_USES_POSIX_RE 1 #elif GTEST_OS_WINDOWS // is not available on Windows. Use our own simple regex // implementation instead. # define GTEST_USES_SIMPLE_RE 1 #else // may not be available on this platform. Use our own // simple regex implementation instead. # define GTEST_USES_SIMPLE_RE 1 #endif // GTEST_HAS_POSIX_RE #ifndef GTEST_HAS_EXCEPTIONS // The user didn't tell us whether exceptions are enabled, so we need // to figure it out. # if defined(_MSC_VER) || defined(__BORLANDC__) // MSVC's and C++Builder's implementations of the STL use the _HAS_EXCEPTIONS // macro to enable exceptions, so we'll do the same. // Assumes that exceptions are enabled by default. # ifndef _HAS_EXCEPTIONS # define _HAS_EXCEPTIONS 1 # endif // _HAS_EXCEPTIONS # define GTEST_HAS_EXCEPTIONS _HAS_EXCEPTIONS # elif defined(__GNUC__) && __EXCEPTIONS // gcc defines __EXCEPTIONS to 1 iff exceptions are enabled. # define GTEST_HAS_EXCEPTIONS 1 # elif defined(__SUNPRO_CC) // Sun Pro CC supports exceptions. However, there is no compile-time way of // detecting whether they are enabled or not. Therefore, we assume that // they are enabled unless the user tells us otherwise. # define GTEST_HAS_EXCEPTIONS 1 # elif defined(__IBMCPP__) && __EXCEPTIONS // xlC defines __EXCEPTIONS to 1 iff exceptions are enabled. # define GTEST_HAS_EXCEPTIONS 1 # elif defined(__HP_aCC) // Exception handling is in effect by default in HP aCC compiler. It has to // be turned of by +noeh compiler option if desired. # define GTEST_HAS_EXCEPTIONS 1 # else // For other compilers, we assume exceptions are disabled to be // conservative. # define GTEST_HAS_EXCEPTIONS 0 # endif // defined(_MSC_VER) || defined(__BORLANDC__) #endif // GTEST_HAS_EXCEPTIONS #if !defined(GTEST_HAS_STD_STRING) // Even though we don't use this macro any longer, we keep it in case // some clients still depend on it. # define GTEST_HAS_STD_STRING 1 #elif !GTEST_HAS_STD_STRING // The user told us that ::std::string isn't available. # error "Google Test cannot be used where ::std::string isn't available." #endif // !defined(GTEST_HAS_STD_STRING) #ifndef GTEST_HAS_GLOBAL_STRING // The user didn't tell us whether ::string is available, so we need // to figure it out. # define GTEST_HAS_GLOBAL_STRING 0 #endif // GTEST_HAS_GLOBAL_STRING #ifndef GTEST_HAS_STD_WSTRING // The user didn't tell us whether ::std::wstring is available, so we need // to figure it out. // TODO(wan@google.com): uses autoconf to detect whether ::std::wstring // is available. // Cygwin 1.7 and below doesn't support ::std::wstring. // Solaris' libc++ doesn't support it either. Android has // no support for it at least as recent as Froyo (2.2). # define GTEST_HAS_STD_WSTRING \ (!(GTEST_OS_LINUX_ANDROID || GTEST_OS_CYGWIN || GTEST_OS_SOLARIS)) #endif // GTEST_HAS_STD_WSTRING #ifndef GTEST_HAS_GLOBAL_WSTRING // The user didn't tell us whether ::wstring is available, so we need // to figure it out. # define GTEST_HAS_GLOBAL_WSTRING \ (GTEST_HAS_STD_WSTRING && GTEST_HAS_GLOBAL_STRING) #endif // GTEST_HAS_GLOBAL_WSTRING // Determines whether RTTI is available. #ifndef GTEST_HAS_RTTI // The user didn't tell us whether RTTI is enabled, so we need to // figure it out. # ifdef _MSC_VER # ifdef _CPPRTTI // MSVC defines this macro iff RTTI is enabled. # define GTEST_HAS_RTTI 1 # else # define GTEST_HAS_RTTI 0 # endif // Starting with version 4.3.2, gcc defines __GXX_RTTI iff RTTI is enabled. # elif defined(__GNUC__) && (GTEST_GCC_VER_ >= 40302) # ifdef __GXX_RTTI // When building against STLport with the Android NDK and with // -frtti -fno-exceptions, the build fails at link time with undefined // references to __cxa_bad_typeid. Note sure if STL or toolchain bug, // so disable RTTI when detected. # if GTEST_OS_LINUX_ANDROID && defined(_STLPORT_MAJOR) && \ !defined(__EXCEPTIONS) # define GTEST_HAS_RTTI 0 # else # define GTEST_HAS_RTTI 1 # endif // GTEST_OS_LINUX_ANDROID && __STLPORT_MAJOR && !__EXCEPTIONS # else # define GTEST_HAS_RTTI 0 # endif // __GXX_RTTI // Clang defines __GXX_RTTI starting with version 3.0, but its manual recommends // using has_feature instead. has_feature(cxx_rtti) is supported since 2.7, the // first version with C++ support. # elif defined(__clang__) # define GTEST_HAS_RTTI __has_feature(cxx_rtti) // Starting with version 9.0 IBM Visual Age defines __RTTI_ALL__ to 1 if // both the typeid and dynamic_cast features are present. # elif defined(__IBMCPP__) && (__IBMCPP__ >= 900) # ifdef __RTTI_ALL__ # define GTEST_HAS_RTTI 1 # else # define GTEST_HAS_RTTI 0 # endif # else // For all other compilers, we assume RTTI is enabled. # define GTEST_HAS_RTTI 1 # endif // _MSC_VER #endif // GTEST_HAS_RTTI // It's this header's responsibility to #include when RTTI // is enabled. #if GTEST_HAS_RTTI # include #endif // Determines whether Google Test can use the pthreads library. #ifndef GTEST_HAS_PTHREAD // The user didn't tell us explicitly, so we assume pthreads support is // available on Linux and Mac. // // To disable threading support in Google Test, add -DGTEST_HAS_PTHREAD=0 // to your compiler flags. # define GTEST_HAS_PTHREAD (GTEST_OS_LINUX || GTEST_OS_MAC || GTEST_OS_HPUX \ || GTEST_OS_QNX) #endif // GTEST_HAS_PTHREAD #if GTEST_HAS_PTHREAD // gtest-port.h guarantees to #include when GTEST_HAS_PTHREAD is // true. # include // NOLINT // For timespec and nanosleep, used below. # include // NOLINT #endif // Determines whether Google Test can use tr1/tuple. You can define // this macro to 0 to prevent Google Test from using tuple (any // feature depending on tuple with be disabled in this mode). #ifndef GTEST_HAS_TR1_TUPLE # if GTEST_OS_LINUX_ANDROID && defined(_STLPORT_MAJOR) // STLport, provided with the Android NDK, has neither or . # define GTEST_HAS_TR1_TUPLE 0 # else // The user didn't tell us not to do it, so we assume it's OK. # define GTEST_HAS_TR1_TUPLE 1 # endif #endif // GTEST_HAS_TR1_TUPLE // Determines whether Google Test's own tr1 tuple implementation // should be used. #ifndef GTEST_USE_OWN_TR1_TUPLE // The user didn't tell us, so we need to figure it out. // We use our own TR1 tuple if we aren't sure the user has an // implementation of it already. At this time, libstdc++ 4.0.0+ and // MSVC 2010 are the only mainstream standard libraries that come // with a TR1 tuple implementation. NVIDIA's CUDA NVCC compiler // pretends to be GCC by defining __GNUC__ and friends, but cannot // compile GCC's tuple implementation. MSVC 2008 (9.0) provides TR1 // tuple in a 323 MB Feature Pack download, which we cannot assume the // user has. QNX's QCC compiler is a modified GCC but it doesn't // support TR1 tuple. libc++ only provides std::tuple, in C++11 mode, // and it can be used with some compilers that define __GNUC__. # if (defined(__GNUC__) && !defined(__CUDACC__) && (GTEST_GCC_VER_ >= 40000) \ && !GTEST_OS_QNX && !defined(_LIBCPP_VERSION)) || _MSC_VER >= 1600 # define GTEST_ENV_HAS_TR1_TUPLE_ 1 # endif // C++11 specifies that provides std::tuple. Use that if gtest is used // in C++11 mode and libstdc++ isn't very old (binaries targeting OS X 10.6 // can build with clang but need to use gcc4.2's libstdc++). # if GTEST_LANG_CXX11 && (!defined(__GLIBCXX__) || __GLIBCXX__ > 20110325) # define GTEST_ENV_HAS_STD_TUPLE_ 1 # endif # if GTEST_ENV_HAS_TR1_TUPLE_ || GTEST_ENV_HAS_STD_TUPLE_ # define GTEST_USE_OWN_TR1_TUPLE 0 # else # define GTEST_USE_OWN_TR1_TUPLE 1 # endif #endif // GTEST_USE_OWN_TR1_TUPLE // To avoid conditional compilation everywhere, we make it // gtest-port.h's responsibility to #include the header implementing // tr1/tuple. #if GTEST_HAS_TR1_TUPLE # if GTEST_USE_OWN_TR1_TUPLE // This file was GENERATED by command: // pump.py gtest-tuple.h.pump // DO NOT EDIT BY HAND!!! // Copyright 2009 Google Inc. // All Rights Reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // Author: wan@google.com (Zhanyong Wan) // Implements a subset of TR1 tuple needed by Google Test and Google Mock. #ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TUPLE_H_ #define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TUPLE_H_ #include // For ::std::pair. // The compiler used in Symbian has a bug that prevents us from declaring the // tuple template as a friend (it complains that tuple is redefined). This // hack bypasses the bug by declaring the members that should otherwise be // private as public. // Sun Studio versions < 12 also have the above bug. #if defined(__SYMBIAN32__) || (defined(__SUNPRO_CC) && __SUNPRO_CC < 0x590) # define GTEST_DECLARE_TUPLE_AS_FRIEND_ public: #else # define GTEST_DECLARE_TUPLE_AS_FRIEND_ \ template friend class tuple; \ private: #endif // GTEST_n_TUPLE_(T) is the type of an n-tuple. #define GTEST_0_TUPLE_(T) tuple<> #define GTEST_1_TUPLE_(T) tuple #define GTEST_2_TUPLE_(T) tuple #define GTEST_3_TUPLE_(T) tuple #define GTEST_4_TUPLE_(T) tuple #define GTEST_5_TUPLE_(T) tuple #define GTEST_6_TUPLE_(T) tuple #define GTEST_7_TUPLE_(T) tuple #define GTEST_8_TUPLE_(T) tuple #define GTEST_9_TUPLE_(T) tuple #define GTEST_10_TUPLE_(T) tuple // GTEST_n_TYPENAMES_(T) declares a list of n typenames. #define GTEST_0_TYPENAMES_(T) #define GTEST_1_TYPENAMES_(T) typename T##0 #define GTEST_2_TYPENAMES_(T) typename T##0, typename T##1 #define GTEST_3_TYPENAMES_(T) typename T##0, typename T##1, typename T##2 #define GTEST_4_TYPENAMES_(T) typename T##0, typename T##1, typename T##2, \ typename T##3 #define GTEST_5_TYPENAMES_(T) typename T##0, typename T##1, typename T##2, \ typename T##3, typename T##4 #define GTEST_6_TYPENAMES_(T) typename T##0, typename T##1, typename T##2, \ typename T##3, typename T##4, typename T##5 #define GTEST_7_TYPENAMES_(T) typename T##0, typename T##1, typename T##2, \ typename T##3, typename T##4, typename T##5, typename T##6 #define GTEST_8_TYPENAMES_(T) typename T##0, typename T##1, typename T##2, \ typename T##3, typename T##4, typename T##5, typename T##6, typename T##7 #define GTEST_9_TYPENAMES_(T) typename T##0, typename T##1, typename T##2, \ typename T##3, typename T##4, typename T##5, typename T##6, \ typename T##7, typename T##8 #define GTEST_10_TYPENAMES_(T) typename T##0, typename T##1, typename T##2, \ typename T##3, typename T##4, typename T##5, typename T##6, \ typename T##7, typename T##8, typename T##9 // In theory, defining stuff in the ::std namespace is undefined // behavior. We can do this as we are playing the role of a standard // library vendor. namespace std { namespace tr1 { template class tuple; // Anything in namespace gtest_internal is Google Test's INTERNAL // IMPLEMENTATION DETAIL and MUST NOT BE USED DIRECTLY in user code. namespace gtest_internal { // ByRef::type is T if T is a reference; otherwise it's const T&. template struct ByRef { typedef const T& type; }; // NOLINT template struct ByRef { typedef T& type; }; // NOLINT // A handy wrapper for ByRef. #define GTEST_BY_REF_(T) typename ::stdt::gtest_internal::ByRef::type // AddRef::type is T if T is a reference; otherwise it's T&. This // is the same as tr1::add_reference::type. template struct AddRef { typedef T& type; }; // NOLINT template struct AddRef { typedef T& type; }; // NOLINT // A handy wrapper for AddRef. #define GTEST_ADD_REF_(T) typename ::stdt::gtest_internal::AddRef::type // A helper for implementing get(). template class Get; // A helper for implementing tuple_element. kIndexValid is true // iff k < the number of fields in tuple type T. template struct TupleElement; template struct TupleElement { typedef T0 type; }; template struct TupleElement { typedef T1 type; }; template struct TupleElement { typedef T2 type; }; template struct TupleElement { typedef T3 type; }; template struct TupleElement { typedef T4 type; }; template struct TupleElement { typedef T5 type; }; template struct TupleElement { typedef T6 type; }; template struct TupleElement { typedef T7 type; }; template struct TupleElement { typedef T8 type; }; template struct TupleElement { typedef T9 type; }; } // namespace gtest_internal template <> class tuple<> { public: tuple() {} tuple(const tuple& /* t */) {} tuple& operator=(const tuple& /* t */) { return *this; } }; template class GTEST_1_TUPLE_(T) { public: template friend class gtest_internal::Get; tuple() : f0_() {} explicit tuple(GTEST_BY_REF_(T0) f0) : f0_(f0) {} tuple(const tuple& t) : f0_(t.f0_) {} template tuple(const GTEST_1_TUPLE_(U)& t) : f0_(t.f0_) {} tuple& operator=(const tuple& t) { return CopyFrom(t); } template tuple& operator=(const GTEST_1_TUPLE_(U)& t) { return CopyFrom(t); } GTEST_DECLARE_TUPLE_AS_FRIEND_ template tuple& CopyFrom(const GTEST_1_TUPLE_(U)& t) { f0_ = t.f0_; return *this; } T0 f0_; }; template class GTEST_2_TUPLE_(T) { public: template friend class gtest_internal::Get; tuple() : f0_(), f1_() {} explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1) : f0_(f0), f1_(f1) {} tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_) {} template tuple(const GTEST_2_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_) {} template tuple(const ::std::pair& p) : f0_(p.first), f1_(p.second) {} tuple& operator=(const tuple& t) { return CopyFrom(t); } template tuple& operator=(const GTEST_2_TUPLE_(U)& t) { return CopyFrom(t); } template tuple& operator=(const ::std::pair& p) { f0_ = p.first; f1_ = p.second; return *this; } GTEST_DECLARE_TUPLE_AS_FRIEND_ template tuple& CopyFrom(const GTEST_2_TUPLE_(U)& t) { f0_ = t.f0_; f1_ = t.f1_; return *this; } T0 f0_; T1 f1_; }; template class GTEST_3_TUPLE_(T) { public: template friend class gtest_internal::Get; tuple() : f0_(), f1_(), f2_() {} explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1, GTEST_BY_REF_(T2) f2) : f0_(f0), f1_(f1), f2_(f2) {} tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_) {} template tuple(const GTEST_3_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_) {} tuple& operator=(const tuple& t) { return CopyFrom(t); } template tuple& operator=(const GTEST_3_TUPLE_(U)& t) { return CopyFrom(t); } GTEST_DECLARE_TUPLE_AS_FRIEND_ template tuple& CopyFrom(const GTEST_3_TUPLE_(U)& t) { f0_ = t.f0_; f1_ = t.f1_; f2_ = t.f2_; return *this; } T0 f0_; T1 f1_; T2 f2_; }; template class GTEST_4_TUPLE_(T) { public: template friend class gtest_internal::Get; tuple() : f0_(), f1_(), f2_(), f3_() {} explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1, GTEST_BY_REF_(T2) f2, GTEST_BY_REF_(T3) f3) : f0_(f0), f1_(f1), f2_(f2), f3_(f3) {} tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), f3_(t.f3_) {} template tuple(const GTEST_4_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), f3_(t.f3_) {} tuple& operator=(const tuple& t) { return CopyFrom(t); } template tuple& operator=(const GTEST_4_TUPLE_(U)& t) { return CopyFrom(t); } GTEST_DECLARE_TUPLE_AS_FRIEND_ template tuple& CopyFrom(const GTEST_4_TUPLE_(U)& t) { f0_ = t.f0_; f1_ = t.f1_; f2_ = t.f2_; f3_ = t.f3_; return *this; } T0 f0_; T1 f1_; T2 f2_; T3 f3_; }; template class GTEST_5_TUPLE_(T) { public: template friend class gtest_internal::Get; tuple() : f0_(), f1_(), f2_(), f3_(), f4_() {} explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1, GTEST_BY_REF_(T2) f2, GTEST_BY_REF_(T3) f3, GTEST_BY_REF_(T4) f4) : f0_(f0), f1_(f1), f2_(f2), f3_(f3), f4_(f4) {} tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), f3_(t.f3_), f4_(t.f4_) {} template tuple(const GTEST_5_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), f3_(t.f3_), f4_(t.f4_) {} tuple& operator=(const tuple& t) { return CopyFrom(t); } template tuple& operator=(const GTEST_5_TUPLE_(U)& t) { return CopyFrom(t); } GTEST_DECLARE_TUPLE_AS_FRIEND_ template tuple& CopyFrom(const GTEST_5_TUPLE_(U)& t) { f0_ = t.f0_; f1_ = t.f1_; f2_ = t.f2_; f3_ = t.f3_; f4_ = t.f4_; return *this; } T0 f0_; T1 f1_; T2 f2_; T3 f3_; T4 f4_; }; template class GTEST_6_TUPLE_(T) { public: template friend class gtest_internal::Get; tuple() : f0_(), f1_(), f2_(), f3_(), f4_(), f5_() {} explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1, GTEST_BY_REF_(T2) f2, GTEST_BY_REF_(T3) f3, GTEST_BY_REF_(T4) f4, GTEST_BY_REF_(T5) f5) : f0_(f0), f1_(f1), f2_(f2), f3_(f3), f4_(f4), f5_(f5) {} tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), f3_(t.f3_), f4_(t.f4_), f5_(t.f5_) {} template tuple(const GTEST_6_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), f3_(t.f3_), f4_(t.f4_), f5_(t.f5_) {} tuple& operator=(const tuple& t) { return CopyFrom(t); } template tuple& operator=(const GTEST_6_TUPLE_(U)& t) { return CopyFrom(t); } GTEST_DECLARE_TUPLE_AS_FRIEND_ template tuple& CopyFrom(const GTEST_6_TUPLE_(U)& t) { f0_ = t.f0_; f1_ = t.f1_; f2_ = t.f2_; f3_ = t.f3_; f4_ = t.f4_; f5_ = t.f5_; return *this; } T0 f0_; T1 f1_; T2 f2_; T3 f3_; T4 f4_; T5 f5_; }; template class GTEST_7_TUPLE_(T) { public: template friend class gtest_internal::Get; tuple() : f0_(), f1_(), f2_(), f3_(), f4_(), f5_(), f6_() {} explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1, GTEST_BY_REF_(T2) f2, GTEST_BY_REF_(T3) f3, GTEST_BY_REF_(T4) f4, GTEST_BY_REF_(T5) f5, GTEST_BY_REF_(T6) f6) : f0_(f0), f1_(f1), f2_(f2), f3_(f3), f4_(f4), f5_(f5), f6_(f6) {} tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), f3_(t.f3_), f4_(t.f4_), f5_(t.f5_), f6_(t.f6_) {} template tuple(const GTEST_7_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), f3_(t.f3_), f4_(t.f4_), f5_(t.f5_), f6_(t.f6_) {} tuple& operator=(const tuple& t) { return CopyFrom(t); } template tuple& operator=(const GTEST_7_TUPLE_(U)& t) { return CopyFrom(t); } GTEST_DECLARE_TUPLE_AS_FRIEND_ template tuple& CopyFrom(const GTEST_7_TUPLE_(U)& t) { f0_ = t.f0_; f1_ = t.f1_; f2_ = t.f2_; f3_ = t.f3_; f4_ = t.f4_; f5_ = t.f5_; f6_ = t.f6_; return *this; } T0 f0_; T1 f1_; T2 f2_; T3 f3_; T4 f4_; T5 f5_; T6 f6_; }; template class GTEST_8_TUPLE_(T) { public: template friend class gtest_internal::Get; tuple() : f0_(), f1_(), f2_(), f3_(), f4_(), f5_(), f6_(), f7_() {} explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1, GTEST_BY_REF_(T2) f2, GTEST_BY_REF_(T3) f3, GTEST_BY_REF_(T4) f4, GTEST_BY_REF_(T5) f5, GTEST_BY_REF_(T6) f6, GTEST_BY_REF_(T7) f7) : f0_(f0), f1_(f1), f2_(f2), f3_(f3), f4_(f4), f5_(f5), f6_(f6), f7_(f7) {} tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), f3_(t.f3_), f4_(t.f4_), f5_(t.f5_), f6_(t.f6_), f7_(t.f7_) {} template tuple(const GTEST_8_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), f3_(t.f3_), f4_(t.f4_), f5_(t.f5_), f6_(t.f6_), f7_(t.f7_) {} tuple& operator=(const tuple& t) { return CopyFrom(t); } template tuple& operator=(const GTEST_8_TUPLE_(U)& t) { return CopyFrom(t); } GTEST_DECLARE_TUPLE_AS_FRIEND_ template tuple& CopyFrom(const GTEST_8_TUPLE_(U)& t) { f0_ = t.f0_; f1_ = t.f1_; f2_ = t.f2_; f3_ = t.f3_; f4_ = t.f4_; f5_ = t.f5_; f6_ = t.f6_; f7_ = t.f7_; return *this; } T0 f0_; T1 f1_; T2 f2_; T3 f3_; T4 f4_; T5 f5_; T6 f6_; T7 f7_; }; template class GTEST_9_TUPLE_(T) { public: template friend class gtest_internal::Get; tuple() : f0_(), f1_(), f2_(), f3_(), f4_(), f5_(), f6_(), f7_(), f8_() {} explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1, GTEST_BY_REF_(T2) f2, GTEST_BY_REF_(T3) f3, GTEST_BY_REF_(T4) f4, GTEST_BY_REF_(T5) f5, GTEST_BY_REF_(T6) f6, GTEST_BY_REF_(T7) f7, GTEST_BY_REF_(T8) f8) : f0_(f0), f1_(f1), f2_(f2), f3_(f3), f4_(f4), f5_(f5), f6_(f6), f7_(f7), f8_(f8) {} tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), f3_(t.f3_), f4_(t.f4_), f5_(t.f5_), f6_(t.f6_), f7_(t.f7_), f8_(t.f8_) {} template tuple(const GTEST_9_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), f3_(t.f3_), f4_(t.f4_), f5_(t.f5_), f6_(t.f6_), f7_(t.f7_), f8_(t.f8_) {} tuple& operator=(const tuple& t) { return CopyFrom(t); } template tuple& operator=(const GTEST_9_TUPLE_(U)& t) { return CopyFrom(t); } GTEST_DECLARE_TUPLE_AS_FRIEND_ template tuple& CopyFrom(const GTEST_9_TUPLE_(U)& t) { f0_ = t.f0_; f1_ = t.f1_; f2_ = t.f2_; f3_ = t.f3_; f4_ = t.f4_; f5_ = t.f5_; f6_ = t.f6_; f7_ = t.f7_; f8_ = t.f8_; return *this; } T0 f0_; T1 f1_; T2 f2_; T3 f3_; T4 f4_; T5 f5_; T6 f6_; T7 f7_; T8 f8_; }; template class tuple { public: template friend class gtest_internal::Get; tuple() : f0_(), f1_(), f2_(), f3_(), f4_(), f5_(), f6_(), f7_(), f8_(), f9_() {} explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1, GTEST_BY_REF_(T2) f2, GTEST_BY_REF_(T3) f3, GTEST_BY_REF_(T4) f4, GTEST_BY_REF_(T5) f5, GTEST_BY_REF_(T6) f6, GTEST_BY_REF_(T7) f7, GTEST_BY_REF_(T8) f8, GTEST_BY_REF_(T9) f9) : f0_(f0), f1_(f1), f2_(f2), f3_(f3), f4_(f4), f5_(f5), f6_(f6), f7_(f7), f8_(f8), f9_(f9) {} tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), f3_(t.f3_), f4_(t.f4_), f5_(t.f5_), f6_(t.f6_), f7_(t.f7_), f8_(t.f8_), f9_(t.f9_) {} template tuple(const GTEST_10_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), f3_(t.f3_), f4_(t.f4_), f5_(t.f5_), f6_(t.f6_), f7_(t.f7_), f8_(t.f8_), f9_(t.f9_) {} tuple& operator=(const tuple& t) { return CopyFrom(t); } template tuple& operator=(const GTEST_10_TUPLE_(U)& t) { return CopyFrom(t); } GTEST_DECLARE_TUPLE_AS_FRIEND_ template tuple& CopyFrom(const GTEST_10_TUPLE_(U)& t) { f0_ = t.f0_; f1_ = t.f1_; f2_ = t.f2_; f3_ = t.f3_; f4_ = t.f4_; f5_ = t.f5_; f6_ = t.f6_; f7_ = t.f7_; f8_ = t.f8_; f9_ = t.f9_; return *this; } T0 f0_; T1 f1_; T2 f2_; T3 f3_; T4 f4_; T5 f5_; T6 f6_; T7 f7_; T8 f8_; T9 f9_; }; // 6.1.3.2 Tuple creation functions. // Known limitations: we don't support passing an // stdt::reference_wrapper to make_tuple(). And we don't // implement tie(). inline tuple<> make_tuple() { return tuple<>(); } template inline GTEST_1_TUPLE_(T) make_tuple(const T0& f0) { return GTEST_1_TUPLE_(T)(f0); } template inline GTEST_2_TUPLE_(T) make_tuple(const T0& f0, const T1& f1) { return GTEST_2_TUPLE_(T)(f0, f1); } template inline GTEST_3_TUPLE_(T) make_tuple(const T0& f0, const T1& f1, const T2& f2) { return GTEST_3_TUPLE_(T)(f0, f1, f2); } template inline GTEST_4_TUPLE_(T) make_tuple(const T0& f0, const T1& f1, const T2& f2, const T3& f3) { return GTEST_4_TUPLE_(T)(f0, f1, f2, f3); } template inline GTEST_5_TUPLE_(T) make_tuple(const T0& f0, const T1& f1, const T2& f2, const T3& f3, const T4& f4) { return GTEST_5_TUPLE_(T)(f0, f1, f2, f3, f4); } template inline GTEST_6_TUPLE_(T) make_tuple(const T0& f0, const T1& f1, const T2& f2, const T3& f3, const T4& f4, const T5& f5) { return GTEST_6_TUPLE_(T)(f0, f1, f2, f3, f4, f5); } template inline GTEST_7_TUPLE_(T) make_tuple(const T0& f0, const T1& f1, const T2& f2, const T3& f3, const T4& f4, const T5& f5, const T6& f6) { return GTEST_7_TUPLE_(T)(f0, f1, f2, f3, f4, f5, f6); } template inline GTEST_8_TUPLE_(T) make_tuple(const T0& f0, const T1& f1, const T2& f2, const T3& f3, const T4& f4, const T5& f5, const T6& f6, const T7& f7) { return GTEST_8_TUPLE_(T)(f0, f1, f2, f3, f4, f5, f6, f7); } template inline GTEST_9_TUPLE_(T) make_tuple(const T0& f0, const T1& f1, const T2& f2, const T3& f3, const T4& f4, const T5& f5, const T6& f6, const T7& f7, const T8& f8) { return GTEST_9_TUPLE_(T)(f0, f1, f2, f3, f4, f5, f6, f7, f8); } template inline GTEST_10_TUPLE_(T) make_tuple(const T0& f0, const T1& f1, const T2& f2, const T3& f3, const T4& f4, const T5& f5, const T6& f6, const T7& f7, const T8& f8, const T9& f9) { return GTEST_10_TUPLE_(T)(f0, f1, f2, f3, f4, f5, f6, f7, f8, f9); } // 6.1.3.3 Tuple helper classes. template struct tuple_size; template struct tuple_size { static const int value = 0; }; template struct tuple_size { static const int value = 1; }; template struct tuple_size { static const int value = 2; }; template struct tuple_size { static const int value = 3; }; template struct tuple_size { static const int value = 4; }; template struct tuple_size { static const int value = 5; }; template struct tuple_size { static const int value = 6; }; template struct tuple_size { static const int value = 7; }; template struct tuple_size { static const int value = 8; }; template struct tuple_size { static const int value = 9; }; template struct tuple_size { static const int value = 10; }; template struct tuple_element { typedef typename gtest_internal::TupleElement< k < (tuple_size::value), k, Tuple>::type type; }; #define GTEST_TUPLE_ELEMENT_(k, Tuple) typename tuple_element::type // 6.1.3.4 Element access. namespace gtest_internal { template <> class Get<0> { public: template static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(0, Tuple)) Field(Tuple& t) { return t.f0_; } // NOLINT template static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(0, Tuple)) ConstField(const Tuple& t) { return t.f0_; } }; template <> class Get<1> { public: template static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(1, Tuple)) Field(Tuple& t) { return t.f1_; } // NOLINT template static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(1, Tuple)) ConstField(const Tuple& t) { return t.f1_; } }; template <> class Get<2> { public: template static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(2, Tuple)) Field(Tuple& t) { return t.f2_; } // NOLINT template static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(2, Tuple)) ConstField(const Tuple& t) { return t.f2_; } }; template <> class Get<3> { public: template static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(3, Tuple)) Field(Tuple& t) { return t.f3_; } // NOLINT template static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(3, Tuple)) ConstField(const Tuple& t) { return t.f3_; } }; template <> class Get<4> { public: template static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(4, Tuple)) Field(Tuple& t) { return t.f4_; } // NOLINT template static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(4, Tuple)) ConstField(const Tuple& t) { return t.f4_; } }; template <> class Get<5> { public: template static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(5, Tuple)) Field(Tuple& t) { return t.f5_; } // NOLINT template static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(5, Tuple)) ConstField(const Tuple& t) { return t.f5_; } }; template <> class Get<6> { public: template static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(6, Tuple)) Field(Tuple& t) { return t.f6_; } // NOLINT template static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(6, Tuple)) ConstField(const Tuple& t) { return t.f6_; } }; template <> class Get<7> { public: template static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(7, Tuple)) Field(Tuple& t) { return t.f7_; } // NOLINT template static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(7, Tuple)) ConstField(const Tuple& t) { return t.f7_; } }; template <> class Get<8> { public: template static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(8, Tuple)) Field(Tuple& t) { return t.f8_; } // NOLINT template static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(8, Tuple)) ConstField(const Tuple& t) { return t.f8_; } }; template <> class Get<9> { public: template static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(9, Tuple)) Field(Tuple& t) { return t.f9_; } // NOLINT template static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(9, Tuple)) ConstField(const Tuple& t) { return t.f9_; } }; } // namespace gtest_internal template GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(k, GTEST_10_TUPLE_(T))) get(GTEST_10_TUPLE_(T)& t) { return gtest_internal::Get::Field(t); } template GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(k, GTEST_10_TUPLE_(T))) get(const GTEST_10_TUPLE_(T)& t) { return gtest_internal::Get::ConstField(t); } // 6.1.3.5 Relational operators // We only implement == and !=, as we don't have a need for the rest yet. namespace gtest_internal { // SameSizeTuplePrefixComparator::Eq(t1, t2) returns true if the // first k fields of t1 equals the first k fields of t2. // SameSizeTuplePrefixComparator(k1, k2) would be a compiler error if // k1 != k2. template struct SameSizeTuplePrefixComparator; template <> struct SameSizeTuplePrefixComparator<0, 0> { template static bool Eq(const Tuple1& /* t1 */, const Tuple2& /* t2 */) { return true; } }; template struct SameSizeTuplePrefixComparator { template static bool Eq(const Tuple1& t1, const Tuple2& t2) { return SameSizeTuplePrefixComparator::Eq(t1, t2) && ::stdt::get(t1) == ::stdt::get(t2); } }; } // namespace gtest_internal template inline bool operator==(const GTEST_10_TUPLE_(T)& t, const GTEST_10_TUPLE_(U)& u) { return gtest_internal::SameSizeTuplePrefixComparator< tuple_size::value, tuple_size::value>::Eq(t, u); } template inline bool operator!=(const GTEST_10_TUPLE_(T)& t, const GTEST_10_TUPLE_(U)& u) { return !(t == u); } // 6.1.4 Pairs. // Unimplemented. } // namespace tr1 } // namespace std #undef GTEST_0_TUPLE_ #undef GTEST_1_TUPLE_ #undef GTEST_2_TUPLE_ #undef GTEST_3_TUPLE_ #undef GTEST_4_TUPLE_ #undef GTEST_5_TUPLE_ #undef GTEST_6_TUPLE_ #undef GTEST_7_TUPLE_ #undef GTEST_8_TUPLE_ #undef GTEST_9_TUPLE_ #undef GTEST_10_TUPLE_ #undef GTEST_0_TYPENAMES_ #undef GTEST_1_TYPENAMES_ #undef GTEST_2_TYPENAMES_ #undef GTEST_3_TYPENAMES_ #undef GTEST_4_TYPENAMES_ #undef GTEST_5_TYPENAMES_ #undef GTEST_6_TYPENAMES_ #undef GTEST_7_TYPENAMES_ #undef GTEST_8_TYPENAMES_ #undef GTEST_9_TYPENAMES_ #undef GTEST_10_TYPENAMES_ #undef GTEST_DECLARE_TUPLE_AS_FRIEND_ #undef GTEST_BY_REF_ #undef GTEST_ADD_REF_ #undef GTEST_TUPLE_ELEMENT_ #endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TUPLE_H_ # elif GTEST_ENV_HAS_STD_TUPLE_ # include // C++11 puts its tuple into the ::std namespace rather than // ::std::tr1. gtest expects tuple to live in ::std::tr1, so put it there. // This causes undefined behavior, but supported compilers react in // the way we intend. namespace std { namespace tr1 { using ::std::get; using ::std::make_tuple; using ::std::tuple; using ::std::tuple_element; using ::std::tuple_size; } } # elif GTEST_OS_SYMBIAN // On Symbian, BOOST_HAS_TR1_TUPLE causes Boost's TR1 tuple library to // use STLport's tuple implementation, which unfortunately doesn't // work as the copy of STLport distributed with Symbian is incomplete. // By making sure BOOST_HAS_TR1_TUPLE is undefined, we force Boost to // use its own tuple implementation. # ifdef BOOST_HAS_TR1_TUPLE # undef BOOST_HAS_TR1_TUPLE # endif // BOOST_HAS_TR1_TUPLE // This prevents , which defines // BOOST_HAS_TR1_TUPLE, from being #included by Boost's . # define BOOST_TR1_DETAIL_CONFIG_HPP_INCLUDED # include # elif defined(__GNUC__) && (GTEST_GCC_VER_ >= 40000) // GCC 4.0+ implements tr1/tuple in the header. This does // not conform to the TR1 spec, which requires the header to be . # if !GTEST_HAS_RTTI && GTEST_GCC_VER_ < 40302 // Until version 4.3.2, gcc has a bug that causes , // which is #included by , to not compile when RTTI is // disabled. _TR1_FUNCTIONAL is the header guard for // . Hence the following #define is a hack to prevent // from being included. # define _TR1_FUNCTIONAL 1 # include # undef _TR1_FUNCTIONAL // Allows the user to #include // if he chooses to. # else # include // NOLINT # endif // !GTEST_HAS_RTTI && GTEST_GCC_VER_ < 40302 # else // If the compiler is not GCC 4.0+, we assume the user is using a // spec-conforming TR1 implementation. # include // NOLINT # endif // GTEST_USE_OWN_TR1_TUPLE #endif // GTEST_HAS_TR1_TUPLE // Determines whether clone(2) is supported. // Usually it will only be available on Linux, excluding // Linux on the Itanium architecture. // Also see http://linux.die.net/man/2/clone. #ifndef GTEST_HAS_CLONE // The user didn't tell us, so we need to figure it out. # if GTEST_OS_LINUX && !defined(__ia64__) # if GTEST_OS_LINUX_ANDROID // On Android, clone() is only available on ARM starting with Gingerbread. # if defined(__arm__) && __ANDROID_API__ >= 9 # define GTEST_HAS_CLONE 1 # else # define GTEST_HAS_CLONE 0 # endif # else # define GTEST_HAS_CLONE 1 # endif # else # define GTEST_HAS_CLONE 0 # endif // GTEST_OS_LINUX && !defined(__ia64__) #endif // GTEST_HAS_CLONE // Determines whether to support stream redirection. This is used to test // output correctness and to implement death tests. #ifndef GTEST_HAS_STREAM_REDIRECTION // By default, we assume that stream redirection is supported on all // platforms except known mobile ones. # if GTEST_OS_WINDOWS_MOBILE || GTEST_OS_SYMBIAN # define GTEST_HAS_STREAM_REDIRECTION 0 # else # define GTEST_HAS_STREAM_REDIRECTION 1 # endif // !GTEST_OS_WINDOWS_MOBILE && !GTEST_OS_SYMBIAN #endif // GTEST_HAS_STREAM_REDIRECTION // Determines whether to support death tests. // Google Test does not support death tests for VC 7.1 and earlier as // abort() in a VC 7.1 application compiled as GUI in debug config // pops up a dialog window that cannot be suppressed programmatically. #if (GTEST_OS_LINUX || GTEST_OS_CYGWIN || GTEST_OS_SOLARIS || \ (GTEST_OS_MAC && !GTEST_OS_IOS) || GTEST_OS_IOS_SIMULATOR || \ (GTEST_OS_WINDOWS_DESKTOP && _MSC_VER >= 1400) || \ GTEST_OS_WINDOWS_MINGW || GTEST_OS_AIX || GTEST_OS_HPUX || \ GTEST_OS_OPENBSD || GTEST_OS_QNX) # define GTEST_HAS_DEATH_TEST 1 # include // NOLINT #endif // We don't support MSVC 7.1 with exceptions disabled now. Therefore // all the compilers we care about are adequate for supporting // value-parameterized tests. #define GTEST_HAS_PARAM_TEST 1 // Determines whether to support type-driven tests. // Typed tests need and variadic macros, which GCC, VC++ 8.0, // Sun Pro CC, IBM Visual Age, and HP aCC support. #if defined(__GNUC__) || (_MSC_VER >= 1400) || defined(__SUNPRO_CC) || \ defined(__IBMCPP__) || defined(__HP_aCC) # define GTEST_HAS_TYPED_TEST 1 # define GTEST_HAS_TYPED_TEST_P 1 #endif // Determines whether to support Combine(). This only makes sense when // value-parameterized tests are enabled. The implementation doesn't // work on Sun Studio since it doesn't understand templated conversion // operators. #if GTEST_HAS_PARAM_TEST && GTEST_HAS_TR1_TUPLE && !defined(__SUNPRO_CC) # define GTEST_HAS_COMBINE 1 #endif // Determines whether the system compiler uses UTF-16 for encoding wide strings. #define GTEST_WIDE_STRING_USES_UTF16_ \ (GTEST_OS_WINDOWS || GTEST_OS_CYGWIN || GTEST_OS_SYMBIAN || GTEST_OS_AIX) // Determines whether test results can be streamed to a socket. #if GTEST_OS_LINUX # define GTEST_CAN_STREAM_RESULTS_ 1 #endif // Defines some utility macros. // The GNU compiler emits a warning if nested "if" statements are followed by // an "else" statement and braces are not used to explicitly disambiguate the // "else" binding. This leads to problems with code like: // // if (gate) // ASSERT_*(condition) << "Some message"; // // The "switch (0) case 0:" idiom is used to suppress this. #ifdef __INTEL_COMPILER # define GTEST_AMBIGUOUS_ELSE_BLOCKER_ #else # define GTEST_AMBIGUOUS_ELSE_BLOCKER_ switch (0) case 0: default: // NOLINT #endif // Use this annotation at the end of a struct/class definition to // prevent the compiler from optimizing away instances that are never // used. This is useful when all interesting logic happens inside the // c'tor and / or d'tor. Example: // // struct Foo { // Foo() { ... } // } GTEST_ATTRIBUTE_UNUSED_; // // Also use it after a variable or parameter declaration to tell the // compiler the variable/parameter does not have to be used. #if defined(__GNUC__) && !defined(COMPILER_ICC) # define GTEST_ATTRIBUTE_UNUSED_ __attribute__ ((unused)) #else # define GTEST_ATTRIBUTE_UNUSED_ #endif // A macro to disallow operator= // This should be used in the private: declarations for a class. #define GTEST_DISALLOW_ASSIGN_(type)\ void operator=(type const &) // A macro to disallow copy constructor and operator= // This should be used in the private: declarations for a class. #define GTEST_DISALLOW_COPY_AND_ASSIGN_(type)\ type(type const &); \ GTEST_DISALLOW_ASSIGN_(type) // Tell the compiler to warn about unused return values for functions declared // with this macro. The macro should be used on function declarations // following the argument list: // // Sprocket* AllocateSprocket() GTEST_MUST_USE_RESULT_; #if defined(__GNUC__) && (GTEST_GCC_VER_ >= 30400) && !defined(COMPILER_ICC) # define GTEST_MUST_USE_RESULT_ __attribute__ ((warn_unused_result)) #else # define GTEST_MUST_USE_RESULT_ #endif // __GNUC__ && (GTEST_GCC_VER_ >= 30400) && !COMPILER_ICC // Determine whether the compiler supports Microsoft's Structured Exception // Handling. This is supported by several Windows compilers but generally // does not exist on any other system. #ifndef GTEST_HAS_SEH // The user didn't tell us, so we need to figure it out. # if defined(_MSC_VER) || defined(__BORLANDC__) // These two compilers are known to support SEH. # define GTEST_HAS_SEH 1 # else // Assume no SEH. # define GTEST_HAS_SEH 0 # endif #endif // GTEST_HAS_SEH #ifdef _MSC_VER # if GTEST_LINKED_AS_SHARED_LIBRARY # define GTEST_API_ __declspec(dllimport) # elif GTEST_CREATE_SHARED_LIBRARY # define GTEST_API_ __declspec(dllexport) # endif #endif // _MSC_VER #ifndef GTEST_API_ # define GTEST_API_ #endif #ifdef __GNUC__ // Ask the compiler to never inline a given function. # define GTEST_NO_INLINE_ __attribute__((noinline)) #else # define GTEST_NO_INLINE_ #endif // _LIBCPP_VERSION is defined by the libc++ library from the LLVM project. #if defined(__GLIBCXX__) || defined(_LIBCPP_VERSION) # define GTEST_HAS_CXXABI_H_ 1 #else # define GTEST_HAS_CXXABI_H_ 0 #endif namespace testing { class Message; namespace internal { // A secret type that Google Test users don't know about. It has no // definition on purpose. Therefore it's impossible to create a // Secret object, which is what we want. class Secret; // The GTEST_COMPILE_ASSERT_ macro can be used to verify that a compile time // expression is true. For example, you could use it to verify the // size of a static array: // // GTEST_COMPILE_ASSERT_(ARRAYSIZE(content_type_names) == CONTENT_NUM_TYPES, // content_type_names_incorrect_size); // // or to make sure a struct is smaller than a certain size: // // GTEST_COMPILE_ASSERT_(sizeof(foo) < 128, foo_too_large); // // The second argument to the macro is the name of the variable. If // the expression is false, most compilers will issue a warning/error // containing the name of the variable. template struct CompileAssert { }; #define GTEST_COMPILE_ASSERT_(expr, msg) \ typedef ::testing::internal::CompileAssert<(static_cast(expr))> \ msg[static_cast(expr) ? 1 : -1] GTEST_ATTRIBUTE_UNUSED_ // Implementation details of GTEST_COMPILE_ASSERT_: // // - GTEST_COMPILE_ASSERT_ works by defining an array type that has -1 // elements (and thus is invalid) when the expression is false. // // - The simpler definition // // #define GTEST_COMPILE_ASSERT_(expr, msg) typedef char msg[(expr) ? 1 : -1] // // does not work, as gcc supports variable-length arrays whose sizes // are determined at run-time (this is gcc's extension and not part // of the C++ standard). As a result, gcc fails to reject the // following code with the simple definition: // // int foo; // GTEST_COMPILE_ASSERT_(foo, msg); // not supposed to compile as foo is // // not a compile-time constant. // // - By using the type CompileAssert<(bool(expr))>, we ensures that // expr is a compile-time constant. (Template arguments must be // determined at compile-time.) // // - The outter parentheses in CompileAssert<(bool(expr))> are necessary // to work around a bug in gcc 3.4.4 and 4.0.1. If we had written // // CompileAssert // // instead, these compilers will refuse to compile // // GTEST_COMPILE_ASSERT_(5 > 0, some_message); // // (They seem to think the ">" in "5 > 0" marks the end of the // template argument list.) // // - The array size is (bool(expr) ? 1 : -1), instead of simply // // ((expr) ? 1 : -1). // // This is to avoid running into a bug in MS VC 7.1, which // causes ((0.0) ? 1 : -1) to incorrectly evaluate to 1. // StaticAssertTypeEqHelper is used by StaticAssertTypeEq defined in gtest.h. // // This template is declared, but intentionally undefined. template struct StaticAssertTypeEqHelper; template struct StaticAssertTypeEqHelper {}; #if GTEST_HAS_GLOBAL_STRING typedef ::string string; #else typedef ::std::string string; #endif // GTEST_HAS_GLOBAL_STRING #if GTEST_HAS_GLOBAL_WSTRING typedef ::wstring wstring; #elif GTEST_HAS_STD_WSTRING typedef ::std::wstring wstring; #endif // GTEST_HAS_GLOBAL_WSTRING // A helper for suppressing warnings on constant condition. It just // returns 'condition'. GTEST_API_ bool IsTrue(bool condition); // Defines scoped_ptr. // This implementation of scoped_ptr is PARTIAL - it only contains // enough stuff to satisfy Google Test's need. template class scoped_ptr { public: typedef T element_type; explicit scoped_ptr(T* p = NULL) : ptr_(p) {} ~scoped_ptr() { reset(); } T& operator*() const { return *ptr_; } T* operator->() const { return ptr_; } T* get() const { return ptr_; } T* release() { T* const ptr = ptr_; ptr_ = NULL; return ptr; } void reset(T* p = NULL) { if (p != ptr_) { if (IsTrue(sizeof(T) > 0)) { // Makes sure T is a complete type. delete ptr_; } ptr_ = p; } } private: T* ptr_; GTEST_DISALLOW_COPY_AND_ASSIGN_(scoped_ptr); }; // Defines RE. // A simple C++ wrapper for . It uses the POSIX Extended // Regular Expression syntax. class GTEST_API_ RE { public: // A copy constructor is required by the Standard to initialize object // references from r-values. RE(const RE& other) { Init(other.pattern()); } // Constructs an RE from a string. RE(const ::std::string& regex) { Init(regex.c_str()); } // NOLINT #if GTEST_HAS_GLOBAL_STRING RE(const ::string& regex) { Init(regex.c_str()); } // NOLINT #endif // GTEST_HAS_GLOBAL_STRING RE(const char* regex) { Init(regex); } // NOLINT ~RE(); // Returns the string representation of the regex. const char* pattern() const { return pattern_; } // FullMatch(str, re) returns true iff regular expression re matches // the entire str. // PartialMatch(str, re) returns true iff regular expression re // matches a substring of str (including str itself). // // TODO(wan@google.com): make FullMatch() and PartialMatch() work // when str contains NUL characters. static bool FullMatch(const ::std::string& str, const RE& re) { return FullMatch(str.c_str(), re); } static bool PartialMatch(const ::std::string& str, const RE& re) { return PartialMatch(str.c_str(), re); } #if GTEST_HAS_GLOBAL_STRING static bool FullMatch(const ::string& str, const RE& re) { return FullMatch(str.c_str(), re); } static bool PartialMatch(const ::string& str, const RE& re) { return PartialMatch(str.c_str(), re); } #endif // GTEST_HAS_GLOBAL_STRING static bool FullMatch(const char* str, const RE& re); static bool PartialMatch(const char* str, const RE& re); private: void Init(const char* regex); // We use a const char* instead of an std::string, as Google Test used to be // used where std::string is not available. TODO(wan@google.com): change to // std::string. const char* pattern_; bool is_valid_; #if GTEST_USES_POSIX_RE regex_t full_regex_; // For FullMatch(). regex_t partial_regex_; // For PartialMatch(). #else // GTEST_USES_SIMPLE_RE const char* full_pattern_; // For FullMatch(); #endif GTEST_DISALLOW_ASSIGN_(RE); }; // Formats a source file path and a line number as they would appear // in an error message from the compiler used to compile this code. GTEST_API_::std::string FormatFileLocation(const char* file, int line); // Formats a file location for compiler-independent XML output. // Although this function is not platform dependent, we put it next to // FormatFileLocation in order to contrast the two functions. GTEST_API_::std::string FormatCompilerIndependentFileLocation(const char* file, int line); // Defines logging utilities: // GTEST_LOG_(severity) - logs messages at the specified severity level. The // message itself is streamed into the macro. // LogToStderr() - directs all log messages to stderr. // FlushInfoLog() - flushes informational log messages. enum GTestLogSeverity { GTEST_INFO, GTEST_WARNING, GTEST_ERROR, GTEST_FATAL }; // Formats log entry severity, provides a stream object for streaming the // log message, and terminates the message with a newline when going out of // scope. class GTEST_API_ GTestLog { public: GTestLog(GTestLogSeverity severity, const char* file, int line); // Flushes the buffers and, if severity is GTEST_FATAL, aborts the program. ~GTestLog(); ::std::ostream& GetStream() { return ::std::cerr; } private: const GTestLogSeverity severity_; GTEST_DISALLOW_COPY_AND_ASSIGN_(GTestLog); }; #define GTEST_LOG_(severity) \ ::testing::internal::GTestLog(::testing::internal::GTEST_##severity, \ __FILE__, __LINE__).GetStream() inline void LogToStderr() {} inline void FlushInfoLog() { fflush(NULL); } // INTERNAL IMPLEMENTATION - DO NOT USE. // // GTEST_CHECK_ is an all-mode assert. It aborts the program if the condition // is not satisfied. // Synopsys: // GTEST_CHECK_(boolean_condition); // or // GTEST_CHECK_(boolean_condition) << "Additional message"; // // This checks the condition and if the condition is not satisfied // it prints message about the condition violation, including the // condition itself, plus additional message streamed into it, if any, // and then it aborts the program. It aborts the program irrespective of // whether it is built in the debug mode or not. #define GTEST_CHECK_(condition) \ GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ if (::testing::internal::IsTrue(condition)) \ ; \ else \ GTEST_LOG_(FATAL) << "Condition " #condition " failed. " // An all-mode assert to verify that the given POSIX-style function // call returns 0 (indicating success). Known limitation: this // doesn't expand to a balanced 'if' statement, so enclose the macro // in {} if you need to use it as the only statement in an 'if' // branch. #define GTEST_CHECK_POSIX_SUCCESS_(posix_call) \ if (const int gtest_error = (posix_call)) \ GTEST_LOG_(FATAL) << #posix_call << "failed with error " \ << gtest_error // INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. // // Use ImplicitCast_ as a safe version of static_cast for upcasting in // the type hierarchy (e.g. casting a Foo* to a SuperclassOfFoo* or a // const Foo*). When you use ImplicitCast_, the compiler checks that // the cast is safe. Such explicit ImplicitCast_s are necessary in // surprisingly many situations where C++ demands an exact type match // instead of an argument type convertable to a target type. // // The syntax for using ImplicitCast_ is the same as for static_cast: // // ImplicitCast_(expr) // // ImplicitCast_ would have been part of the C++ standard library, // but the proposal was submitted too late. It will probably make // its way into the language in the future. // // This relatively ugly name is intentional. It prevents clashes with // similar functions users may have (e.g., implicit_cast). The internal // namespace alone is not enough because the function can be found by ADL. template inline To ImplicitCast_(To x) { return x; } // When you upcast (that is, cast a pointer from type Foo to type // SuperclassOfFoo), it's fine to use ImplicitCast_<>, since upcasts // always succeed. When you downcast (that is, cast a pointer from // type Foo to type SubclassOfFoo), static_cast<> isn't safe, because // how do you know the pointer is really of type SubclassOfFoo? It // could be a bare Foo, or of type DifferentSubclassOfFoo. Thus, // when you downcast, you should use this macro. In debug mode, we // use dynamic_cast<> to double-check the downcast is legal (we die // if it's not). In normal mode, we do the efficient static_cast<> // instead. Thus, it's important to test in debug mode to make sure // the cast is legal! // This is the only place in the code we should use dynamic_cast<>. // In particular, you SHOULDN'T be using dynamic_cast<> in order to // do RTTI (eg code like this: // if (dynamic_cast(foo)) HandleASubclass1Object(foo); // if (dynamic_cast(foo)) HandleASubclass2Object(foo); // You should design the code some other way not to need this. // // This relatively ugly name is intentional. It prevents clashes with // similar functions users may have (e.g., down_cast). The internal // namespace alone is not enough because the function can be found by ADL. template // use like this: DownCast_(foo); inline To DownCast_(From* f) { // so we only accept pointers // Ensures that To is a sub-type of From *. This test is here only // for compile-time type checking, and has no overhead in an // optimized build at run-time, as it will be optimized away // completely. if (false) { const To to = NULL; ::testing::internal::ImplicitCast_(to); } #if GTEST_HAS_RTTI // RTTI: debug mode only! GTEST_CHECK_(f == NULL || dynamic_cast(f) != NULL); #endif return static_cast(f); } // Downcasts the pointer of type Base to Derived. // Derived must be a subclass of Base. The parameter MUST // point to a class of type Derived, not any subclass of it. // When RTTI is available, the function performs a runtime // check to enforce this. template Derived* CheckedDowncastToActualType(Base* base) { #if GTEST_HAS_RTTI GTEST_CHECK_(typeid(*base) == typeid(Derived)); return dynamic_cast(base); // NOLINT #else return static_cast(base); // Poor man's downcast. #endif } #if GTEST_HAS_STREAM_REDIRECTION // Defines the stderr capturer: // CaptureStdout - starts capturing stdout. // GetCapturedStdout - stops capturing stdout and returns the captured string. // CaptureStderr - starts capturing stderr. // GetCapturedStderr - stops capturing stderr and returns the captured string. // GTEST_API_ void CaptureStdout(); GTEST_API_ std::string GetCapturedStdout(); GTEST_API_ void CaptureStderr(); GTEST_API_ std::string GetCapturedStderr(); #endif // GTEST_HAS_STREAM_REDIRECTION #if GTEST_HAS_DEATH_TEST const ::std::vector& GetInjectableArgvs(); void SetInjectableArgvs(const ::std::vector* new_argvs); // A copy of all command line arguments. Set by InitGoogleTest(). extern ::std::vector g_argvs; #endif // GTEST_HAS_DEATH_TEST // Defines synchronization primitives. #if GTEST_HAS_PTHREAD // Sleeps for (roughly) n milli-seconds. This function is only for // testing Google Test's own constructs. Don't use it in user tests, // either directly or indirectly. inline void SleepMilliseconds(int n) { const timespec time = { 0, // 0 seconds. n * 1000L * 1000L, // And n ms. }; nanosleep(&time, NULL); } // Allows a controller thread to pause execution of newly created // threads until notified. Instances of this class must be created // and destroyed in the controller thread. // // This class is only for testing Google Test's own constructs. Do not // use it in user tests, either directly or indirectly. class Notification { public: Notification() : notified_(false) { GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_init(&mutex_, NULL)); } ~Notification() { pthread_mutex_destroy(&mutex_); } // Notifies all threads created with this notification to start. Must // be called from the controller thread. void Notify() { pthread_mutex_lock(&mutex_); notified_ = true; pthread_mutex_unlock(&mutex_); } // Blocks until the controller thread notifies. Must be called from a test // thread. void WaitForNotification() { for (;;) { pthread_mutex_lock(&mutex_); const bool notified = notified_; pthread_mutex_unlock(&mutex_); if (notified) break; SleepMilliseconds(10); } } private: pthread_mutex_t mutex_; bool notified_; GTEST_DISALLOW_COPY_AND_ASSIGN_(Notification); }; // As a C-function, ThreadFuncWithCLinkage cannot be templated itself. // Consequently, it cannot select a correct instantiation of ThreadWithParam // in order to call its Run(). Introducing ThreadWithParamBase as a // non-templated base class for ThreadWithParam allows us to bypass this // problem. class ThreadWithParamBase { public: virtual ~ThreadWithParamBase() {} virtual void Run() = 0; }; // pthread_create() accepts a pointer to a function type with the C linkage. // According to the Standard (7.5/1), function types with different linkages // are different even if they are otherwise identical. Some compilers (for // example, SunStudio) treat them as different types. Since class methods // cannot be defined with C-linkage we need to define a free C-function to // pass into pthread_create(). extern "C" inline void* ThreadFuncWithCLinkage(void* thread) { static_cast(thread)->Run(); return NULL; } // Helper class for testing Google Test's multi-threading constructs. // To use it, write: // // void ThreadFunc(int param) { /* Do things with param */ } // Notification thread_can_start; // ... // // The thread_can_start parameter is optional; you can supply NULL. // ThreadWithParam thread(&ThreadFunc, 5, &thread_can_start); // thread_can_start.Notify(); // // These classes are only for testing Google Test's own constructs. Do // not use them in user tests, either directly or indirectly. template class ThreadWithParam : public ThreadWithParamBase { public: typedef void(*UserThreadFunc)(T); ThreadWithParam( UserThreadFunc func, T param, Notification* thread_can_start) : func_(func), param_(param), thread_can_start_(thread_can_start), finished_(false) { ThreadWithParamBase* const base = this; // The thread can be created only after all fields except thread_ // have been initialized. GTEST_CHECK_POSIX_SUCCESS_( pthread_create(&thread_, 0, &ThreadFuncWithCLinkage, base)); } ~ThreadWithParam() { Join(); } void Join() { if (!finished_) { GTEST_CHECK_POSIX_SUCCESS_(pthread_join(thread_, 0)); finished_ = true; } } virtual void Run() { if (thread_can_start_ != NULL) thread_can_start_->WaitForNotification(); func_(param_); } private: const UserThreadFunc func_; // User-supplied thread function. const T param_; // User-supplied parameter to the thread function. // When non-NULL, used to block execution until the controller thread // notifies. Notification* const thread_can_start_; bool finished_; // true iff we know that the thread function has finished. pthread_t thread_; // The native thread object. GTEST_DISALLOW_COPY_AND_ASSIGN_(ThreadWithParam); }; // MutexBase and Mutex implement mutex on pthreads-based platforms. They // are used in conjunction with class MutexLock: // // Mutex mutex; // ... // MutexLock lock(&mutex); // Acquires the mutex and releases it at the end // // of the current scope. // // MutexBase implements behavior for both statically and dynamically // allocated mutexes. Do not use MutexBase directly. Instead, write // the following to define a static mutex: // // GTEST_DEFINE_STATIC_MUTEX_(g_some_mutex); // // You can forward declare a static mutex like this: // // GTEST_DECLARE_STATIC_MUTEX_(g_some_mutex); // // To create a dynamic mutex, just define an object of type Mutex. class MutexBase { public: // Acquires this mutex. void Lock() { GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_lock(&mutex_)); owner_ = pthread_self(); has_owner_ = true; } // Releases this mutex. void Unlock() { // Since the lock is being released the owner_ field should no longer be // considered valid. We don't protect writing to has_owner_ here, as it's // the caller's responsibility to ensure that the current thread holds the // mutex when this is called. has_owner_ = false; GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_unlock(&mutex_)); } // Does nothing if the current thread holds the mutex. Otherwise, crashes // with high probability. void AssertHeld() const { GTEST_CHECK_(has_owner_ && pthread_equal(owner_, pthread_self())) << "The current thread is not holding the mutex @" << this; } // A static mutex may be used before main() is entered. It may even // be used before the dynamic initialization stage. Therefore we // must be able to initialize a static mutex object at link time. // This means MutexBase has to be a POD and its member variables // have to be public. public: pthread_mutex_t mutex_; // The underlying pthread mutex. // has_owner_ indicates whether the owner_ field below contains a valid thread // ID and is therefore safe to inspect (e.g., to use in pthread_equal()). All // accesses to the owner_ field should be protected by a check of this field. // An alternative might be to memset() owner_ to all zeros, but there's no // guarantee that a zero'd pthread_t is necessarily invalid or even different // from pthread_self(). bool has_owner_; pthread_t owner_; // The thread holding the mutex. }; // Forward-declares a static mutex. # define GTEST_DECLARE_STATIC_MUTEX_(mutex) \ extern ::testing::internal::MutexBase mutex // Defines and statically (i.e. at link time) initializes a static mutex. // The initialization list here does not explicitly initialize each field, // instead relying on default initialization for the unspecified fields. In // particular, the owner_ field (a pthread_t) is not explicitly initialized. // This allows initialization to work whether pthread_t is a scalar or struct. // The flag -Wmissing-field-initializers must not be specified for this to work. # define GTEST_DEFINE_STATIC_MUTEX_(mutex) \ ::testing::internal::MutexBase mutex = { PTHREAD_MUTEX_INITIALIZER, false } // The Mutex class can only be used for mutexes created at runtime. It // shares its API with MutexBase otherwise. class Mutex : public MutexBase { public: Mutex() { GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_init(&mutex_, NULL)); has_owner_ = false; } ~Mutex() { GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_destroy(&mutex_)); } private: GTEST_DISALLOW_COPY_AND_ASSIGN_(Mutex); }; // We cannot name this class MutexLock as the ctor declaration would // conflict with a macro named MutexLock, which is defined on some // platforms. Hence the typedef trick below. class GTestMutexLock { public: explicit GTestMutexLock(MutexBase* mutex) : mutex_(mutex) { mutex_->Lock(); } ~GTestMutexLock() { mutex_->Unlock(); } private: MutexBase* const mutex_; GTEST_DISALLOW_COPY_AND_ASSIGN_(GTestMutexLock); }; typedef GTestMutexLock MutexLock; // Helpers for ThreadLocal. // pthread_key_create() requires DeleteThreadLocalValue() to have // C-linkage. Therefore it cannot be templatized to access // ThreadLocal. Hence the need for class // ThreadLocalValueHolderBase. class ThreadLocalValueHolderBase { public: virtual ~ThreadLocalValueHolderBase() {} }; // Called by pthread to delete thread-local data stored by // pthread_setspecific(). extern "C" inline void DeleteThreadLocalValue(void* value_holder) { delete static_cast(value_holder); } // Implements thread-local storage on pthreads-based systems. // // // Thread 1 // ThreadLocal tl(100); // 100 is the default value for each thread. // // // Thread 2 // tl.set(150); // Changes the value for thread 2 only. // EXPECT_EQ(150, tl.get()); // // // Thread 1 // EXPECT_EQ(100, tl.get()); // In thread 1, tl has the original value. // tl.set(200); // EXPECT_EQ(200, tl.get()); // // The template type argument T must have a public copy constructor. // In addition, the default ThreadLocal constructor requires T to have // a public default constructor. // // An object managed for a thread by a ThreadLocal instance is deleted // when the thread exits. Or, if the ThreadLocal instance dies in // that thread, when the ThreadLocal dies. It's the user's // responsibility to ensure that all other threads using a ThreadLocal // have exited when it dies, or the per-thread objects for those // threads will not be deleted. // // Google Test only uses global ThreadLocal objects. That means they // will die after main() has returned. Therefore, no per-thread // object managed by Google Test will be leaked as long as all threads // using Google Test have exited when main() returns. template class ThreadLocal { public: ThreadLocal() : key_(CreateKey()), default_() {} explicit ThreadLocal(const T& value) : key_(CreateKey()), default_(value) {} ~ThreadLocal() { // Destroys the managed object for the current thread, if any. DeleteThreadLocalValue(pthread_getspecific(key_)); // Releases resources associated with the key. This will *not* // delete managed objects for other threads. GTEST_CHECK_POSIX_SUCCESS_(pthread_key_delete(key_)); } T* pointer() { return GetOrCreateValue(); } const T* pointer() const { return GetOrCreateValue(); } const T& get() const { return *pointer(); } void set(const T& value) { *pointer() = value; } private: // Holds a value of type T. class ValueHolder : public ThreadLocalValueHolderBase { public: explicit ValueHolder(const T& value) : value_(value) {} T* pointer() { return &value_; } private: T value_; GTEST_DISALLOW_COPY_AND_ASSIGN_(ValueHolder); }; static pthread_key_t CreateKey() { pthread_key_t key; // When a thread exits, DeleteThreadLocalValue() will be called on // the object managed for that thread. GTEST_CHECK_POSIX_SUCCESS_( pthread_key_create(&key, &DeleteThreadLocalValue)); return key; } T* GetOrCreateValue() const { ThreadLocalValueHolderBase* const holder = static_cast(pthread_getspecific(key_)); if (holder != NULL) { return CheckedDowncastToActualType(holder)->pointer(); } ValueHolder* const new_holder = new ValueHolder(default_); ThreadLocalValueHolderBase* const holder_base = new_holder; GTEST_CHECK_POSIX_SUCCESS_(pthread_setspecific(key_, holder_base)); return new_holder->pointer(); } // A key pthreads uses for looking up per-thread values. const pthread_key_t key_; const T default_; // The default value for each thread. GTEST_DISALLOW_COPY_AND_ASSIGN_(ThreadLocal); }; # define GTEST_IS_THREADSAFE 1 #else // GTEST_HAS_PTHREAD // A dummy implementation of synchronization primitives (mutex, lock, // and thread-local variable). Necessary for compiling Google Test where // mutex is not supported - using Google Test in multiple threads is not // supported on such platforms. class Mutex { public: Mutex() {} void Lock() {} void Unlock() {} void AssertHeld() const {} }; # define GTEST_DECLARE_STATIC_MUTEX_(mutex) \ extern ::testing::internal::Mutex mutex # define GTEST_DEFINE_STATIC_MUTEX_(mutex) ::testing::internal::Mutex mutex class GTestMutexLock { public: explicit GTestMutexLock(Mutex*) {} // NOLINT }; typedef GTestMutexLock MutexLock; template class ThreadLocal { public: ThreadLocal() : value_() {} explicit ThreadLocal(const T& value) : value_(value) {} T* pointer() { return &value_; } const T* pointer() const { return &value_; } const T& get() const { return value_; } void set(const T& value) { value_ = value; } private: T value_; }; // The above synchronization primitives have dummy implementations. // Therefore Google Test is not thread-safe. # define GTEST_IS_THREADSAFE 0 #endif // GTEST_HAS_PTHREAD // Returns the number of threads running in the process, or 0 to indicate that // we cannot detect it. GTEST_API_ size_t GetThreadCount(); // Passing non-POD classes through ellipsis (...) crashes the ARM // compiler and generates a warning in Sun Studio. The Nokia Symbian // and the IBM XL C/C++ compiler try to instantiate a copy constructor // for objects passed through ellipsis (...), failing for uncopyable // objects. We define this to ensure that only POD is passed through // ellipsis on these systems. #if defined(__SYMBIAN32__) || defined(__IBMCPP__) || defined(__SUNPRO_CC) // We lose support for NULL detection where the compiler doesn't like // passing non-POD classes through ellipsis (...). # define GTEST_ELLIPSIS_NEEDS_POD_ 1 #else # define GTEST_CAN_COMPARE_NULL 1 #endif // The Nokia Symbian and IBM XL C/C++ compilers cannot decide between // const T& and const T* in a function template. These compilers // _can_ decide between class template specializations for T and T*, // so a tr1::type_traits-like is_pointer works. #if defined(__SYMBIAN32__) || defined(__IBMCPP__) # define GTEST_NEEDS_IS_POINTER_ 1 #endif template struct bool_constant { typedef bool_constant type; static const bool value = bool_value; }; template const bool bool_constant::value; typedef bool_constant false_type; typedef bool_constant true_type; template struct is_pointer : public false_type {}; template struct is_pointer : public true_type{}; template struct IteratorTraits { typedef typename Iterator::value_type value_type; }; template struct IteratorTraits { typedef T value_type; }; template struct IteratorTraits { typedef T value_type; }; #if GTEST_OS_WINDOWS # define GTEST_PATH_SEP_ "\\" # define GTEST_HAS_ALT_PATH_SEP_ 1 // The biggest signed integer type the compiler supports. typedef __int64 BiggestInt; #else # define GTEST_PATH_SEP_ "/" # define GTEST_HAS_ALT_PATH_SEP_ 0 typedef long long BiggestInt; // NOLINT #endif // GTEST_OS_WINDOWS // Utilities for char. // isspace(int ch) and friends accept an unsigned char or EOF. char // may be signed, depending on the compiler (or compiler flags). // Therefore we need to cast a char to unsigned char before calling // isspace(), etc. inline bool IsAlpha(char ch) { return isalpha(static_cast(ch)) != 0; } inline bool IsAlNum(char ch) { return isalnum(static_cast(ch)) != 0; } inline bool IsDigit(char ch) { return isdigit(static_cast(ch)) != 0; } inline bool IsLower(char ch) { return islower(static_cast(ch)) != 0; } inline bool IsSpace(char ch) { return isspace(static_cast(ch)) != 0; } inline bool IsUpper(char ch) { return isupper(static_cast(ch)) != 0; } inline bool IsXDigit(char ch) { return isxdigit(static_cast(ch)) != 0; } inline bool IsXDigit(wchar_t ch) { const unsigned char low_byte = static_cast(ch); return ch == low_byte && isxdigit(low_byte) != 0; } inline char ToLower(char ch) { return static_cast(tolower(static_cast(ch))); } inline char ToUpper(char ch) { return static_cast(toupper(static_cast(ch))); } // The testing::internal::posix namespace holds wrappers for common // POSIX functions. These wrappers hide the differences between // Windows/MSVC and POSIX systems. Since some compilers define these // standard functions as macros, the wrapper cannot have the same name // as the wrapped function. namespace posix { // Functions with a different name on Windows. #if GTEST_OS_WINDOWS typedef struct _stat StatStruct; # ifdef __BORLANDC__ inline int IsATTY(int fd) { return isatty(fd); } inline int StrCaseCmp(const char* s1, const char* s2) { return stricmp(s1, s2); } inline char* StrDup(const char* src) { return strdup(src); } # else // !__BORLANDC__ # if GTEST_OS_WINDOWS_MOBILE inline int IsATTY(int /* fd */) { return 0; } # else inline int IsATTY(int fd) { return _isatty(fd); } # endif // GTEST_OS_WINDOWS_MOBILE inline int StrCaseCmp(const char* s1, const char* s2) { return _stricmp(s1, s2); } inline char* StrDup(const char* src) { return _strdup(src); } # endif // __BORLANDC__ # if GTEST_OS_WINDOWS_MOBILE inline int FileNo(FILE* file) { return reinterpret_cast(_fileno(file)); } // Stat(), RmDir(), and IsDir() are not needed on Windows CE at this // time and thus not defined there. # else inline int FileNo(FILE* file) { return _fileno(file); } inline int Stat(const char* path, StatStruct* buf) { return _stat(path, buf); } inline int RmDir(const char* dir) { return _rmdir(dir); } inline bool IsDir(const StatStruct& st) { return (_S_IFDIR & st.st_mode) != 0; } # endif // GTEST_OS_WINDOWS_MOBILE #else typedef struct stat StatStruct; inline int FileNo(FILE* file) { return fileno(file); } inline int IsATTY(int fd) { return isatty(fd); } inline int Stat(const char* path, StatStruct* buf) { return stat(path, buf); } inline int StrCaseCmp(const char* s1, const char* s2) { return strcasecmp(s1, s2); } inline char* StrDup(const char* src) { return strdup(src); } inline int RmDir(const char* dir) { return rmdir(dir); } inline bool IsDir(const StatStruct& st) { return S_ISDIR(st.st_mode); } #endif // GTEST_OS_WINDOWS // Functions deprecated by MSVC 8.0. #ifdef _MSC_VER // Temporarily disable warning 4996 (deprecated function). # pragma warning(push) # pragma warning(disable:4996) #endif inline const char* StrNCpy(char* dest, const char* src, size_t n) { return strncpy(dest, src, n); } // ChDir(), FReopen(), FDOpen(), Read(), Write(), Close(), and // StrError() aren't needed on Windows CE at this time and thus not // defined there. #if !GTEST_OS_WINDOWS_MOBILE inline int ChDir(const char* dir) { return chdir(dir); } #endif inline FILE* FOpen(const char* path, const char* mode) { return fopen(path, mode); } #if !GTEST_OS_WINDOWS_MOBILE inline FILE *FReopen(const char* path, const char* mode, FILE* stream) { return freopen(path, mode, stream); } inline FILE* FDOpen(int fd, const char* mode) { return fdopen(fd, mode); } #endif inline int FClose(FILE* fp) { return fclose(fp); } #if !GTEST_OS_WINDOWS_MOBILE inline int Read(int fd, void* buf, unsigned int count) { return static_cast(read(fd, buf, count)); } inline int Write(int fd, const void* buf, unsigned int count) { return static_cast(write(fd, buf, count)); } inline int Close(int fd) { return close(fd); } inline const char* StrError(int errnum) { return strerror(errnum); } #endif inline const char* GetEnv(const char* name) { #if GTEST_OS_WINDOWS_MOBILE // We are on Windows CE, which has no environment variables. return NULL; #elif defined(__BORLANDC__) || defined(__SunOS_5_8) || defined(__SunOS_5_9) // Environment variables which we programmatically clear will be set to the // empty string rather than unset (NULL). Handle that case. const char* const env = getenv(name); return (env != NULL && env[0] != '\0') ? env : NULL; #else return getenv(name); #endif } #ifdef _MSC_VER # pragma warning(pop) // Restores the warning state. #endif #if GTEST_OS_WINDOWS_MOBILE // Windows CE has no C library. The abort() function is used in // several places in Google Test. This implementation provides a reasonable // imitation of standard behaviour. void Abort(); #else inline void Abort() { abort(); } #endif // GTEST_OS_WINDOWS_MOBILE } // namespace posix // MSVC "deprecates" snprintf and issues warnings wherever it is used. In // order to avoid these warnings, we need to use _snprintf or _snprintf_s on // MSVC-based platforms. We map the GTEST_SNPRINTF_ macro to the appropriate // function in order to achieve that. We use macro definition here because // snprintf is a variadic function. #if _MSC_VER >= 1400 && !GTEST_OS_WINDOWS_MOBILE // MSVC 2005 and above support variadic macros. # define GTEST_SNPRINTF_(buffer, size, format, ...) \ _snprintf_s(buffer, size, size, format, __VA_ARGS__) #elif defined(_MSC_VER) // Windows CE does not define _snprintf_s and MSVC prior to 2005 doesn't // complain about _snprintf. # define GTEST_SNPRINTF_ _snprintf #else # define GTEST_SNPRINTF_ snprintf #endif // The maximum number a BiggestInt can represent. This definition // works no matter BiggestInt is represented in one's complement or // two's complement. // // We cannot rely on numeric_limits in STL, as __int64 and long long // are not part of standard C++ and numeric_limits doesn't need to be // defined for them. const BiggestInt kMaxBiggestInt = ~(static_cast(1) << (8 * sizeof(BiggestInt)-1)); // This template class serves as a compile-time function from size to // type. It maps a size in bytes to a primitive type with that // size. e.g. // // TypeWithSize<4>::UInt // // is typedef-ed to be unsigned int (unsigned integer made up of 4 // bytes). // // Such functionality should belong to STL, but I cannot find it // there. // // Google Test uses this class in the implementation of floating-point // comparison. // // For now it only handles UInt (unsigned int) as that's all Google Test // needs. Other types can be easily added in the future if need // arises. template class TypeWithSize { public: // This prevents the user from using TypeWithSize with incorrect // values of N. typedef void UInt; }; // The specialization for size 4. template <> class TypeWithSize<4> { public: // unsigned int has size 4 in both gcc and MSVC. // // As base/basictypes.h doesn't compile on Windows, we cannot use // uint32, uint64, and etc here. typedef int Int; typedef unsigned int UInt; }; // The specialization for size 8. template <> class TypeWithSize<8> { public: #if GTEST_OS_WINDOWS typedef __int64 Int; typedef unsigned __int64 UInt; #else typedef long long Int; // NOLINT typedef unsigned long long UInt; // NOLINT #endif // GTEST_OS_WINDOWS }; // Integer types of known sizes. typedef TypeWithSize<4>::Int Int32; typedef TypeWithSize<4>::UInt UInt32; typedef TypeWithSize<8>::Int Int64; typedef TypeWithSize<8>::UInt UInt64; typedef TypeWithSize<8>::Int TimeInMillis; // Represents time in milliseconds. // Utilities for command line flags and environment variables. // Macro for referencing flags. #define GTEST_FLAG(name) FLAGS_gtest_##name // Macros for declaring flags. #define GTEST_DECLARE_bool_(name) GTEST_API_ extern bool GTEST_FLAG(name) #define GTEST_DECLARE_int32_(name) \ GTEST_API_ extern ::testing::internal::Int32 GTEST_FLAG(name) #define GTEST_DECLARE_string_(name) \ GTEST_API_ extern ::std::string GTEST_FLAG(name) // Macros for defining flags. #define GTEST_DEFINE_bool_(name, default_val, doc) \ GTEST_API_ bool GTEST_FLAG(name) = (default_val) #define GTEST_DEFINE_int32_(name, default_val, doc) \ GTEST_API_::testing::internal::Int32 GTEST_FLAG(name) = (default_val) #define GTEST_DEFINE_string_(name, default_val, doc) \ GTEST_API_::std::string GTEST_FLAG(name) = (default_val) // Thread annotations #define GTEST_EXCLUSIVE_LOCK_REQUIRED_(locks) #define GTEST_LOCK_EXCLUDED_(locks) // Parses 'str' for a 32-bit signed integer. If successful, writes the result // to *value and returns true; otherwise leaves *value unchanged and returns // false. // TODO(chandlerc): Find a better way to refactor flag and environment parsing // out of both gtest-port.cc and gtest.cc to avoid exporting this utility // function. bool ParseInt32(const Message& src_text, const char* str, Int32* value); // Parses a bool/Int32/string from the environment variable // corresponding to the given Google Test flag. bool BoolFromGTestEnv(const char* flag, bool default_val); GTEST_API_ Int32 Int32FromGTestEnv(const char* flag, Int32 default_val); const char* StringFromGTestEnv(const char* flag, const char* default_val); } // namespace internal } // namespace testing #endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PORT_H_ #if GTEST_OS_LINUX # include # include # include # include #endif // GTEST_OS_LINUX #if GTEST_HAS_EXCEPTIONS # include #endif #include #include #include #include #include #include // Copyright 2005, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // Author: wan@google.com (Zhanyong Wan) // // The Google C++ Testing Framework (Google Test) // // This header file defines the Message class. // // IMPORTANT NOTE: Due to limitation of the C++ language, we have to // leave some internal implementation details in this header file. // They are clearly marked by comments like this: // // // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. // // Such code is NOT meant to be used by a user directly, and is subject // to CHANGE WITHOUT NOTICE. Therefore DO NOT DEPEND ON IT in a user // program! #ifndef GTEST_INCLUDE_GTEST_GTEST_MESSAGE_H_ #define GTEST_INCLUDE_GTEST_GTEST_MESSAGE_H_ #include // Ensures that there is at least one operator<< in the global namespace. // See Message& operator<<(...) below for why. void operator<<(const testing::internal::Secret&, int); namespace testing { // The Message class works like an ostream repeater. // // Typical usage: // // 1. You stream a bunch of values to a Message object. // It will remember the text in a stringstream. // 2. Then you stream the Message object to an ostream. // This causes the text in the Message to be streamed // to the ostream. // // For example; // // testing::Message foo; // foo << 1 << " != " << 2; // std::cout << foo; // // will print "1 != 2". // // Message is not intended to be inherited from. In particular, its // destructor is not virtual. // // Note that stringstream behaves differently in gcc and in MSVC. You // can stream a NULL char pointer to it in the former, but not in the // latter (it causes an access violation if you do). The Message // class hides this difference by treating a NULL char pointer as // "(null)". class GTEST_API_ Message { private: // The type of basic IO manipulators (endl, ends, and flush) for // narrow streams. typedef std::ostream& (*BasicNarrowIoManip)(std::ostream&); public: // Constructs an empty Message. Message(); // Copy constructor. Message(const Message& msg) : ss_(new ::std::stringstream) { // NOLINT *ss_ << msg.GetString(); } // Constructs a Message from a C-string. explicit Message(const char* str) : ss_(new ::std::stringstream) { *ss_ << str; } #if GTEST_OS_SYMBIAN // Streams a value (either a pointer or not) to this object. template inline Message& operator <<(const T& value) { StreamHelper(typename internal::is_pointer::type(), value); return *this; } #else // Streams a non-pointer value to this object. template inline Message& operator <<(const T& val) { // Some libraries overload << for STL containers. These // overloads are defined in the global namespace instead of ::std. // // C++'s symbol lookup rule (i.e. Koenig lookup) says that these // overloads are visible in either the std namespace or the global // namespace, but not other namespaces, including the testing // namespace which Google Test's Message class is in. // // To allow STL containers (and other types that has a << operator // defined in the global namespace) to be used in Google Test // assertions, testing::Message must access the custom << operator // from the global namespace. With this using declaration, // overloads of << defined in the global namespace and those // visible via Koenig lookup are both exposed in this function. using ::operator <<; *ss_ << val; return *this; } // Streams a pointer value to this object. // // This function is an overload of the previous one. When you // stream a pointer to a Message, this definition will be used as it // is more specialized. (The C++ Standard, section // [temp.func.order].) If you stream a non-pointer, then the // previous definition will be used. // // The reason for this overload is that streaming a NULL pointer to // ostream is undefined behavior. Depending on the compiler, you // may get "0", "(nil)", "(null)", or an access violation. To // ensure consistent result across compilers, we always treat NULL // as "(null)". template inline Message& operator <<(T* const& pointer) { // NOLINT if (pointer == NULL) { *ss_ << "(null)"; } else { *ss_ << pointer; } return *this; } #endif // GTEST_OS_SYMBIAN // Since the basic IO manipulators are overloaded for both narrow // and wide streams, we have to provide this specialized definition // of operator <<, even though its body is the same as the // templatized version above. Without this definition, streaming // endl or other basic IO manipulators to Message will confuse the // compiler. Message& operator <<(BasicNarrowIoManip val) { *ss_ << val; return *this; } // Instead of 1/0, we want to see true/false for bool values. Message& operator <<(bool b) { return *this << (b ? "true" : "false"); } // These two overloads allow streaming a wide C string to a Message // using the UTF-8 encoding. Message& operator <<(const wchar_t* wide_c_str); Message& operator <<(wchar_t* wide_c_str); #if GTEST_HAS_STD_WSTRING // Converts the given wide string to a narrow string using the UTF-8 // encoding, and streams the result to this Message object. Message& operator <<(const ::std::wstring& wstr); #endif // GTEST_HAS_STD_WSTRING #if GTEST_HAS_GLOBAL_WSTRING // Converts the given wide string to a narrow string using the UTF-8 // encoding, and streams the result to this Message object. Message& operator <<(const ::wstring& wstr); #endif // GTEST_HAS_GLOBAL_WSTRING // Gets the text streamed to this object so far as an std::string. // Each '\0' character in the buffer is replaced with "\\0". // // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. std::string GetString() const; private: #if GTEST_OS_SYMBIAN // These are needed as the Nokia Symbian Compiler cannot decide between // const T& and const T* in a function template. The Nokia compiler _can_ // decide between class template specializations for T and T*, so a // tr1::type_traits-like is_pointer works, and we can overload on that. template inline void StreamHelper(internal::true_type /*is_pointer*/, T* pointer) { if (pointer == NULL) { *ss_ << "(null)"; } else { *ss_ << pointer; } } template inline void StreamHelper(internal::false_type /*is_pointer*/, const T& value) { // See the comments in Message& operator <<(const T&) above for why // we need this using statement. using ::operator <<; *ss_ << value; } #endif // GTEST_OS_SYMBIAN // We'll hold the text streamed to this object here. const internal::scoped_ptr< ::std::stringstream> ss_; // We declare (but don't implement) this to prevent the compiler // from implementing the assignment operator. void operator=(const Message&); }; // Streams a Message to an ostream. inline std::ostream& operator <<(std::ostream& os, const Message& sb) { return os << sb.GetString(); } namespace internal { // Converts a streamable value to an std::string. A NULL pointer is // converted to "(null)". When the input value is a ::string, // ::std::string, ::wstring, or ::std::wstring object, each NUL // character in it is replaced with "\\0". template std::string StreamableToString(const T& streamable) { return (Message() << streamable).GetString(); } } // namespace internal } // namespace testing #endif // GTEST_INCLUDE_GTEST_GTEST_MESSAGE_H_ // Copyright 2005, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // Authors: wan@google.com (Zhanyong Wan), eefacm@gmail.com (Sean Mcafee) // // The Google C++ Testing Framework (Google Test) // // This header file declares the String class and functions used internally by // Google Test. They are subject to change without notice. They should not used // by code external to Google Test. // // This header file is #included by . // It should not be #included by other files. #ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_STRING_H_ #define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_STRING_H_ #ifdef __BORLANDC__ // string.h is not guaranteed to provide strcpy on C++ Builder. # include #endif #include #include namespace testing { namespace internal { // String - an abstract class holding static string utilities. class GTEST_API_ String { public: // Static utility methods // Clones a 0-terminated C string, allocating memory using new. The // caller is responsible for deleting the return value using // delete[]. Returns the cloned string, or NULL if the input is // NULL. // // This is different from strdup() in string.h, which allocates // memory using malloc(). static const char* CloneCString(const char* c_str); #if GTEST_OS_WINDOWS_MOBILE // Windows CE does not have the 'ANSI' versions of Win32 APIs. To be // able to pass strings to Win32 APIs on CE we need to convert them // to 'Unicode', UTF-16. // Creates a UTF-16 wide string from the given ANSI string, allocating // memory using new. The caller is responsible for deleting the return // value using delete[]. Returns the wide string, or NULL if the // input is NULL. // // The wide string is created using the ANSI codepage (CP_ACP) to // match the behaviour of the ANSI versions of Win32 calls and the // C runtime. static LPCWSTR AnsiToUtf16(const char* c_str); // Creates an ANSI string from the given wide string, allocating // memory using new. The caller is responsible for deleting the return // value using delete[]. Returns the ANSI string, or NULL if the // input is NULL. // // The returned string is created using the ANSI codepage (CP_ACP) to // match the behaviour of the ANSI versions of Win32 calls and the // C runtime. static const char* Utf16ToAnsi(LPCWSTR utf16_str); #endif // Compares two C strings. Returns true iff they have the same content. // // Unlike strcmp(), this function can handle NULL argument(s). A // NULL C string is considered different to any non-NULL C string, // including the empty string. static bool CStringEquals(const char* lhs, const char* rhs); // Converts a wide C string to a String using the UTF-8 encoding. // NULL will be converted to "(null)". If an error occurred during // the conversion, "(failed to convert from wide string)" is // returned. static std::string ShowWideCString(const wchar_t* wide_c_str); // Compares two wide C strings. Returns true iff they have the same // content. // // Unlike wcscmp(), this function can handle NULL argument(s). A // NULL C string is considered different to any non-NULL C string, // including the empty string. static bool WideCStringEquals(const wchar_t* lhs, const wchar_t* rhs); // Compares two C strings, ignoring case. Returns true iff they // have the same content. // // Unlike strcasecmp(), this function can handle NULL argument(s). // A NULL C string is considered different to any non-NULL C string, // including the empty string. static bool CaseInsensitiveCStringEquals(const char* lhs, const char* rhs); // Compares two wide C strings, ignoring case. Returns true iff they // have the same content. // // Unlike wcscasecmp(), this function can handle NULL argument(s). // A NULL C string is considered different to any non-NULL wide C string, // including the empty string. // NB: The implementations on different platforms slightly differ. // On windows, this method uses _wcsicmp which compares according to LC_CTYPE // environment variable. On GNU platform this method uses wcscasecmp // which compares according to LC_CTYPE category of the current locale. // On MacOS X, it uses towlower, which also uses LC_CTYPE category of the // current locale. static bool CaseInsensitiveWideCStringEquals(const wchar_t* lhs, const wchar_t* rhs); // Returns true iff the given string ends with the given suffix, ignoring // case. Any string is considered to end with an empty suffix. static bool EndsWithCaseInsensitive( const std::string& str, const std::string& suffix); // Formats an int value as "%02d". static std::string FormatIntWidth2(int value); // "%02d" for width == 2 // Formats an int value as "%X". static std::string FormatHexInt(int value); // Formats a byte as "%02X". static std::string FormatByte(unsigned char value); private: String(); // Not meant to be instantiated. }; // class String // Gets the content of the stringstream's buffer as an std::string. Each '\0' // character in the buffer is replaced with "\\0". GTEST_API_ std::string StringStreamToString(::std::stringstream* stream); } // namespace internal } // namespace testing #endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_STRING_H_ // Copyright 2008, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // Author: keith.ray@gmail.com (Keith Ray) // // Google Test filepath utilities // // This header file declares classes and functions used internally by // Google Test. They are subject to change without notice. // // This file is #included in . // Do not include this header file separately! #ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_FILEPATH_H_ #define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_FILEPATH_H_ namespace testing { namespace internal { // FilePath - a class for file and directory pathname manipulation which // handles platform-specific conventions (like the pathname separator). // Used for helper functions for naming files in a directory for xml output. // Except for Set methods, all methods are const or static, which provides an // "immutable value object" -- useful for peace of mind. // A FilePath with a value ending in a path separator ("like/this/") represents // a directory, otherwise it is assumed to represent a file. In either case, // it may or may not represent an actual file or directory in the file system. // Names are NOT checked for syntax correctness -- no checking for illegal // characters, malformed paths, etc. class GTEST_API_ FilePath { public: FilePath() : pathname_("") { } FilePath(const FilePath& rhs) : pathname_(rhs.pathname_) { } explicit FilePath(const std::string& pathname) : pathname_(pathname) { Normalize(); } FilePath& operator=(const FilePath& rhs) { Set(rhs); return *this; } void Set(const FilePath& rhs) { pathname_ = rhs.pathname_; } const std::string& string() const { return pathname_; } const char* c_str() const { return pathname_.c_str(); } // Returns the current working directory, or "" if unsuccessful. static FilePath GetCurrentDir(); // Given directory = "dir", base_name = "test", number = 0, // extension = "xml", returns "dir/test.xml". If number is greater // than zero (e.g., 12), returns "dir/test_12.xml". // On Windows platform, uses \ as the separator rather than /. static FilePath MakeFileName(const FilePath& directory, const FilePath& base_name, int number, const char* extension); // Given directory = "dir", relative_path = "test.xml", // returns "dir/test.xml". // On Windows, uses \ as the separator rather than /. static FilePath ConcatPaths(const FilePath& directory, const FilePath& relative_path); // Returns a pathname for a file that does not currently exist. The pathname // will be directory/base_name.extension or // directory/base_name_.extension if directory/base_name.extension // already exists. The number will be incremented until a pathname is found // that does not already exist. // Examples: 'dir/foo_test.xml' or 'dir/foo_test_1.xml'. // There could be a race condition if two or more processes are calling this // function at the same time -- they could both pick the same filename. static FilePath GenerateUniqueFileName(const FilePath& directory, const FilePath& base_name, const char* extension); // Returns true iff the path is "". bool IsEmpty() const { return pathname_.empty(); } // If input name has a trailing separator character, removes it and returns // the name, otherwise return the name string unmodified. // On Windows platform, uses \ as the separator, other platforms use /. FilePath RemoveTrailingPathSeparator() const; // Returns a copy of the FilePath with the directory part removed. // Example: FilePath("path/to/file").RemoveDirectoryName() returns // FilePath("file"). If there is no directory part ("just_a_file"), it returns // the FilePath unmodified. If there is no file part ("just_a_dir/") it // returns an empty FilePath (""). // On Windows platform, '\' is the path separator, otherwise it is '/'. FilePath RemoveDirectoryName() const; // RemoveFileName returns the directory path with the filename removed. // Example: FilePath("path/to/file").RemoveFileName() returns "path/to/". // If the FilePath is "a_file" or "/a_file", RemoveFileName returns // FilePath("./") or, on Windows, FilePath(".\\"). If the filepath does // not have a file, like "just/a/dir/", it returns the FilePath unmodified. // On Windows platform, '\' is the path separator, otherwise it is '/'. FilePath RemoveFileName() const; // Returns a copy of the FilePath with the case-insensitive extension removed. // Example: FilePath("dir/file.exe").RemoveExtension("EXE") returns // FilePath("dir/file"). If a case-insensitive extension is not // found, returns a copy of the original FilePath. FilePath RemoveExtension(const char* extension) const; // Creates directories so that path exists. Returns true if successful or if // the directories already exist; returns false if unable to create // directories for any reason. Will also return false if the FilePath does // not represent a directory (that is, it doesn't end with a path separator). bool CreateDirectoriesRecursively() const; // Create the directory so that path exists. Returns true if successful or // if the directory already exists; returns false if unable to create the // directory for any reason, including if the parent directory does not // exist. Not named "CreateDirectory" because that's a macro on Windows. bool CreateFolder() const; // Returns true if FilePath describes something in the file-system, // either a file, directory, or whatever, and that something exists. bool FileOrDirectoryExists() const; // Returns true if pathname describes a directory in the file-system // that exists. bool DirectoryExists() const; // Returns true if FilePath ends with a path separator, which indicates that // it is intended to represent a directory. Returns false otherwise. // This does NOT check that a directory (or file) actually exists. bool IsDirectory() const; // Returns true if pathname describes a root directory. (Windows has one // root directory per disk drive.) bool IsRootDirectory() const; // Returns true if pathname describes an absolute path. bool IsAbsolutePath() const; private: // Replaces multiple consecutive separators with a single separator. // For example, "bar///foo" becomes "bar/foo". Does not eliminate other // redundancies that might be in a pathname involving "." or "..". // // A pathname with multiple consecutive separators may occur either through // user error or as a result of some scripts or APIs that generate a pathname // with a trailing separator. On other platforms the same API or script // may NOT generate a pathname with a trailing "/". Then elsewhere that // pathname may have another "/" and pathname components added to it, // without checking for the separator already being there. // The script language and operating system may allow paths like "foo//bar" // but some of the functions in FilePath will not handle that correctly. In // particular, RemoveTrailingPathSeparator() only removes one separator, and // it is called in CreateDirectoriesRecursively() assuming that it will change // a pathname from directory syntax (trailing separator) to filename syntax. // // On Windows this method also replaces the alternate path separator '/' with // the primary path separator '\\', so that for example "bar\\/\\foo" becomes // "bar\\foo". void Normalize(); // Returns a pointer to the last occurence of a valid path separator in // the FilePath. On Windows, for example, both '/' and '\' are valid path // separators. Returns NULL if no path separator was found. const char* FindLastPathSeparator() const; std::string pathname_; }; // class FilePath } // namespace internal } // namespace testing #endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_FILEPATH_H_ // This file was GENERATED by command: // pump.py gtest-type-util.h.pump // DO NOT EDIT BY HAND!!! // Copyright 2008 Google Inc. // All Rights Reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // Author: wan@google.com (Zhanyong Wan) // Type utilities needed for implementing typed and type-parameterized // tests. This file is generated by a SCRIPT. DO NOT EDIT BY HAND! // // Currently we support at most 50 types in a list, and at most 50 // type-parameterized tests in one type-parameterized test case. // Please contact googletestframework@googlegroups.com if you need // more. #ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TYPE_UTIL_H_ #define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TYPE_UTIL_H_ // #ifdef __GNUC__ is too general here. It is possible to use gcc without using // libstdc++ (which is where cxxabi.h comes from). # if GTEST_HAS_CXXABI_H_ # include # elif defined(__HP_aCC) # include # endif // GTEST_HASH_CXXABI_H_ namespace testing { namespace internal { // GetTypeName() returns a human-readable name of type T. // NB: This function is also used in Google Mock, so don't move it inside of // the typed-test-only section below. template std::string GetTypeName() { # if GTEST_HAS_RTTI const char* const name = typeid(T).name(); # if GTEST_HAS_CXXABI_H_ || defined(__HP_aCC) int status = 0; // gcc's implementation of typeid(T).name() mangles the type name, // so we have to demangle it. # if GTEST_HAS_CXXABI_H_ using abi::__cxa_demangle; # endif // GTEST_HAS_CXXABI_H_ char* const readable_name = __cxa_demangle(name, 0, 0, &status); const std::string name_str(status == 0 ? readable_name : name); free(readable_name); return name_str; # else return name; # endif // GTEST_HAS_CXXABI_H_ || __HP_aCC # else return ""; # endif // GTEST_HAS_RTTI } #if GTEST_HAS_TYPED_TEST || GTEST_HAS_TYPED_TEST_P // AssertyTypeEq::type is defined iff T1 and T2 are the same // type. This can be used as a compile-time assertion to ensure that // two types are equal. template struct AssertTypeEq; template struct AssertTypeEq { typedef bool type; }; // A unique type used as the default value for the arguments of class // template Types. This allows us to simulate variadic templates // (e.g. Types, Type, and etc), which C++ doesn't // support directly. struct None {}; // The following family of struct and struct templates are used to // represent type lists. In particular, TypesN // represents a type list with N types (T1, T2, ..., and TN) in it. // Except for Types0, every struct in the family has two member types: // Head for the first type in the list, and Tail for the rest of the // list. // The empty type list. struct Types0 {}; // Type lists of length 1, 2, 3, and so on. template struct Types1 { typedef T1 Head; typedef Types0 Tail; }; template struct Types2 { typedef T1 Head; typedef Types1 Tail; }; template struct Types3 { typedef T1 Head; typedef Types2 Tail; }; template struct Types4 { typedef T1 Head; typedef Types3 Tail; }; template struct Types5 { typedef T1 Head; typedef Types4 Tail; }; template struct Types6 { typedef T1 Head; typedef Types5 Tail; }; template struct Types7 { typedef T1 Head; typedef Types6 Tail; }; template struct Types8 { typedef T1 Head; typedef Types7 Tail; }; template struct Types9 { typedef T1 Head; typedef Types8 Tail; }; template struct Types10 { typedef T1 Head; typedef Types9 Tail; }; template struct Types11 { typedef T1 Head; typedef Types10 Tail; }; template struct Types12 { typedef T1 Head; typedef Types11 Tail; }; template struct Types13 { typedef T1 Head; typedef Types12 Tail; }; template struct Types14 { typedef T1 Head; typedef Types13 Tail; }; template struct Types15 { typedef T1 Head; typedef Types14 Tail; }; template struct Types16 { typedef T1 Head; typedef Types15 Tail; }; template struct Types17 { typedef T1 Head; typedef Types16 Tail; }; template struct Types18 { typedef T1 Head; typedef Types17 Tail; }; template struct Types19 { typedef T1 Head; typedef Types18 Tail; }; template struct Types20 { typedef T1 Head; typedef Types19 Tail; }; template struct Types21 { typedef T1 Head; typedef Types20 Tail; }; template struct Types22 { typedef T1 Head; typedef Types21 Tail; }; template struct Types23 { typedef T1 Head; typedef Types22 Tail; }; template struct Types24 { typedef T1 Head; typedef Types23 Tail; }; template struct Types25 { typedef T1 Head; typedef Types24 Tail; }; template struct Types26 { typedef T1 Head; typedef Types25 Tail; }; template struct Types27 { typedef T1 Head; typedef Types26 Tail; }; template struct Types28 { typedef T1 Head; typedef Types27 Tail; }; template struct Types29 { typedef T1 Head; typedef Types28 Tail; }; template struct Types30 { typedef T1 Head; typedef Types29 Tail; }; template struct Types31 { typedef T1 Head; typedef Types30 Tail; }; template struct Types32 { typedef T1 Head; typedef Types31 Tail; }; template struct Types33 { typedef T1 Head; typedef Types32 Tail; }; template struct Types34 { typedef T1 Head; typedef Types33 Tail; }; template struct Types35 { typedef T1 Head; typedef Types34 Tail; }; template struct Types36 { typedef T1 Head; typedef Types35 Tail; }; template struct Types37 { typedef T1 Head; typedef Types36 Tail; }; template struct Types38 { typedef T1 Head; typedef Types37 Tail; }; template struct Types39 { typedef T1 Head; typedef Types38 Tail; }; template struct Types40 { typedef T1 Head; typedef Types39 Tail; }; template struct Types41 { typedef T1 Head; typedef Types40 Tail; }; template struct Types42 { typedef T1 Head; typedef Types41 Tail; }; template struct Types43 { typedef T1 Head; typedef Types42 Tail; }; template struct Types44 { typedef T1 Head; typedef Types43 Tail; }; template struct Types45 { typedef T1 Head; typedef Types44 Tail; }; template struct Types46 { typedef T1 Head; typedef Types45 Tail; }; template struct Types47 { typedef T1 Head; typedef Types46 Tail; }; template struct Types48 { typedef T1 Head; typedef Types47 Tail; }; template struct Types49 { typedef T1 Head; typedef Types48 Tail; }; template struct Types50 { typedef T1 Head; typedef Types49 Tail; }; } // namespace internal // We don't want to require the users to write TypesN<...> directly, // as that would require them to count the length. Types<...> is much // easier to write, but generates horrible messages when there is a // compiler error, as gcc insists on printing out each template // argument, even if it has the default value (this means Types // will appear as Types in the compiler // errors). // // Our solution is to combine the best part of the two approaches: a // user would write Types, and Google Test will translate // that to TypesN internally to make error messages // readable. The translation is done by the 'type' member of the // Types template. template struct Types { typedef internal::Types50 type; }; template <> struct Types { typedef internal::Types0 type; }; template struct Types { typedef internal::Types1 type; }; template struct Types { typedef internal::Types2 type; }; template struct Types { typedef internal::Types3 type; }; template struct Types { typedef internal::Types4 type; }; template struct Types { typedef internal::Types5 type; }; template struct Types { typedef internal::Types6 type; }; template struct Types { typedef internal::Types7 type; }; template struct Types { typedef internal::Types8 type; }; template struct Types { typedef internal::Types9 type; }; template struct Types { typedef internal::Types10 type; }; template struct Types { typedef internal::Types11 type; }; template struct Types { typedef internal::Types12 type; }; template struct Types { typedef internal::Types13 type; }; template struct Types { typedef internal::Types14 type; }; template struct Types { typedef internal::Types15 type; }; template struct Types { typedef internal::Types16 type; }; template struct Types { typedef internal::Types17 type; }; template struct Types { typedef internal::Types18 type; }; template struct Types { typedef internal::Types19 type; }; template struct Types { typedef internal::Types20 type; }; template struct Types { typedef internal::Types21 type; }; template struct Types { typedef internal::Types22 type; }; template struct Types { typedef internal::Types23 type; }; template struct Types { typedef internal::Types24 type; }; template struct Types { typedef internal::Types25 type; }; template struct Types { typedef internal::Types26 type; }; template struct Types { typedef internal::Types27 type; }; template struct Types { typedef internal::Types28 type; }; template struct Types { typedef internal::Types29 type; }; template struct Types { typedef internal::Types30 type; }; template struct Types { typedef internal::Types31 type; }; template struct Types { typedef internal::Types32 type; }; template struct Types { typedef internal::Types33 type; }; template struct Types { typedef internal::Types34 type; }; template struct Types { typedef internal::Types35 type; }; template struct Types { typedef internal::Types36 type; }; template struct Types { typedef internal::Types37 type; }; template struct Types { typedef internal::Types38 type; }; template struct Types { typedef internal::Types39 type; }; template struct Types { typedef internal::Types40 type; }; template struct Types { typedef internal::Types41 type; }; template struct Types { typedef internal::Types42 type; }; template struct Types { typedef internal::Types43 type; }; template struct Types { typedef internal::Types44 type; }; template struct Types { typedef internal::Types45 type; }; template struct Types { typedef internal::Types46 type; }; template struct Types { typedef internal::Types47 type; }; template struct Types { typedef internal::Types48 type; }; template struct Types { typedef internal::Types49 type; }; namespace internal { # define GTEST_TEMPLATE_ template class // The template "selector" struct TemplateSel is used to // represent Tmpl, which must be a class template with one type // parameter, as a type. TemplateSel::Bind::type is defined // as the type Tmpl. This allows us to actually instantiate the // template "selected" by TemplateSel. // // This trick is necessary for simulating typedef for class templates, // which C++ doesn't support directly. template struct TemplateSel { template struct Bind { typedef Tmpl type; }; }; # define GTEST_BIND_(TmplSel, T) \ TmplSel::template Bind::type // A unique struct template used as the default value for the // arguments of class template Templates. This allows us to simulate // variadic templates (e.g. Templates, Templates, // and etc), which C++ doesn't support directly. template struct NoneT {}; // The following family of struct and struct templates are used to // represent template lists. In particular, TemplatesN represents a list of N templates (T1, T2, ..., and TN). Except // for Templates0, every struct in the family has two member types: // Head for the selector of the first template in the list, and Tail // for the rest of the list. // The empty template list. struct Templates0 {}; // Template lists of length 1, 2, 3, and so on. template struct Templates1 { typedef TemplateSel Head; typedef Templates0 Tail; }; template struct Templates2 { typedef TemplateSel Head; typedef Templates1 Tail; }; template struct Templates3 { typedef TemplateSel Head; typedef Templates2 Tail; }; template struct Templates4 { typedef TemplateSel Head; typedef Templates3 Tail; }; template struct Templates5 { typedef TemplateSel Head; typedef Templates4 Tail; }; template struct Templates6 { typedef TemplateSel Head; typedef Templates5 Tail; }; template struct Templates7 { typedef TemplateSel Head; typedef Templates6 Tail; }; template struct Templates8 { typedef TemplateSel Head; typedef Templates7 Tail; }; template struct Templates9 { typedef TemplateSel Head; typedef Templates8 Tail; }; template struct Templates10 { typedef TemplateSel Head; typedef Templates9 Tail; }; template struct Templates11 { typedef TemplateSel Head; typedef Templates10 Tail; }; template struct Templates12 { typedef TemplateSel Head; typedef Templates11 Tail; }; template struct Templates13 { typedef TemplateSel Head; typedef Templates12 Tail; }; template struct Templates14 { typedef TemplateSel Head; typedef Templates13 Tail; }; template struct Templates15 { typedef TemplateSel Head; typedef Templates14 Tail; }; template struct Templates16 { typedef TemplateSel Head; typedef Templates15 Tail; }; template struct Templates17 { typedef TemplateSel Head; typedef Templates16 Tail; }; template struct Templates18 { typedef TemplateSel Head; typedef Templates17 Tail; }; template struct Templates19 { typedef TemplateSel Head; typedef Templates18 Tail; }; template struct Templates20 { typedef TemplateSel Head; typedef Templates19 Tail; }; template struct Templates21 { typedef TemplateSel Head; typedef Templates20 Tail; }; template struct Templates22 { typedef TemplateSel Head; typedef Templates21 Tail; }; template struct Templates23 { typedef TemplateSel Head; typedef Templates22 Tail; }; template struct Templates24 { typedef TemplateSel Head; typedef Templates23 Tail; }; template struct Templates25 { typedef TemplateSel Head; typedef Templates24 Tail; }; template struct Templates26 { typedef TemplateSel Head; typedef Templates25 Tail; }; template struct Templates27 { typedef TemplateSel Head; typedef Templates26 Tail; }; template struct Templates28 { typedef TemplateSel Head; typedef Templates27 Tail; }; template struct Templates29 { typedef TemplateSel Head; typedef Templates28 Tail; }; template struct Templates30 { typedef TemplateSel Head; typedef Templates29 Tail; }; template struct Templates31 { typedef TemplateSel Head; typedef Templates30 Tail; }; template struct Templates32 { typedef TemplateSel Head; typedef Templates31 Tail; }; template struct Templates33 { typedef TemplateSel Head; typedef Templates32 Tail; }; template struct Templates34 { typedef TemplateSel Head; typedef Templates33 Tail; }; template struct Templates35 { typedef TemplateSel Head; typedef Templates34 Tail; }; template struct Templates36 { typedef TemplateSel Head; typedef Templates35 Tail; }; template struct Templates37 { typedef TemplateSel Head; typedef Templates36 Tail; }; template struct Templates38 { typedef TemplateSel Head; typedef Templates37 Tail; }; template struct Templates39 { typedef TemplateSel Head; typedef Templates38 Tail; }; template struct Templates40 { typedef TemplateSel Head; typedef Templates39 Tail; }; template struct Templates41 { typedef TemplateSel Head; typedef Templates40 Tail; }; template struct Templates42 { typedef TemplateSel Head; typedef Templates41 Tail; }; template struct Templates43 { typedef TemplateSel Head; typedef Templates42 Tail; }; template struct Templates44 { typedef TemplateSel Head; typedef Templates43 Tail; }; template struct Templates45 { typedef TemplateSel Head; typedef Templates44 Tail; }; template struct Templates46 { typedef TemplateSel Head; typedef Templates45 Tail; }; template struct Templates47 { typedef TemplateSel Head; typedef Templates46 Tail; }; template struct Templates48 { typedef TemplateSel Head; typedef Templates47 Tail; }; template struct Templates49 { typedef TemplateSel Head; typedef Templates48 Tail; }; template struct Templates50 { typedef TemplateSel Head; typedef Templates49 Tail; }; // We don't want to require the users to write TemplatesN<...> directly, // as that would require them to count the length. Templates<...> is much // easier to write, but generates horrible messages when there is a // compiler error, as gcc insists on printing out each template // argument, even if it has the default value (this means Templates // will appear as Templates in the compiler // errors). // // Our solution is to combine the best part of the two approaches: a // user would write Templates, and Google Test will translate // that to TemplatesN internally to make error messages // readable. The translation is done by the 'type' member of the // Templates template. template struct Templates { typedef Templates50 type; }; template <> struct Templates { typedef Templates0 type; }; template struct Templates { typedef Templates1 type; }; template struct Templates { typedef Templates2 type; }; template struct Templates { typedef Templates3 type; }; template struct Templates { typedef Templates4 type; }; template struct Templates { typedef Templates5 type; }; template struct Templates { typedef Templates6 type; }; template struct Templates { typedef Templates7 type; }; template struct Templates { typedef Templates8 type; }; template struct Templates { typedef Templates9 type; }; template struct Templates { typedef Templates10 type; }; template struct Templates { typedef Templates11 type; }; template struct Templates { typedef Templates12 type; }; template struct Templates { typedef Templates13 type; }; template struct Templates { typedef Templates14 type; }; template struct Templates { typedef Templates15 type; }; template struct Templates { typedef Templates16 type; }; template struct Templates { typedef Templates17 type; }; template struct Templates { typedef Templates18 type; }; template struct Templates { typedef Templates19 type; }; template struct Templates { typedef Templates20 type; }; template struct Templates { typedef Templates21 type; }; template struct Templates { typedef Templates22 type; }; template struct Templates { typedef Templates23 type; }; template struct Templates { typedef Templates24 type; }; template struct Templates { typedef Templates25 type; }; template struct Templates { typedef Templates26 type; }; template struct Templates { typedef Templates27 type; }; template struct Templates { typedef Templates28 type; }; template struct Templates { typedef Templates29 type; }; template struct Templates { typedef Templates30 type; }; template struct Templates { typedef Templates31 type; }; template struct Templates { typedef Templates32 type; }; template struct Templates { typedef Templates33 type; }; template struct Templates { typedef Templates34 type; }; template struct Templates { typedef Templates35 type; }; template struct Templates { typedef Templates36 type; }; template struct Templates { typedef Templates37 type; }; template struct Templates { typedef Templates38 type; }; template struct Templates { typedef Templates39 type; }; template struct Templates { typedef Templates40 type; }; template struct Templates { typedef Templates41 type; }; template struct Templates { typedef Templates42 type; }; template struct Templates { typedef Templates43 type; }; template struct Templates { typedef Templates44 type; }; template struct Templates { typedef Templates45 type; }; template struct Templates { typedef Templates46 type; }; template struct Templates { typedef Templates47 type; }; template struct Templates { typedef Templates48 type; }; template struct Templates { typedef Templates49 type; }; // The TypeList template makes it possible to use either a single type // or a Types<...> list in TYPED_TEST_CASE() and // INSTANTIATE_TYPED_TEST_CASE_P(). template struct TypeList { typedef Types1 type; }; template struct TypeList > { typedef typename Types::type type; }; #endif // GTEST_HAS_TYPED_TEST || GTEST_HAS_TYPED_TEST_P } // namespace internal } // namespace testing #endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TYPE_UTIL_H_ // Due to C++ preprocessor weirdness, we need double indirection to // concatenate two tokens when one of them is __LINE__. Writing // // foo ## __LINE__ // // will result in the token foo__LINE__, instead of foo followed by // the current line number. For more details, see // http://www.parashift.com/c++-faq-lite/misc-technical-issues.html#faq-39.6 #define GTEST_CONCAT_TOKEN_(foo, bar) GTEST_CONCAT_TOKEN_IMPL_(foo, bar) #define GTEST_CONCAT_TOKEN_IMPL_(foo, bar) foo ## bar class ProtocolMessage; namespace proto2 { class Message; } namespace testing { // Forward declarations. class AssertionResult; // Result of an assertion. class Message; // Represents a failure message. class Test; // Represents a test. class TestInfo; // Information about a test. class TestPartResult; // Result of a test part. class UnitTest; // A collection of test cases. template ::std::string PrintToString(const T& value); namespace internal { struct TraceInfo; // Information about a trace point. class ScopedTrace; // Implements scoped trace. class TestInfoImpl; // Opaque implementation of TestInfo class UnitTestImpl; // Opaque implementation of UnitTest // How many times InitGoogleTest() has been called. GTEST_API_ extern int g_init_gtest_count; // The text used in failure messages to indicate the start of the // stack trace. GTEST_API_ extern const char kStackTraceMarker[]; // Two overloaded helpers for checking at compile time whether an // expression is a null pointer literal (i.e. NULL or any 0-valued // compile-time integral constant). Their return values have // different sizes, so we can use sizeof() to test which version is // picked by the compiler. These helpers have no implementations, as // we only need their signatures. // // Given IsNullLiteralHelper(x), the compiler will pick the first // version if x can be implicitly converted to Secret*, and pick the // second version otherwise. Since Secret is a secret and incomplete // type, the only expression a user can write that has type Secret* is // a null pointer literal. Therefore, we know that x is a null // pointer literal if and only if the first version is picked by the // compiler. char IsNullLiteralHelper(Secret* p); char(&IsNullLiteralHelper(...))[2]; // NOLINT // A compile-time bool constant that is true if and only if x is a // null pointer literal (i.e. NULL or any 0-valued compile-time // integral constant). #ifdef GTEST_ELLIPSIS_NEEDS_POD_ // We lose support for NULL detection where the compiler doesn't like // passing non-POD classes through ellipsis (...). # define GTEST_IS_NULL_LITERAL_(x) false #else # define GTEST_IS_NULL_LITERAL_(x) \ (sizeof(::testing::internal::IsNullLiteralHelper(x)) == 1) #endif // GTEST_ELLIPSIS_NEEDS_POD_ // Appends the user-supplied message to the Google-Test-generated message. GTEST_API_ std::string AppendUserMessage( const std::string& gtest_msg, const Message& user_msg); #if GTEST_HAS_EXCEPTIONS // This exception is thrown by (and only by) a failed Google Test // assertion when GTEST_FLAG(throw_on_failure) is true (if exceptions // are enabled). We derive it from std::runtime_error, which is for // errors presumably detectable only at run time. Since // std::runtime_error inherits from std::exception, many testing // frameworks know how to extract and print the message inside it. class GTEST_API_ GoogleTestFailureException : public ::std::runtime_error { public: explicit GoogleTestFailureException(const TestPartResult& failure); }; #endif // GTEST_HAS_EXCEPTIONS // A helper class for creating scoped traces in user programs. class GTEST_API_ ScopedTrace { public: // The c'tor pushes the given source file location and message onto // a trace stack maintained by Google Test. ScopedTrace(const char* file, int line, const Message& message); // The d'tor pops the info pushed by the c'tor. // // Note that the d'tor is not virtual in order to be efficient. // Don't inherit from ScopedTrace! ~ScopedTrace(); private: GTEST_DISALLOW_COPY_AND_ASSIGN_(ScopedTrace); } GTEST_ATTRIBUTE_UNUSED_; // A ScopedTrace object does its job in its // c'tor and d'tor. Therefore it doesn't // need to be used otherwise. // Constructs and returns the message for an equality assertion // (e.g. ASSERT_EQ, EXPECT_STREQ, etc) failure. // // The first four parameters are the expressions used in the assertion // and their values, as strings. For example, for ASSERT_EQ(foo, bar) // where foo is 5 and bar is 6, we have: // // expected_expression: "foo" // actual_expression: "bar" // expected_value: "5" // actual_value: "6" // // The ignoring_case parameter is true iff the assertion is a // *_STRCASEEQ*. When it's true, the string " (ignoring case)" will // be inserted into the message. GTEST_API_ AssertionResult EqFailure(const char* expected_expression, const char* actual_expression, const std::string& expected_value, const std::string& actual_value, bool ignoring_case); // Constructs a failure message for Boolean assertions such as EXPECT_TRUE. GTEST_API_ std::string GetBoolAssertionFailureMessage( const AssertionResult& assertion_result, const char* expression_text, const char* actual_predicate_value, const char* expected_predicate_value); // This template class represents an IEEE floating-point number // (either single-precision or double-precision, depending on the // template parameters). // // The purpose of this class is to do more sophisticated number // comparison. (Due to round-off error, etc, it's very unlikely that // two floating-points will be equal exactly. Hence a naive // comparison by the == operation often doesn't work.) // // Format of IEEE floating-point: // // The most-significant bit being the leftmost, an IEEE // floating-point looks like // // sign_bit exponent_bits fraction_bits // // Here, sign_bit is a single bit that designates the sign of the // number. // // For float, there are 8 exponent bits and 23 fraction bits. // // For double, there are 11 exponent bits and 52 fraction bits. // // More details can be found at // http://en.wikipedia.org/wiki/IEEE_floating-point_standard. // // Template parameter: // // RawType: the raw floating-point type (either float or double) template class FloatingPoint { public: // Defines the unsigned integer type that has the same size as the // floating point number. typedef typename TypeWithSize::UInt Bits; // Constants. // # of bits in a number. static const size_t kBitCount = 8 * sizeof(RawType); // # of fraction bits in a number. static const size_t kFractionBitCount = std::numeric_limits::digits - 1; // # of exponent bits in a number. static const size_t kExponentBitCount = kBitCount - 1 - kFractionBitCount; // The mask for the sign bit. static const Bits kSignBitMask = static_cast(1) << (kBitCount - 1); // The mask for the fraction bits. static const Bits kFractionBitMask = ~static_cast(0) >> (kExponentBitCount + 1); // The mask for the exponent bits. static const Bits kExponentBitMask = ~(kSignBitMask | kFractionBitMask); // How many ULP's (Units in the Last Place) we want to tolerate when // comparing two numbers. The larger the value, the more error we // allow. A 0 value means that two numbers must be exactly the same // to be considered equal. // // The maximum error of a single floating-point operation is 0.5 // units in the last place. On Intel CPU's, all floating-point // calculations are done with 80-bit precision, while double has 64 // bits. Therefore, 4 should be enough for ordinary use. // // See the following article for more details on ULP: // http://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/ static const size_t kMaxUlps = 4; // Constructs a FloatingPoint from a raw floating-point number. // // On an Intel CPU, passing a non-normalized NAN (Not a Number) // around may change its bits, although the new value is guaranteed // to be also a NAN. Therefore, don't expect this constructor to // preserve the bits in x when x is a NAN. explicit FloatingPoint(const RawType& x) { u_.value_ = x; } // Static methods // Reinterprets a bit pattern as a floating-point number. // // This function is needed to test the AlmostEquals() method. static RawType ReinterpretBits(const Bits bits) { FloatingPoint fp(0); fp.u_.bits_ = bits; return fp.u_.value_; } // Returns the floating-point number that represent positive infinity. static RawType Infinity() { return ReinterpretBits(kExponentBitMask); } // Returns the maximum representable finite floating-point number. static RawType Max(); // Non-static methods // Returns the bits that represents this number. const Bits &bits() const { return u_.bits_; } // Returns the exponent bits of this number. Bits exponent_bits() const { return kExponentBitMask & u_.bits_; } // Returns the fraction bits of this number. Bits fraction_bits() const { return kFractionBitMask & u_.bits_; } // Returns the sign bit of this number. Bits sign_bit() const { return kSignBitMask & u_.bits_; } // Returns true iff this is NAN (not a number). bool is_nan() const { // It's a NAN if the exponent bits are all ones and the fraction // bits are not entirely zeros. return (exponent_bits() == kExponentBitMask) && (fraction_bits() != 0); } // Returns true iff this number is at most kMaxUlps ULP's away from // rhs. In particular, this function: // // - returns false if either number is (or both are) NAN. // - treats really large numbers as almost equal to infinity. // - thinks +0.0 and -0.0 are 0 DLP's apart. bool AlmostEquals(const FloatingPoint& rhs) const { // The IEEE standard says that any comparison operation involving // a NAN must return false. if (is_nan() || rhs.is_nan()) return false; return DistanceBetweenSignAndMagnitudeNumbers(u_.bits_, rhs.u_.bits_) <= kMaxUlps; } private: // The data type used to store the actual floating-point number. union FloatingPointUnion { RawType value_; // The raw floating-point number. Bits bits_; // The bits that represent the number. }; // Converts an integer from the sign-and-magnitude representation to // the biased representation. More precisely, let N be 2 to the // power of (kBitCount - 1), an integer x is represented by the // unsigned number x + N. // // For instance, // // -N + 1 (the most negative number representable using // sign-and-magnitude) is represented by 1; // 0 is represented by N; and // N - 1 (the biggest number representable using // sign-and-magnitude) is represented by 2N - 1. // // Read http://en.wikipedia.org/wiki/Signed_number_representations // for more details on signed number representations. static Bits SignAndMagnitudeToBiased(const Bits &sam) { if (kSignBitMask & sam) { // sam represents a negative number. return ~sam + 1; } else { // sam represents a positive number. return kSignBitMask | sam; } } // Given two numbers in the sign-and-magnitude representation, // returns the distance between them as an unsigned number. static Bits DistanceBetweenSignAndMagnitudeNumbers(const Bits &sam1, const Bits &sam2) { const Bits biased1 = SignAndMagnitudeToBiased(sam1); const Bits biased2 = SignAndMagnitudeToBiased(sam2); return (biased1 >= biased2) ? (biased1 - biased2) : (biased2 - biased1); } FloatingPointUnion u_; }; // We cannot use std::numeric_limits::max() as it clashes with the max() // macro defined by . template <> inline float FloatingPoint::Max() { return FLT_MAX; } template <> inline double FloatingPoint::Max() { return DBL_MAX; } // Typedefs the instances of the FloatingPoint template class that we // care to use. typedef FloatingPoint Float; typedef FloatingPoint Double; // In order to catch the mistake of putting tests that use different // test fixture classes in the same test case, we need to assign // unique IDs to fixture classes and compare them. The TypeId type is // used to hold such IDs. The user should treat TypeId as an opaque // type: the only operation allowed on TypeId values is to compare // them for equality using the == operator. typedef const void* TypeId; template class TypeIdHelper { public: // dummy_ must not have a const type. Otherwise an overly eager // compiler (e.g. MSVC 7.1 & 8.0) may try to merge // TypeIdHelper::dummy_ for different Ts as an "optimization". static bool dummy_; }; template bool TypeIdHelper::dummy_ = false; // GetTypeId() returns the ID of type T. Different values will be // returned for different types. Calling the function twice with the // same type argument is guaranteed to return the same ID. template TypeId GetTypeId() { // The compiler is required to allocate a different // TypeIdHelper::dummy_ variable for each T used to instantiate // the template. Therefore, the address of dummy_ is guaranteed to // be unique. return &(TypeIdHelper::dummy_); } // Returns the type ID of ::testing::Test. Always call this instead // of GetTypeId< ::testing::Test>() to get the type ID of // ::testing::Test, as the latter may give the wrong result due to a // suspected linker bug when compiling Google Test as a Mac OS X // framework. GTEST_API_ TypeId GetTestTypeId(); // Defines the abstract factory interface that creates instances // of a Test object. class TestFactoryBase { public: virtual ~TestFactoryBase() {} // Creates a test instance to run. The instance is both created and destroyed // within TestInfoImpl::Run() virtual Test* CreateTest() = 0; protected: TestFactoryBase() {} private: GTEST_DISALLOW_COPY_AND_ASSIGN_(TestFactoryBase); }; // This class provides implementation of TeastFactoryBase interface. // It is used in TEST and TEST_F macros. template class TestFactoryImpl : public TestFactoryBase { public: virtual Test* CreateTest() { return new TestClass; } }; #if GTEST_OS_WINDOWS // Predicate-formatters for implementing the HRESULT checking macros // {ASSERT|EXPECT}_HRESULT_{SUCCEEDED|FAILED} // We pass a long instead of HRESULT to avoid causing an // include dependency for the HRESULT type. GTEST_API_ AssertionResult IsHRESULTSuccess(const char* expr, long hr); // NOLINT GTEST_API_ AssertionResult IsHRESULTFailure(const char* expr, long hr); // NOLINT #endif // GTEST_OS_WINDOWS // Types of SetUpTestCase() and TearDownTestCase() functions. typedef void(*SetUpTestCaseFunc)(); typedef void(*TearDownTestCaseFunc)(); // Creates a new TestInfo object and registers it with Google Test; // returns the created object. // // Arguments: // // test_case_name: name of the test case // name: name of the test // type_param the name of the test's type parameter, or NULL if // this is not a typed or a type-parameterized test. // value_param text representation of the test's value parameter, // or NULL if this is not a type-parameterized test. // fixture_class_id: ID of the test fixture class // set_up_tc: pointer to the function that sets up the test case // tear_down_tc: pointer to the function that tears down the test case // factory: pointer to the factory that creates a test object. // The newly created TestInfo instance will assume // ownership of the factory object. GTEST_API_ TestInfo* MakeAndRegisterTestInfo( const char* test_case_name, const char* name, const char* type_param, const char* value_param, TypeId fixture_class_id, SetUpTestCaseFunc set_up_tc, TearDownTestCaseFunc tear_down_tc, TestFactoryBase* factory); // If *pstr starts with the given prefix, modifies *pstr to be right // past the prefix and returns true; otherwise leaves *pstr unchanged // and returns false. None of pstr, *pstr, and prefix can be NULL. GTEST_API_ bool SkipPrefix(const char* prefix, const char** pstr); #if GTEST_HAS_TYPED_TEST || GTEST_HAS_TYPED_TEST_P // State of the definition of a type-parameterized test case. class GTEST_API_ TypedTestCasePState { public: TypedTestCasePState() : registered_(false) {} // Adds the given test name to defined_test_names_ and return true // if the test case hasn't been registered; otherwise aborts the // program. bool AddTestName(const char* file, int line, const char* case_name, const char* test_name) { if (registered_) { fprintf(stderr, "%s Test %s must be defined before " "REGISTER_TYPED_TEST_CASE_P(%s, ...).\n", FormatFileLocation(file, line).c_str(), test_name, case_name); fflush(stderr); posix::Abort(); } defined_test_names_.insert(test_name); return true; } // Verifies that registered_tests match the test names in // defined_test_names_; returns registered_tests if successful, or // aborts the program otherwise. const char* VerifyRegisteredTestNames( const char* file, int line, const char* registered_tests); private: bool registered_; ::std::set defined_test_names_; }; // Skips to the first non-space char after the first comma in 'str'; // returns NULL if no comma is found in 'str'. inline const char* SkipComma(const char* str) { const char* comma = strchr(str, ','); if (comma == NULL) { return NULL; } while (IsSpace(*(++comma))) {} return comma; } // Returns the prefix of 'str' before the first comma in it; returns // the entire string if it contains no comma. inline std::string GetPrefixUntilComma(const char* str) { const char* comma = strchr(str, ','); return comma == NULL ? str : std::string(str, comma); } // TypeParameterizedTest::Register() // registers a list of type-parameterized tests with Google Test. The // return value is insignificant - we just need to return something // such that we can call this function in a namespace scope. // // Implementation note: The GTEST_TEMPLATE_ macro declares a template // template parameter. It's defined in gtest-type-util.h. template class TypeParameterizedTest { public: // 'index' is the index of the test in the type list 'Types' // specified in INSTANTIATE_TYPED_TEST_CASE_P(Prefix, TestCase, // Types). Valid values for 'index' are [0, N - 1] where N is the // length of Types. static bool Register(const char* prefix, const char* case_name, const char* test_names, int index) { typedef typename Types::Head Type; typedef Fixture FixtureClass; typedef typename GTEST_BIND_(TestSel, Type) TestClass; // First, registers the first type-parameterized test in the type // list. MakeAndRegisterTestInfo( (std::string(prefix) + (prefix[0] == '\0' ? "" : "/") + case_name + "/" + StreamableToString(index)).c_str(), GetPrefixUntilComma(test_names).c_str(), GetTypeName().c_str(), NULL, // No value parameter. GetTypeId(), TestClass::SetUpTestCase, TestClass::TearDownTestCase, new TestFactoryImpl); // Next, recurses (at compile time) with the tail of the type list. return TypeParameterizedTest ::Register(prefix, case_name, test_names, index + 1); } }; // The base case for the compile time recursion. template class TypeParameterizedTest { public: static bool Register(const char* /*prefix*/, const char* /*case_name*/, const char* /*test_names*/, int /*index*/) { return true; } }; // TypeParameterizedTestCase::Register() // registers *all combinations* of 'Tests' and 'Types' with Google // Test. The return value is insignificant - we just need to return // something such that we can call this function in a namespace scope. template class TypeParameterizedTestCase { public: static bool Register(const char* prefix, const char* case_name, const char* test_names) { typedef typename Tests::Head Head; // First, register the first test in 'Test' for each type in 'Types'. TypeParameterizedTest::Register( prefix, case_name, test_names, 0); // Next, recurses (at compile time) with the tail of the test list. return TypeParameterizedTestCase ::Register(prefix, case_name, SkipComma(test_names)); } }; // The base case for the compile time recursion. template class TypeParameterizedTestCase { public: static bool Register(const char* /*prefix*/, const char* /*case_name*/, const char* /*test_names*/) { return true; } }; #endif // GTEST_HAS_TYPED_TEST || GTEST_HAS_TYPED_TEST_P // Returns the current OS stack trace as an std::string. // // The maximum number of stack frames to be included is specified by // the gtest_stack_trace_depth flag. The skip_count parameter // specifies the number of top frames to be skipped, which doesn't // count against the number of frames to be included. // // For example, if Foo() calls Bar(), which in turn calls // GetCurrentOsStackTraceExceptTop(..., 1), Foo() will be included in // the trace but Bar() and GetCurrentOsStackTraceExceptTop() won't. GTEST_API_ std::string GetCurrentOsStackTraceExceptTop( UnitTest* unit_test, int skip_count); // Helpers for suppressing warnings on unreachable code or constant // condition. // Always returns true. GTEST_API_ bool AlwaysTrue(); // Always returns false. inline bool AlwaysFalse() { return !AlwaysTrue(); } // Helper for suppressing false warning from Clang on a const char* // variable declared in a conditional expression always being NULL in // the else branch. struct GTEST_API_ ConstCharPtr { ConstCharPtr(const char* str) : value(str) {} operator bool() const { return true; } const char* value; }; // A simple Linear Congruential Generator for generating random // numbers with a uniform distribution. Unlike rand() and srand(), it // doesn't use global state (and therefore can't interfere with user // code). Unlike rand_r(), it's portable. An LCG isn't very random, // but it's good enough for our purposes. class GTEST_API_ Random { public: static const UInt32 kMaxRange = 1u << 31; explicit Random(UInt32 seed) : state_(seed) {} void Reseed(UInt32 seed) { state_ = seed; } // Generates a random number from [0, range). Crashes if 'range' is // 0 or greater than kMaxRange. UInt32 Generate(UInt32 range); private: UInt32 state_; GTEST_DISALLOW_COPY_AND_ASSIGN_(Random); }; // Defining a variable of type CompileAssertTypesEqual will cause a // compiler error iff T1 and T2 are different types. template struct CompileAssertTypesEqual; template struct CompileAssertTypesEqual { }; // Removes the reference from a type if it is a reference type, // otherwise leaves it unchanged. This is the same as // tr1::remove_reference, which is not widely available yet. template struct RemoveReference { typedef T type; }; // NOLINT template struct RemoveReference { typedef T type; }; // NOLINT // A handy wrapper around RemoveReference that works when the argument // T depends on template parameters. #define GTEST_REMOVE_REFERENCE_(T) \ typename ::testing::internal::RemoveReference::type // Removes const from a type if it is a const type, otherwise leaves // it unchanged. This is the same as tr1::remove_const, which is not // widely available yet. template struct RemoveConst { typedef T type; }; // NOLINT template struct RemoveConst { typedef T type; }; // NOLINT // MSVC 8.0, Sun C++, and IBM XL C++ have a bug which causes the above // definition to fail to remove the const in 'const int[3]' and 'const // char[3][4]'. The following specialization works around the bug. template struct RemoveConst { typedef typename RemoveConst::type type[N]; }; #if defined(_MSC_VER) && _MSC_VER < 1400 // This is the only specialization that allows VC++ 7.1 to remove const in // 'const int[3] and 'const int[3][4]'. However, it causes trouble with GCC // and thus needs to be conditionally compiled. template struct RemoveConst { typedef typename RemoveConst::type type[N]; }; #endif // A handy wrapper around RemoveConst that works when the argument // T depends on template parameters. #define GTEST_REMOVE_CONST_(T) \ typename ::testing::internal::RemoveConst::type // Turns const U&, U&, const U, and U all into U. #define GTEST_REMOVE_REFERENCE_AND_CONST_(T) \ GTEST_REMOVE_CONST_(GTEST_REMOVE_REFERENCE_(T)) // Adds reference to a type if it is not a reference type, // otherwise leaves it unchanged. This is the same as // tr1::add_reference, which is not widely available yet. template struct AddReference { typedef T& type; }; // NOLINT template struct AddReference { typedef T& type; }; // NOLINT // A handy wrapper around AddReference that works when the argument T // depends on template parameters. #define GTEST_ADD_REFERENCE_(T) \ typename ::testing::internal::AddReference::type // Adds a reference to const on top of T as necessary. For example, // it transforms // // char ==> const char& // const char ==> const char& // char& ==> const char& // const char& ==> const char& // // The argument T must depend on some template parameters. #define GTEST_REFERENCE_TO_CONST_(T) \ GTEST_ADD_REFERENCE_(const GTEST_REMOVE_REFERENCE_(T)) // ImplicitlyConvertible::value is a compile-time bool // constant that's true iff type From can be implicitly converted to // type To. template class ImplicitlyConvertible { private: // We need the following helper functions only for their types. // They have no implementations. // MakeFrom() is an expression whose type is From. We cannot simply // use From(), as the type From may not have a public default // constructor. static From MakeFrom(); // These two functions are overloaded. Given an expression // Helper(x), the compiler will pick the first version if x can be // implicitly converted to type To; otherwise it will pick the // second version. // // The first version returns a value of size 1, and the second // version returns a value of size 2. Therefore, by checking the // size of Helper(x), which can be done at compile time, we can tell // which version of Helper() is used, and hence whether x can be // implicitly converted to type To. static char Helper(To); static char(&Helper(...))[2]; // NOLINT // We have to put the 'public' section after the 'private' section, // or MSVC refuses to compile the code. public: // MSVC warns about implicitly converting from double to int for // possible loss of data, so we need to temporarily disable the // warning. #ifdef _MSC_VER # pragma warning(push) // Saves the current warning state. # pragma warning(disable:4244) // Temporarily disables warning 4244. static const bool value = sizeof(Helper(ImplicitlyConvertible::MakeFrom())) == 1; # pragma warning(pop) // Restores the warning state. #elif defined(__BORLANDC__) // C++Builder cannot use member overload resolution during template // instantiation. The simplest workaround is to use its C++0x type traits // functions (C++Builder 2009 and above only). static const bool value = __is_convertible(From, To); #else static const bool value = sizeof(Helper(ImplicitlyConvertible::MakeFrom())) == 1; #endif // _MSV_VER }; template const bool ImplicitlyConvertible::value; // IsAProtocolMessage::value is a compile-time bool constant that's // true iff T is type ProtocolMessage, proto2::Message, or a subclass // of those. template struct IsAProtocolMessage : public bool_constant< ImplicitlyConvertible::value || ImplicitlyConvertible::value> { }; // When the compiler sees expression IsContainerTest(0), if C is an // STL-style container class, the first overload of IsContainerTest // will be viable (since both C::iterator* and C::const_iterator* are // valid types and NULL can be implicitly converted to them). It will // be picked over the second overload as 'int' is a perfect match for // the type of argument 0. If C::iterator or C::const_iterator is not // a valid type, the first overload is not viable, and the second // overload will be picked. Therefore, we can determine whether C is // a container class by checking the type of IsContainerTest(0). // The value of the expression is insignificant. // // Note that we look for both C::iterator and C::const_iterator. The // reason is that C++ injects the name of a class as a member of the // class itself (e.g. you can refer to class iterator as either // 'iterator' or 'iterator::iterator'). If we look for C::iterator // only, for example, we would mistakenly think that a class named // iterator is an STL container. // // Also note that the simpler approach of overloading // IsContainerTest(typename C::const_iterator*) and // IsContainerTest(...) doesn't work with Visual Age C++ and Sun C++. typedef int IsContainer; template IsContainer IsContainerTest(int /* dummy */, typename C::iterator* /* it */ = NULL, typename C::const_iterator* /* const_it */ = NULL) { return 0; } typedef char IsNotContainer; template IsNotContainer IsContainerTest(long /* dummy */) { return '\0'; } // EnableIf::type is void when 'Cond' is true, and // undefined when 'Cond' is false. To use SFINAE to make a function // overload only apply when a particular expression is true, add // "typename EnableIf::type* = 0" as the last parameter. template struct EnableIf; template<> struct EnableIf { typedef void type; }; // NOLINT // Utilities for native arrays. // ArrayEq() compares two k-dimensional native arrays using the // elements' operator==, where k can be any integer >= 0. When k is // 0, ArrayEq() degenerates into comparing a single pair of values. template bool ArrayEq(const T* lhs, size_t size, const U* rhs); // This generic version is used when k is 0. template inline bool ArrayEq(const T& lhs, const U& rhs) { return lhs == rhs; } // This overload is used when k >= 1. template inline bool ArrayEq(const T(&lhs)[N], const U(&rhs)[N]) { return internal::ArrayEq(lhs, N, rhs); } // This helper reduces code bloat. If we instead put its logic inside // the previous ArrayEq() function, arrays with different sizes would // lead to different copies of the template code. template bool ArrayEq(const T* lhs, size_t size, const U* rhs) { for (size_t i = 0; i != size; i++) { if (!internal::ArrayEq(lhs[i], rhs[i])) return false; } return true; } // Finds the first element in the iterator range [begin, end) that // equals elem. Element may be a native array type itself. template Iter ArrayAwareFind(Iter begin, Iter end, const Element& elem) { for (Iter it = begin; it != end; ++it) { if (internal::ArrayEq(*it, elem)) return it; } return end; } // CopyArray() copies a k-dimensional native array using the elements' // operator=, where k can be any integer >= 0. When k is 0, // CopyArray() degenerates into copying a single value. template void CopyArray(const T* from, size_t size, U* to); // This generic version is used when k is 0. template inline void CopyArray(const T& from, U* to) { *to = from; } // This overload is used when k >= 1. template inline void CopyArray(const T(&from)[N], U(*to)[N]) { internal::CopyArray(from, N, *to); } // This helper reduces code bloat. If we instead put its logic inside // the previous CopyArray() function, arrays with different sizes // would lead to different copies of the template code. template void CopyArray(const T* from, size_t size, U* to) { for (size_t i = 0; i != size; i++) { internal::CopyArray(from[i], to + i); } } // The relation between an NativeArray object (see below) and the // native array it represents. enum RelationToSource { kReference, // The NativeArray references the native array. kCopy // The NativeArray makes a copy of the native array and // owns the copy. }; // Adapts a native array to a read-only STL-style container. Instead // of the complete STL container concept, this adaptor only implements // members useful for Google Mock's container matchers. New members // should be added as needed. To simplify the implementation, we only // support Element being a raw type (i.e. having no top-level const or // reference modifier). It's the client's responsibility to satisfy // this requirement. Element can be an array type itself (hence // multi-dimensional arrays are supported). template class NativeArray { public: // STL-style container typedefs. typedef Element value_type; typedef Element* iterator; typedef const Element* const_iterator; // Constructs from a native array. NativeArray(const Element* array, size_t count, RelationToSource relation) { Init(array, count, relation); } // Copy constructor. NativeArray(const NativeArray& rhs) { Init(rhs.array_, rhs.size_, rhs.relation_to_source_); } ~NativeArray() { // Ensures that the user doesn't instantiate NativeArray with a // const or reference type. static_cast(StaticAssertTypeEqHelper()); if (relation_to_source_ == kCopy) delete[] array_; } // STL-style container methods. size_t size() const { return size_; } const_iterator begin() const { return array_; } const_iterator end() const { return array_ + size_; } bool operator==(const NativeArray& rhs) const { return size() == rhs.size() && ArrayEq(begin(), size(), rhs.begin()); } private: // Initializes this object; makes a copy of the input array if // 'relation' is kCopy. void Init(const Element* array, size_t a_size, RelationToSource relation) { if (relation == kReference) { array_ = array; } else { Element* const copy = new Element[a_size]; CopyArray(array, a_size, copy); array_ = copy; } size_ = a_size; relation_to_source_ = relation; } const Element* array_; size_t size_; RelationToSource relation_to_source_; GTEST_DISALLOW_ASSIGN_(NativeArray); }; } // namespace internal } // namespace testing #define GTEST_MESSAGE_AT_(file, line, message, result_type) \ ::testing::internal::AssertHelper(result_type, file, line, message) \ = ::testing::Message() #define GTEST_MESSAGE_(message, result_type) \ GTEST_MESSAGE_AT_(__FILE__, __LINE__, message, result_type) #define GTEST_FATAL_FAILURE_(message) \ return GTEST_MESSAGE_(message, ::testing::TestPartResult::kFatalFailure) #define GTEST_NONFATAL_FAILURE_(message) \ GTEST_MESSAGE_(message, ::testing::TestPartResult::kNonFatalFailure) #define GTEST_SUCCESS_(message) \ GTEST_MESSAGE_(message, ::testing::TestPartResult::kSuccess) // Suppresses MSVC warnings 4072 (unreachable code) for the code following // statement if it returns or throws (or doesn't return or throw in some // situations). #define GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement) \ if (::testing::internal::AlwaysTrue()) { statement; } #define GTEST_TEST_THROW_(statement, expected_exception, fail) \ GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ if (::testing::internal::ConstCharPtr gtest_msg = "") { \ bool gtest_caught_expected = false; \ try { \ GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \ } \ catch (expected_exception const&) { \ gtest_caught_expected = true; \ } \ catch (...) { \ gtest_msg.value = \ "Expected: " #statement " throws an exception of type " \ #expected_exception ".\n Actual: it throws a different type."; \ goto GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__); \ } \ if (!gtest_caught_expected) { \ gtest_msg.value = \ "Expected: " #statement " throws an exception of type " \ #expected_exception ".\n Actual: it throws nothing."; \ goto GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__); \ } \ } else \ GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__) : \ fail(gtest_msg.value) #define GTEST_TEST_NO_THROW_(statement, fail) \ GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ if (::testing::internal::AlwaysTrue()) { \ try { \ GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \} \ catch (...) { \ goto GTEST_CONCAT_TOKEN_(gtest_label_testnothrow_, __LINE__); \ } \ } else \ GTEST_CONCAT_TOKEN_(gtest_label_testnothrow_, __LINE__) : \ fail("Expected: " #statement " doesn't throw an exception.\n" \ " Actual: it throws.") #define GTEST_TEST_ANY_THROW_(statement, fail) \ GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ if (::testing::internal::AlwaysTrue()) { \ bool gtest_caught_any = false; \ try { \ GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \ } \ catch (...) { \ gtest_caught_any = true; \ } \ if (!gtest_caught_any) { \ goto GTEST_CONCAT_TOKEN_(gtest_label_testanythrow_, __LINE__); \ } \ } else \ GTEST_CONCAT_TOKEN_(gtest_label_testanythrow_, __LINE__) : \ fail("Expected: " #statement " throws an exception.\n" \ " Actual: it doesn't.") // Implements Boolean test assertions such as EXPECT_TRUE. expression can be // either a boolean expression or an AssertionResult. text is a textual // represenation of expression as it was passed into the EXPECT_TRUE. #define GTEST_TEST_BOOLEAN_(expression, text, actual, expected, fail) \ GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ if (const ::testing::AssertionResult gtest_ar_ = \ ::testing::AssertionResult(expression)) \ ; \ else \ fail(::testing::internal::GetBoolAssertionFailureMessage(\ gtest_ar_, text, #actual, #expected).c_str()) #define GTEST_TEST_NO_FATAL_FAILURE_(statement, fail) \ GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ if (::testing::internal::AlwaysTrue()) { \ ::testing::internal::HasNewFatalFailureHelper gtest_fatal_failure_checker; \ GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \ if (gtest_fatal_failure_checker.has_new_fatal_failure()) { \ goto GTEST_CONCAT_TOKEN_(gtest_label_testnofatal_, __LINE__); \ } \ } else \ GTEST_CONCAT_TOKEN_(gtest_label_testnofatal_, __LINE__) : \ fail("Expected: " #statement " doesn't generate new fatal " \ "failures in the current thread.\n" \ " Actual: it does.") // Expands to the name of the class that implements the given test. #define GTEST_TEST_CLASS_NAME_(test_case_name, test_name) \ test_case_name##_##test_name##_Test // Helper macro for defining tests. #define GTEST_TEST_(test_case_name, test_name, parent_class, parent_id)\ class GTEST_TEST_CLASS_NAME_(test_case_name, test_name) : public parent_class{ \ public:\ GTEST_TEST_CLASS_NAME_(test_case_name, test_name)() {}\ private:\ virtual void TestBody(); \ static ::testing::TestInfo* const test_info_ GTEST_ATTRIBUTE_UNUSED_; \ GTEST_DISALLOW_COPY_AND_ASSIGN_(\ GTEST_TEST_CLASS_NAME_(test_case_name, test_name)); \ }; \ \ ::testing::TestInfo* const GTEST_TEST_CLASS_NAME_(test_case_name, test_name)\ ::test_info_ = \ ::testing::internal::MakeAndRegisterTestInfo(\ #test_case_name, #test_name, NULL, NULL, \ (parent_id), \ parent_class::SetUpTestCase, \ parent_class::TearDownTestCase, \ new ::testing::internal::TestFactoryImpl<\ GTEST_TEST_CLASS_NAME_(test_case_name, test_name)>); \ void GTEST_TEST_CLASS_NAME_(test_case_name, test_name)::TestBody() #endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_INTERNAL_H_ // Copyright 2005, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // Author: wan@google.com (Zhanyong Wan) // // The Google C++ Testing Framework (Google Test) // // This header file defines the public API for death tests. It is // #included by gtest.h so a user doesn't need to include this // directly. #ifndef GTEST_INCLUDE_GTEST_GTEST_DEATH_TEST_H_ #define GTEST_INCLUDE_GTEST_GTEST_DEATH_TEST_H_ // Copyright 2005, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // Authors: wan@google.com (Zhanyong Wan), eefacm@gmail.com (Sean Mcafee) // // The Google C++ Testing Framework (Google Test) // // This header file defines internal utilities needed for implementing // death tests. They are subject to change without notice. #ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_DEATH_TEST_INTERNAL_H_ #define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_DEATH_TEST_INTERNAL_H_ #include namespace testing { namespace internal { GTEST_DECLARE_string_(internal_run_death_test); // Names of the flags (needed for parsing Google Test flags). const char kDeathTestStyleFlag[] = "death_test_style"; const char kDeathTestUseFork[] = "death_test_use_fork"; const char kInternalRunDeathTestFlag[] = "internal_run_death_test"; #if GTEST_HAS_DEATH_TEST // DeathTest is a class that hides much of the complexity of the // GTEST_DEATH_TEST_ macro. It is abstract; its static Create method // returns a concrete class that depends on the prevailing death test // style, as defined by the --gtest_death_test_style and/or // --gtest_internal_run_death_test flags. // In describing the results of death tests, these terms are used with // the corresponding definitions: // // exit status: The integer exit information in the format specified // by wait(2) // exit code: The integer code passed to exit(3), _exit(2), or // returned from main() class GTEST_API_ DeathTest { public: // Create returns false if there was an error determining the // appropriate action to take for the current death test; for example, // if the gtest_death_test_style flag is set to an invalid value. // The LastMessage method will return a more detailed message in that // case. Otherwise, the DeathTest pointer pointed to by the "test" // argument is set. If the death test should be skipped, the pointer // is set to NULL; otherwise, it is set to the address of a new concrete // DeathTest object that controls the execution of the current test. static bool Create(const char* statement, const RE* regex, const char* file, int line, DeathTest** test); DeathTest(); virtual ~DeathTest() { } // A helper class that aborts a death test when it's deleted. class ReturnSentinel { public: explicit ReturnSentinel(DeathTest* test) : test_(test) { } ~ReturnSentinel() { test_->Abort(TEST_ENCOUNTERED_RETURN_STATEMENT); } private: DeathTest* const test_; GTEST_DISALLOW_COPY_AND_ASSIGN_(ReturnSentinel); } GTEST_ATTRIBUTE_UNUSED_; // An enumeration of possible roles that may be taken when a death // test is encountered. EXECUTE means that the death test logic should // be executed immediately. OVERSEE means that the program should prepare // the appropriate environment for a child process to execute the death // test, then wait for it to complete. enum TestRole { OVERSEE_TEST, EXECUTE_TEST }; // An enumeration of the three reasons that a test might be aborted. enum AbortReason { TEST_ENCOUNTERED_RETURN_STATEMENT, TEST_THREW_EXCEPTION, TEST_DID_NOT_DIE }; // Assumes one of the above roles. virtual TestRole AssumeRole() = 0; // Waits for the death test to finish and returns its status. virtual int Wait() = 0; // Returns true if the death test passed; that is, the test process // exited during the test, its exit status matches a user-supplied // predicate, and its stderr output matches a user-supplied regular // expression. // The user-supplied predicate may be a macro expression rather // than a function pointer or functor, or else Wait and Passed could // be combined. virtual bool Passed(bool exit_status_ok) = 0; // Signals that the death test did not die as expected. virtual void Abort(AbortReason reason) = 0; // Returns a human-readable outcome message regarding the outcome of // the last death test. static const char* LastMessage(); static void set_last_death_test_message(const std::string& message); private: // A string containing a description of the outcome of the last death test. static std::string last_death_test_message_; GTEST_DISALLOW_COPY_AND_ASSIGN_(DeathTest); }; // Factory interface for death tests. May be mocked out for testing. class DeathTestFactory { public: virtual ~DeathTestFactory() { } virtual bool Create(const char* statement, const RE* regex, const char* file, int line, DeathTest** test) = 0; }; // A concrete DeathTestFactory implementation for normal use. class DefaultDeathTestFactory : public DeathTestFactory { public: virtual bool Create(const char* statement, const RE* regex, const char* file, int line, DeathTest** test); }; // Returns true if exit_status describes a process that was terminated // by a signal, or exited normally with a nonzero exit code. GTEST_API_ bool ExitedUnsuccessfully(int exit_status); // Traps C++ exceptions escaping statement and reports them as test // failures. Note that trapping SEH exceptions is not implemented here. # if GTEST_HAS_EXCEPTIONS # define GTEST_EXECUTE_DEATH_TEST_STATEMENT_(statement, death_test) \ try { \ GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \ } catch (const ::std::exception& gtest_exception) { \ fprintf(\ stderr, \ "\n%s: Caught std::exception-derived exception escaping the " \ "death test statement. Exception message: %s\n", \ ::testing::internal::FormatFileLocation(__FILE__, __LINE__).c_str(), \ gtest_exception.what()); \ fflush(stderr); \ death_test->Abort(::testing::internal::DeathTest::TEST_THREW_EXCEPTION); \ } catch (...) { \ death_test->Abort(::testing::internal::DeathTest::TEST_THREW_EXCEPTION); \ } # else # define GTEST_EXECUTE_DEATH_TEST_STATEMENT_(statement, death_test) \ GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement) # endif // This macro is for implementing ASSERT_DEATH*, EXPECT_DEATH*, // ASSERT_EXIT*, and EXPECT_EXIT*. # define GTEST_DEATH_TEST_(statement, predicate, regex, fail) \ GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ if (::testing::internal::AlwaysTrue()) { \ const ::testing::internal::RE& gtest_regex = (regex); \ ::testing::internal::DeathTest* gtest_dt; \ if (!::testing::internal::DeathTest::Create(#statement, >est_regex, \ __FILE__, __LINE__, >est_dt)) { \ goto GTEST_CONCAT_TOKEN_(gtest_label_, __LINE__); \ } \ if (gtest_dt != NULL) { \ ::testing::internal::scoped_ptr< ::testing::internal::DeathTest> \ gtest_dt_ptr(gtest_dt); \ switch (gtest_dt->AssumeRole()) { \ case ::testing::internal::DeathTest::OVERSEE_TEST: \ if (!gtest_dt->Passed(predicate(gtest_dt->Wait()))) { \ goto GTEST_CONCAT_TOKEN_(gtest_label_, __LINE__); \ } \ break; \ case ::testing::internal::DeathTest::EXECUTE_TEST: { \ ::testing::internal::DeathTest::ReturnSentinel \ gtest_sentinel(gtest_dt); \ GTEST_EXECUTE_DEATH_TEST_STATEMENT_(statement, gtest_dt); \ gtest_dt->Abort(::testing::internal::DeathTest::TEST_DID_NOT_DIE); \ break; \ } \ default: \ break; \ } \ } \ } else \ GTEST_CONCAT_TOKEN_(gtest_label_, __LINE__) : \ fail(::testing::internal::DeathTest::LastMessage()) // The symbol "fail" here expands to something into which a message // can be streamed. // This macro is for implementing ASSERT/EXPECT_DEBUG_DEATH when compiled in // NDEBUG mode. In this case we need the statements to be executed, the regex is // ignored, and the macro must accept a streamed message even though the message // is never printed. # define GTEST_EXECUTE_STATEMENT_(statement, regex) \ GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ if (::testing::internal::AlwaysTrue()) { \ GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \ } else \ ::testing::Message() // A class representing the parsed contents of the // --gtest_internal_run_death_test flag, as it existed when // RUN_ALL_TESTS was called. class InternalRunDeathTestFlag { public: InternalRunDeathTestFlag(const std::string& a_file, int a_line, int an_index, int a_write_fd) : file_(a_file), line_(a_line), index_(an_index), write_fd_(a_write_fd) {} ~InternalRunDeathTestFlag() { if (write_fd_ >= 0) posix::Close(write_fd_); } const std::string& file() const { return file_; } int line() const { return line_; } int index() const { return index_; } int write_fd() const { return write_fd_; } private: std::string file_; int line_; int index_; int write_fd_; GTEST_DISALLOW_COPY_AND_ASSIGN_(InternalRunDeathTestFlag); }; // Returns a newly created InternalRunDeathTestFlag object with fields // initialized from the GTEST_FLAG(internal_run_death_test) flag if // the flag is specified; otherwise returns NULL. InternalRunDeathTestFlag* ParseInternalRunDeathTestFlag(); #else // GTEST_HAS_DEATH_TEST // This macro is used for implementing macros such as // EXPECT_DEATH_IF_SUPPORTED and ASSERT_DEATH_IF_SUPPORTED on systems where // death tests are not supported. Those macros must compile on such systems // iff EXPECT_DEATH and ASSERT_DEATH compile with the same parameters on // systems that support death tests. This allows one to write such a macro // on a system that does not support death tests and be sure that it will // compile on a death-test supporting system. // // Parameters: // statement - A statement that a macro such as EXPECT_DEATH would test // for program termination. This macro has to make sure this // statement is compiled but not executed, to ensure that // EXPECT_DEATH_IF_SUPPORTED compiles with a certain // parameter iff EXPECT_DEATH compiles with it. // regex - A regex that a macro such as EXPECT_DEATH would use to test // the output of statement. This parameter has to be // compiled but not evaluated by this macro, to ensure that // this macro only accepts expressions that a macro such as // EXPECT_DEATH would accept. // terminator - Must be an empty statement for EXPECT_DEATH_IF_SUPPORTED // and a return statement for ASSERT_DEATH_IF_SUPPORTED. // This ensures that ASSERT_DEATH_IF_SUPPORTED will not // compile inside functions where ASSERT_DEATH doesn't // compile. // // The branch that has an always false condition is used to ensure that // statement and regex are compiled (and thus syntactically correct) but // never executed. The unreachable code macro protects the terminator // statement from generating an 'unreachable code' warning in case // statement unconditionally returns or throws. The Message constructor at // the end allows the syntax of streaming additional messages into the // macro, for compilational compatibility with EXPECT_DEATH/ASSERT_DEATH. # define GTEST_UNSUPPORTED_DEATH_TEST_(statement, regex, terminator) \ GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ if (::testing::internal::AlwaysTrue()) { \ GTEST_LOG_(WARNING) \ << "Death tests are not supported on this platform.\n" \ << "Statement '" #statement "' cannot be verified."; \ } else if (::testing::internal::AlwaysFalse()) { \ ::testing::internal::RE::PartialMatch(".*", (regex)); \ GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \ terminator; \ } else \ ::testing::Message() #endif // GTEST_HAS_DEATH_TEST } // namespace internal } // namespace testing #endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_DEATH_TEST_INTERNAL_H_ namespace testing { // This flag controls the style of death tests. Valid values are "threadsafe", // meaning that the death test child process will re-execute the test binary // from the start, running only a single death test, or "fast", // meaning that the child process will execute the test logic immediately // after forking. GTEST_DECLARE_string_(death_test_style); #if GTEST_HAS_DEATH_TEST namespace internal { // Returns a Boolean value indicating whether the caller is currently // executing in the context of the death test child process. Tools such as // Valgrind heap checkers may need this to modify their behavior in death // tests. IMPORTANT: This is an internal utility. Using it may break the // implementation of death tests. User code MUST NOT use it. GTEST_API_ bool InDeathTestChild(); } // namespace internal // The following macros are useful for writing death tests. // Here's what happens when an ASSERT_DEATH* or EXPECT_DEATH* is // executed: // // 1. It generates a warning if there is more than one active // thread. This is because it's safe to fork() or clone() only // when there is a single thread. // // 2. The parent process clone()s a sub-process and runs the death // test in it; the sub-process exits with code 0 at the end of the // death test, if it hasn't exited already. // // 3. The parent process waits for the sub-process to terminate. // // 4. The parent process checks the exit code and error message of // the sub-process. // // Examples: // // ASSERT_DEATH(server.SendMessage(56, "Hello"), "Invalid port number"); // for (int i = 0; i < 5; i++) { // EXPECT_DEATH(server.ProcessRequest(i), // "Invalid request .* in ProcessRequest()") // << "Failed to die on request " << i; // } // // ASSERT_EXIT(server.ExitNow(), ::testing::ExitedWithCode(0), "Exiting"); // // bool KilledBySIGHUP(int exit_code) { // return WIFSIGNALED(exit_code) && WTERMSIG(exit_code) == SIGHUP; // } // // ASSERT_EXIT(client.HangUpServer(), KilledBySIGHUP, "Hanging up!"); // // On the regular expressions used in death tests: // // On POSIX-compliant systems (*nix), we use the library, // which uses the POSIX extended regex syntax. // // On other platforms (e.g. Windows), we only support a simple regex // syntax implemented as part of Google Test. This limited // implementation should be enough most of the time when writing // death tests; though it lacks many features you can find in PCRE // or POSIX extended regex syntax. For example, we don't support // union ("x|y"), grouping ("(xy)"), brackets ("[xy]"), and // repetition count ("x{5,7}"), among others. // // Below is the syntax that we do support. We chose it to be a // subset of both PCRE and POSIX extended regex, so it's easy to // learn wherever you come from. In the following: 'A' denotes a // literal character, period (.), or a single \\ escape sequence; // 'x' and 'y' denote regular expressions; 'm' and 'n' are for // natural numbers. // // c matches any literal character c // \\d matches any decimal digit // \\D matches any character that's not a decimal digit // \\f matches \f // \\n matches \n // \\r matches \r // \\s matches any ASCII whitespace, including \n // \\S matches any character that's not a whitespace // \\t matches \t // \\v matches \v // \\w matches any letter, _, or decimal digit // \\W matches any character that \\w doesn't match // \\c matches any literal character c, which must be a punctuation // . matches any single character except \n // A? matches 0 or 1 occurrences of A // A* matches 0 or many occurrences of A // A+ matches 1 or many occurrences of A // ^ matches the beginning of a string (not that of each line) // $ matches the end of a string (not that of each line) // xy matches x followed by y // // If you accidentally use PCRE or POSIX extended regex features // not implemented by us, you will get a run-time failure. In that // case, please try to rewrite your regular expression within the // above syntax. // // This implementation is *not* meant to be as highly tuned or robust // as a compiled regex library, but should perform well enough for a // death test, which already incurs significant overhead by launching // a child process. // // Known caveats: // // A "threadsafe" style death test obtains the path to the test // program from argv[0] and re-executes it in the sub-process. For // simplicity, the current implementation doesn't search the PATH // when launching the sub-process. This means that the user must // invoke the test program via a path that contains at least one // path separator (e.g. path/to/foo_test and // /absolute/path/to/bar_test are fine, but foo_test is not). This // is rarely a problem as people usually don't put the test binary // directory in PATH. // // TODO(wan@google.com): make thread-safe death tests search the PATH. // Asserts that a given statement causes the program to exit, with an // integer exit status that satisfies predicate, and emitting error output // that matches regex. # define ASSERT_EXIT(statement, predicate, regex) \ GTEST_DEATH_TEST_(statement, predicate, regex, GTEST_FATAL_FAILURE_) // Like ASSERT_EXIT, but continues on to successive tests in the // test case, if any: # define EXPECT_EXIT(statement, predicate, regex) \ GTEST_DEATH_TEST_(statement, predicate, regex, GTEST_NONFATAL_FAILURE_) // Asserts that a given statement causes the program to exit, either by // explicitly exiting with a nonzero exit code or being killed by a // signal, and emitting error output that matches regex. # define ASSERT_DEATH(statement, regex) \ ASSERT_EXIT(statement, ::testing::internal::ExitedUnsuccessfully, regex) // Like ASSERT_DEATH, but continues on to successive tests in the // test case, if any: # define EXPECT_DEATH(statement, regex) \ EXPECT_EXIT(statement, ::testing::internal::ExitedUnsuccessfully, regex) // Two predicate classes that can be used in {ASSERT,EXPECT}_EXIT*: // Tests that an exit code describes a normal exit with a given exit code. class GTEST_API_ ExitedWithCode { public: explicit ExitedWithCode(int exit_code); bool operator()(int exit_status) const; private: // No implementation - assignment is unsupported. void operator=(const ExitedWithCode& other); const int exit_code_; }; # if !GTEST_OS_WINDOWS // Tests that an exit code describes an exit due to termination by a // given signal. class GTEST_API_ KilledBySignal { public: explicit KilledBySignal(int signum); bool operator()(int exit_status) const; private: const int signum_; }; # endif // !GTEST_OS_WINDOWS // EXPECT_DEBUG_DEATH asserts that the given statements die in debug mode. // The death testing framework causes this to have interesting semantics, // since the sideeffects of the call are only visible in opt mode, and not // in debug mode. // // In practice, this can be used to test functions that utilize the // LOG(DFATAL) macro using the following style: // // int DieInDebugOr12(int* sideeffect) { // if (sideeffect) { // *sideeffect = 12; // } // LOG(DFATAL) << "death"; // return 12; // } // // TEST(TestCase, TestDieOr12WorksInDgbAndOpt) { // int sideeffect = 0; // // Only asserts in dbg. // EXPECT_DEBUG_DEATH(DieInDebugOr12(&sideeffect), "death"); // // #ifdef NDEBUG // // opt-mode has sideeffect visible. // EXPECT_EQ(12, sideeffect); // #else // // dbg-mode no visible sideeffect. // EXPECT_EQ(0, sideeffect); // #endif // } // // This will assert that DieInDebugReturn12InOpt() crashes in debug // mode, usually due to a DCHECK or LOG(DFATAL), but returns the // appropriate fallback value (12 in this case) in opt mode. If you // need to test that a function has appropriate side-effects in opt // mode, include assertions against the side-effects. A general // pattern for this is: // // EXPECT_DEBUG_DEATH({ // // Side-effects here will have an effect after this statement in // // opt mode, but none in debug mode. // EXPECT_EQ(12, DieInDebugOr12(&sideeffect)); // }, "death"); // # ifdef NDEBUG # define EXPECT_DEBUG_DEATH(statement, regex) \ GTEST_EXECUTE_STATEMENT_(statement, regex) # define ASSERT_DEBUG_DEATH(statement, regex) \ GTEST_EXECUTE_STATEMENT_(statement, regex) # else # define EXPECT_DEBUG_DEATH(statement, regex) \ EXPECT_DEATH(statement, regex) # define ASSERT_DEBUG_DEATH(statement, regex) \ ASSERT_DEATH(statement, regex) # endif // NDEBUG for EXPECT_DEBUG_DEATH #endif // GTEST_HAS_DEATH_TEST // EXPECT_DEATH_IF_SUPPORTED(statement, regex) and // ASSERT_DEATH_IF_SUPPORTED(statement, regex) expand to real death tests if // death tests are supported; otherwise they just issue a warning. This is // useful when you are combining death test assertions with normal test // assertions in one test. #if GTEST_HAS_DEATH_TEST # define EXPECT_DEATH_IF_SUPPORTED(statement, regex) \ EXPECT_DEATH(statement, regex) # define ASSERT_DEATH_IF_SUPPORTED(statement, regex) \ ASSERT_DEATH(statement, regex) #else # define EXPECT_DEATH_IF_SUPPORTED(statement, regex) \ GTEST_UNSUPPORTED_DEATH_TEST_(statement, regex, ) # define ASSERT_DEATH_IF_SUPPORTED(statement, regex) \ GTEST_UNSUPPORTED_DEATH_TEST_(statement, regex, return) #endif } // namespace testing #endif // GTEST_INCLUDE_GTEST_GTEST_DEATH_TEST_H_ // This file was GENERATED by command: // pump.py gtest-param-test.h.pump // DO NOT EDIT BY HAND!!! // Copyright 2008, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // Authors: vladl@google.com (Vlad Losev) // // Macros and functions for implementing parameterized tests // in Google C++ Testing Framework (Google Test) // // This file is generated by a SCRIPT. DO NOT EDIT BY HAND! // #ifndef GTEST_INCLUDE_GTEST_GTEST_PARAM_TEST_H_ #define GTEST_INCLUDE_GTEST_GTEST_PARAM_TEST_H_ // Value-parameterized tests allow you to test your code with different // parameters without writing multiple copies of the same test. // // Here is how you use value-parameterized tests: #if 0 // To write value-parameterized tests, first you should define a fixture // class. It is usually derived from testing::TestWithParam (see below for // another inheritance scheme that's sometimes useful in more complicated // class hierarchies), where the type of your parameter values. // TestWithParam is itself derived from testing::Test. T can be any // copyable type. If it's a raw pointer, you are responsible for managing the // lifespan of the pointed values. class FooTest : public ::testing::TestWithParam { // You can implement all the usual class fixture members here. }; // Then, use the TEST_P macro to define as many parameterized tests // for this fixture as you want. The _P suffix is for "parameterized" // or "pattern", whichever you prefer to think. TEST_P(FooTest, DoesBlah) { // Inside a test, access the test parameter with the GetParam() method // of the TestWithParam class: EXPECT_TRUE(foo.Blah(GetParam())); ... } TEST_P(FooTest, HasBlahBlah) { ... } // Finally, you can use INSTANTIATE_TEST_CASE_P to instantiate the test // case with any set of parameters you want. Google Test defines a number // of functions for generating test parameters. They return what we call // (surprise!) parameter generators. Here is a summary of them, which // are all in the testing namespace: // // // Range(begin, end [, step]) - Yields values {begin, begin+step, // begin+step+step, ...}. The values do not // include end. step defaults to 1. // Values(v1, v2, ..., vN) - Yields values {v1, v2, ..., vN}. // ValuesIn(container) - Yields values from a C-style array, an STL // ValuesIn(begin,end) container, or an iterator range [begin, end). // Bool() - Yields sequence {false, true}. // Combine(g1, g2, ..., gN) - Yields all combinations (the Cartesian product // for the math savvy) of the values generated // by the N generators. // // For more details, see comments at the definitions of these functions below // in this file. // // The following statement will instantiate tests from the FooTest test case // each with parameter values "meeny", "miny", and "moe". INSTANTIATE_TEST_CASE_P(InstantiationName, FooTest, Values("meeny", "miny", "moe")); // To distinguish different instances of the pattern, (yes, you // can instantiate it more then once) the first argument to the // INSTANTIATE_TEST_CASE_P macro is a prefix that will be added to the // actual test case name. Remember to pick unique prefixes for different // instantiations. The tests from the instantiation above will have // these names: // // * InstantiationName/FooTest.DoesBlah/0 for "meeny" // * InstantiationName/FooTest.DoesBlah/1 for "miny" // * InstantiationName/FooTest.DoesBlah/2 for "moe" // * InstantiationName/FooTest.HasBlahBlah/0 for "meeny" // * InstantiationName/FooTest.HasBlahBlah/1 for "miny" // * InstantiationName/FooTest.HasBlahBlah/2 for "moe" // // You can use these names in --gtest_filter. // // This statement will instantiate all tests from FooTest again, each // with parameter values "cat" and "dog": const char* pets[] = { "cat", "dog" }; INSTANTIATE_TEST_CASE_P(AnotherInstantiationName, FooTest, ValuesIn(pets)); // The tests from the instantiation above will have these names: // // * AnotherInstantiationName/FooTest.DoesBlah/0 for "cat" // * AnotherInstantiationName/FooTest.DoesBlah/1 for "dog" // * AnotherInstantiationName/FooTest.HasBlahBlah/0 for "cat" // * AnotherInstantiationName/FooTest.HasBlahBlah/1 for "dog" // // Please note that INSTANTIATE_TEST_CASE_P will instantiate all tests // in the given test case, whether their definitions come before or // AFTER the INSTANTIATE_TEST_CASE_P statement. // // Please also note that generator expressions (including parameters to the // generators) are evaluated in InitGoogleTest(), after main() has started. // This allows the user on one hand, to adjust generator parameters in order // to dynamically determine a set of tests to run and on the other hand, // give the user a chance to inspect the generated tests with Google Test // reflection API before RUN_ALL_TESTS() is executed. // // You can see samples/sample7_unittest.cc and samples/sample8_unittest.cc // for more examples. // // In the future, we plan to publish the API for defining new parameter // generators. But for now this interface remains part of the internal // implementation and is subject to change. // // // A parameterized test fixture must be derived from testing::Test and from // testing::WithParamInterface, where T is the type of the parameter // values. Inheriting from TestWithParam satisfies that requirement because // TestWithParam inherits from both Test and WithParamInterface. In more // complicated hierarchies, however, it is occasionally useful to inherit // separately from Test and WithParamInterface. For example: class BaseTest : public ::testing::Test { // You can inherit all the usual members for a non-parameterized test // fixture here. }; class DerivedTest : public BaseTest, public ::testing::WithParamInterface { // The usual test fixture members go here too. }; TEST_F(BaseTest, HasFoo) { // This is an ordinary non-parameterized test. } TEST_P(DerivedTest, DoesBlah) { // GetParam works just the same here as if you inherit from TestWithParam. EXPECT_TRUE(foo.Blah(GetParam())); } #endif // 0 #if !GTEST_OS_SYMBIAN # include #endif // scripts/fuse_gtest.py depends on gtest's own header being #included // *unconditionally*. Therefore these #includes cannot be moved // inside #if GTEST_HAS_PARAM_TEST. // Copyright 2008 Google Inc. // All Rights Reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // Author: vladl@google.com (Vlad Losev) // Type and function utilities for implementing parameterized tests. #ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_H_ #define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_H_ #include #include #include // scripts/fuse_gtest.py depends on gtest's own header being #included // *unconditionally*. Therefore these #includes cannot be moved // inside #if GTEST_HAS_PARAM_TEST. // Copyright 2003 Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // Authors: Dan Egnor (egnor@google.com) // // A "smart" pointer type with reference tracking. Every pointer to a // particular object is kept on a circular linked list. When the last pointer // to an object is destroyed or reassigned, the object is deleted. // // Used properly, this deletes the object when the last reference goes away. // There are several caveats: // - Like all reference counting schemes, cycles lead to leaks. // - Each smart pointer is actually two pointers (8 bytes instead of 4). // - Every time a pointer is assigned, the entire list of pointers to that // object is traversed. This class is therefore NOT SUITABLE when there // will often be more than two or three pointers to a particular object. // - References are only tracked as long as linked_ptr<> objects are copied. // If a linked_ptr<> is converted to a raw pointer and back, BAD THINGS // will happen (double deletion). // // A good use of this class is storing object references in STL containers. // You can safely put linked_ptr<> in a vector<>. // Other uses may not be as good. // // Note: If you use an incomplete type with linked_ptr<>, the class // *containing* linked_ptr<> must have a constructor and destructor (even // if they do nothing!). // // Bill Gibbons suggested we use something like this. // // Thread Safety: // Unlike other linked_ptr implementations, in this implementation // a linked_ptr object is thread-safe in the sense that: // - it's safe to copy linked_ptr objects concurrently, // - it's safe to copy *from* a linked_ptr and read its underlying // raw pointer (e.g. via get()) concurrently, and // - it's safe to write to two linked_ptrs that point to the same // shared object concurrently. // TODO(wan@google.com): rename this to safe_linked_ptr to avoid // confusion with normal linked_ptr. #ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_LINKED_PTR_H_ #define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_LINKED_PTR_H_ #include #include namespace testing { namespace internal { // Protects copying of all linked_ptr objects. GTEST_API_ GTEST_DECLARE_STATIC_MUTEX_(g_linked_ptr_mutex); // This is used internally by all instances of linked_ptr<>. It needs to be // a non-template class because different types of linked_ptr<> can refer to // the same object (linked_ptr(obj) vs linked_ptr(obj)). // So, it needs to be possible for different types of linked_ptr to participate // in the same circular linked list, so we need a single class type here. // // DO NOT USE THIS CLASS DIRECTLY YOURSELF. Use linked_ptr. class linked_ptr_internal { public: // Create a new circle that includes only this instance. void join_new() { next_ = this; } // Many linked_ptr operations may change p.link_ for some linked_ptr // variable p in the same circle as this object. Therefore we need // to prevent two such operations from occurring concurrently. // // Note that different types of linked_ptr objects can coexist in a // circle (e.g. linked_ptr, linked_ptr, and // linked_ptr). Therefore we must use a single mutex to // protect all linked_ptr objects. This can create serious // contention in production code, but is acceptable in a testing // framework. // Join an existing circle. void join(linked_ptr_internal const* ptr) GTEST_LOCK_EXCLUDED_(g_linked_ptr_mutex) { MutexLock lock(&g_linked_ptr_mutex); linked_ptr_internal const* p = ptr; while (p->next_ != ptr) p = p->next_; p->next_ = this; next_ = ptr; } // Leave whatever circle we're part of. Returns true if we were the // last member of the circle. Once this is done, you can join() another. bool depart() GTEST_LOCK_EXCLUDED_(g_linked_ptr_mutex) { MutexLock lock(&g_linked_ptr_mutex); if (next_ == this) return true; linked_ptr_internal const* p = next_; while (p->next_ != this) p = p->next_; p->next_ = next_; return false; } private: mutable linked_ptr_internal const* next_; }; template class linked_ptr { public: typedef T element_type; // Take over ownership of a raw pointer. This should happen as soon as // possible after the object is created. explicit linked_ptr(T* ptr = NULL) { capture(ptr); } ~linked_ptr() { depart(); } // Copy an existing linked_ptr<>, adding ourselves to the list of references. template linked_ptr(linked_ptr const& ptr) { copy(&ptr); } linked_ptr(linked_ptr const& ptr) { // NOLINT assert(&ptr != this); copy(&ptr); } // Assignment releases the old value and acquires the new. template linked_ptr& operator=(linked_ptr const& ptr) { depart(); copy(&ptr); return *this; } linked_ptr& operator=(linked_ptr const& ptr) { if (&ptr != this) { depart(); copy(&ptr); } return *this; } // Smart pointer members. void reset(T* ptr = NULL) { depart(); capture(ptr); } T* get() const { return value_; } T* operator->() const { return value_; } T& operator*() const { return *value_; } bool operator==(T* p) const { return value_ == p; } bool operator!=(T* p) const { return value_ != p; } template bool operator==(linked_ptr const& ptr) const { return value_ == ptr.get(); } template bool operator!=(linked_ptr const& ptr) const { return value_ != ptr.get(); } private: template friend class linked_ptr; T* value_; linked_ptr_internal link_; void depart() { if (link_.depart()) delete value_; } void capture(T* ptr) { value_ = ptr; link_.join_new(); } template void copy(linked_ptr const* ptr) { value_ = ptr->get(); if (value_) link_.join(&ptr->link_); else link_.join_new(); } }; template inline bool operator==(T* ptr, const linked_ptr& x) { return ptr == x.get(); } template inline bool operator!=(T* ptr, const linked_ptr& x) { return ptr != x.get(); } // A function to convert T* into linked_ptr // Doing e.g. make_linked_ptr(new FooBarBaz(arg)) is a shorter notation // for linked_ptr >(new FooBarBaz(arg)) template linked_ptr make_linked_ptr(T* ptr) { return linked_ptr(ptr); } } // namespace internal } // namespace testing #endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_LINKED_PTR_H_ // Copyright 2007, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // Author: wan@google.com (Zhanyong Wan) // Google Test - The Google C++ Testing Framework // // This file implements a universal value printer that can print a // value of any type T: // // void ::testing::internal::UniversalPrinter::Print(value, ostream_ptr); // // A user can teach this function how to print a class type T by // defining either operator<<() or PrintTo() in the namespace that // defines T. More specifically, the FIRST defined function in the // following list will be used (assuming T is defined in namespace // foo): // // 1. foo::PrintTo(const T&, ostream*) // 2. operator<<(ostream&, const T&) defined in either foo or the // global namespace. // // If none of the above is defined, it will print the debug string of // the value if it is a protocol buffer, or print the raw bytes in the // value otherwise. // // To aid debugging: when T is a reference type, the address of the // value is also printed; when T is a (const) char pointer, both the // pointer value and the NUL-terminated string it points to are // printed. // // We also provide some convenient wrappers: // // // Prints a value to a string. For a (const or not) char // // pointer, the NUL-terminated string (but not the pointer) is // // printed. // std::string ::testing::PrintToString(const T& value); // // // Prints a value tersely: for a reference type, the referenced // // value (but not the address) is printed; for a (const or not) char // // pointer, the NUL-terminated string (but not the pointer) is // // printed. // void ::testing::internal::UniversalTersePrint(const T& value, ostream*); // // // Prints value using the type inferred by the compiler. The difference // // from UniversalTersePrint() is that this function prints both the // // pointer and the NUL-terminated string for a (const or not) char pointer. // void ::testing::internal::UniversalPrint(const T& value, ostream*); // // // Prints the fields of a tuple tersely to a string vector, one // // element for each field. Tuple support must be enabled in // // gtest-port.h. // std::vector UniversalTersePrintTupleFieldsToStrings( // const Tuple& value); // // Known limitation: // // The print primitives print the elements of an STL-style container // using the compiler-inferred type of *iter where iter is a // const_iterator of the container. When const_iterator is an input // iterator but not a forward iterator, this inferred type may not // match value_type, and the print output may be incorrect. In // practice, this is rarely a problem as for most containers // const_iterator is a forward iterator. We'll fix this if there's an // actual need for it. Note that this fix cannot rely on value_type // being defined as many user-defined container types don't have // value_type. #ifndef GTEST_INCLUDE_GTEST_GTEST_PRINTERS_H_ #define GTEST_INCLUDE_GTEST_GTEST_PRINTERS_H_ #include // NOLINT #include #include #include #include namespace testing { // Definitions in the 'internal' and 'internal2' name spaces are // subject to change without notice. DO NOT USE THEM IN USER CODE! namespace internal2 { // Prints the given number of bytes in the given object to the given // ostream. GTEST_API_ void PrintBytesInObjectTo(const unsigned char* obj_bytes, size_t count, ::std::ostream* os); // For selecting which printer to use when a given type has neither << // nor PrintTo(). enum TypeKind { kProtobuf, // a protobuf type kConvertibleToInteger, // a type implicitly convertible to BiggestInt // (e.g. a named or unnamed enum type) kOtherType // anything else }; // TypeWithoutFormatter::PrintValue(value, os) is called // by the universal printer to print a value of type T when neither // operator<< nor PrintTo() is defined for T, where kTypeKind is the // "kind" of T as defined by enum TypeKind. template class TypeWithoutFormatter { public: // This default version is called when kTypeKind is kOtherType. static void PrintValue(const T& value, ::std::ostream* os) { PrintBytesInObjectTo(reinterpret_cast(&value), sizeof(value), os); } }; // We print a protobuf using its ShortDebugString() when the string // doesn't exceed this many characters; otherwise we print it using // DebugString() for better readability. const size_t kProtobufOneLinerMaxLength = 50; template class TypeWithoutFormatter { public: static void PrintValue(const T& value, ::std::ostream* os) { const ::testing::internal::string short_str = value.ShortDebugString(); const ::testing::internal::string pretty_str = short_str.length() <= kProtobufOneLinerMaxLength ? short_str : ("\n" + value.DebugString()); *os << ("<" + pretty_str + ">"); } }; template class TypeWithoutFormatter { public: // Since T has no << operator or PrintTo() but can be implicitly // converted to BiggestInt, we print it as a BiggestInt. // // Most likely T is an enum type (either named or unnamed), in which // case printing it as an integer is the desired behavior. In case // T is not an enum, printing it as an integer is the best we can do // given that it has no user-defined printer. static void PrintValue(const T& value, ::std::ostream* os) { const internal::BiggestInt kBigInt = value; *os << kBigInt; } }; // Prints the given value to the given ostream. If the value is a // protocol message, its debug string is printed; if it's an enum or // of a type implicitly convertible to BiggestInt, it's printed as an // integer; otherwise the bytes in the value are printed. This is // what UniversalPrinter::Print() does when it knows nothing about // type T and T has neither << operator nor PrintTo(). // // A user can override this behavior for a class type Foo by defining // a << operator in the namespace where Foo is defined. // // We put this operator in namespace 'internal2' instead of 'internal' // to simplify the implementation, as much code in 'internal' needs to // use << in STL, which would conflict with our own << were it defined // in 'internal'. // // Note that this operator<< takes a generic std::basic_ostream type instead of the more restricted std::ostream. If // we define it to take an std::ostream instead, we'll get an // "ambiguous overloads" compiler error when trying to print a type // Foo that supports streaming to std::basic_ostream, as the compiler cannot tell whether // operator<<(std::ostream&, const T&) or // operator<<(std::basic_stream, const Foo&) is more // specific. template ::std::basic_ostream& operator<<( ::std::basic_ostream& os, const T& x) { TypeWithoutFormatter::value ? kProtobuf : internal::ImplicitlyConvertible::value ? kConvertibleToInteger : kOtherType)>::PrintValue(x, &os); return os; } } // namespace internal2 } // namespace testing // This namespace MUST NOT BE NESTED IN ::testing, or the name look-up // magic needed for implementing UniversalPrinter won't work. namespace testing_internal { // Used to print a value that is not an STL-style container when the // user doesn't define PrintTo() for it. template void DefaultPrintNonContainerTo(const T& value, ::std::ostream* os) { // With the following statement, during unqualified name lookup, // testing::internal2::operator<< appears as if it was declared in // the nearest enclosing namespace that contains both // ::testing_internal and ::testing::internal2, i.e. the global // namespace. For more details, refer to the C++ Standard section // 7.3.4-1 [namespace.udir]. This allows us to fall back onto // testing::internal2::operator<< in case T doesn't come with a << // operator. // // We cannot write 'using ::testing::internal2::operator<<;', which // gcc 3.3 fails to compile due to a compiler bug. using namespace ::testing::internal2; // NOLINT // Assuming T is defined in namespace foo, in the next statement, // the compiler will consider all of: // // 1. foo::operator<< (thanks to Koenig look-up), // 2. ::operator<< (as the current namespace is enclosed in ::), // 3. testing::internal2::operator<< (thanks to the using statement above). // // The operator<< whose type matches T best will be picked. // // We deliberately allow #2 to be a candidate, as sometimes it's // impossible to define #1 (e.g. when foo is ::std, defining // anything in it is undefined behavior unless you are a compiler // vendor.). *os << value; } } // namespace testing_internal namespace testing { namespace internal { // UniversalPrinter::Print(value, ostream_ptr) prints the given // value to the given ostream. The caller must ensure that // 'ostream_ptr' is not NULL, or the behavior is undefined. // // We define UniversalPrinter as a class template (as opposed to a // function template), as we need to partially specialize it for // reference types, which cannot be done with function templates. template class UniversalPrinter; template void UniversalPrint(const T& value, ::std::ostream* os); // Used to print an STL-style container when the user doesn't define // a PrintTo() for it. template void DefaultPrintTo(IsContainer /* dummy */, false_type /* is not a pointer */, const C& container, ::std::ostream* os) { const size_t kMaxCount = 32; // The maximum number of elements to print. *os << '{'; size_t count = 0; for (typename C::const_iterator it = container.begin(); it != container.end(); ++it, ++count) { if (count > 0) { *os << ','; if (count == kMaxCount) { // Enough has been printed. *os << " ..."; break; } } *os << ' '; // We cannot call PrintTo(*it, os) here as PrintTo() doesn't // handle *it being a native array. internal::UniversalPrint(*it, os); } if (count > 0) { *os << ' '; } *os << '}'; } // Used to print a pointer that is neither a char pointer nor a member // pointer, when the user doesn't define PrintTo() for it. (A member // variable pointer or member function pointer doesn't really point to // a location in the address space. Their representation is // implementation-defined. Therefore they will be printed as raw // bytes.) template void DefaultPrintTo(IsNotContainer /* dummy */, true_type /* is a pointer */, T* p, ::std::ostream* os) { if (p == NULL) { *os << "NULL"; } else { // C++ doesn't allow casting from a function pointer to any object // pointer. // // IsTrue() silences warnings: "Condition is always true", // "unreachable code". if (IsTrue(ImplicitlyConvertible::value)) { // T is not a function type. We just call << to print p, // relying on ADL to pick up user-defined << for their pointer // types, if any. *os << p; } else { // T is a function type, so '*os << p' doesn't do what we want // (it just prints p as bool). We want to print p as a const // void*. However, we cannot cast it to const void* directly, // even using reinterpret_cast, as earlier versions of gcc // (e.g. 3.4.5) cannot compile the cast when p is a function // pointer. Casting to UInt64 first solves the problem. *os << reinterpret_cast( reinterpret_cast(p)); } } } // Used to print a non-container, non-pointer value when the user // doesn't define PrintTo() for it. template void DefaultPrintTo(IsNotContainer /* dummy */, false_type /* is not a pointer */, const T& value, ::std::ostream* os) { ::testing_internal::DefaultPrintNonContainerTo(value, os); } // Prints the given value using the << operator if it has one; // otherwise prints the bytes in it. This is what // UniversalPrinter::Print() does when PrintTo() is not specialized // or overloaded for type T. // // A user can override this behavior for a class type Foo by defining // an overload of PrintTo() in the namespace where Foo is defined. We // give the user this option as sometimes defining a << operator for // Foo is not desirable (e.g. the coding style may prevent doing it, // or there is already a << operator but it doesn't do what the user // wants). template void PrintTo(const T& value, ::std::ostream* os) { // DefaultPrintTo() is overloaded. The type of its first two // arguments determine which version will be picked. If T is an // STL-style container, the version for container will be called; if // T is a pointer, the pointer version will be called; otherwise the // generic version will be called. // // Note that we check for container types here, prior to we check // for protocol message types in our operator<<. The rationale is: // // For protocol messages, we want to give people a chance to // override Google Mock's format by defining a PrintTo() or // operator<<. For STL containers, other formats can be // incompatible with Google Mock's format for the container // elements; therefore we check for container types here to ensure // that our format is used. // // The second argument of DefaultPrintTo() is needed to bypass a bug // in Symbian's C++ compiler that prevents it from picking the right // overload between: // // PrintTo(const T& x, ...); // PrintTo(T* x, ...); DefaultPrintTo(IsContainerTest(0), is_pointer(), value, os); } // The following list of PrintTo() overloads tells // UniversalPrinter::Print() how to print standard types (built-in // types, strings, plain arrays, and pointers). // Overloads for various char types. GTEST_API_ void PrintTo(unsigned char c, ::std::ostream* os); GTEST_API_ void PrintTo(signed char c, ::std::ostream* os); inline void PrintTo(char c, ::std::ostream* os) { // When printing a plain char, we always treat it as unsigned. This // way, the output won't be affected by whether the compiler thinks // char is signed or not. PrintTo(static_cast(c), os); } // Overloads for other simple built-in types. inline void PrintTo(bool x, ::std::ostream* os) { *os << (x ? "true" : "false"); } // Overload for wchar_t type. // Prints a wchar_t as a symbol if it is printable or as its internal // code otherwise and also as its decimal code (except for L'\0'). // The L'\0' char is printed as "L'\\0'". The decimal code is printed // as signed integer when wchar_t is implemented by the compiler // as a signed type and is printed as an unsigned integer when wchar_t // is implemented as an unsigned type. GTEST_API_ void PrintTo(wchar_t wc, ::std::ostream* os); // Overloads for C strings. GTEST_API_ void PrintTo(const char* s, ::std::ostream* os); inline void PrintTo(char* s, ::std::ostream* os) { PrintTo(ImplicitCast_(s), os); } // signed/unsigned char is often used for representing binary data, so // we print pointers to it as void* to be safe. inline void PrintTo(const signed char* s, ::std::ostream* os) { PrintTo(ImplicitCast_(s), os); } inline void PrintTo(signed char* s, ::std::ostream* os) { PrintTo(ImplicitCast_(s), os); } inline void PrintTo(const unsigned char* s, ::std::ostream* os) { PrintTo(ImplicitCast_(s), os); } inline void PrintTo(unsigned char* s, ::std::ostream* os) { PrintTo(ImplicitCast_(s), os); } // MSVC can be configured to define wchar_t as a typedef of unsigned // short. It defines _NATIVE_WCHAR_T_DEFINED when wchar_t is a native // type. When wchar_t is a typedef, defining an overload for const // wchar_t* would cause unsigned short* be printed as a wide string, // possibly causing invalid memory accesses. #if !defined(_MSC_VER) || defined(_NATIVE_WCHAR_T_DEFINED) // Overloads for wide C strings GTEST_API_ void PrintTo(const wchar_t* s, ::std::ostream* os); inline void PrintTo(wchar_t* s, ::std::ostream* os) { PrintTo(ImplicitCast_(s), os); } #endif // Overload for C arrays. Multi-dimensional arrays are printed // properly. // Prints the given number of elements in an array, without printing // the curly braces. template void PrintRawArrayTo(const T a[], size_t count, ::std::ostream* os) { UniversalPrint(a[0], os); for (size_t i = 1; i != count; i++) { *os << ", "; UniversalPrint(a[i], os); } } // Overloads for ::string and ::std::string. #if GTEST_HAS_GLOBAL_STRING GTEST_API_ void PrintStringTo(const ::string&s, ::std::ostream* os); inline void PrintTo(const ::string& s, ::std::ostream* os) { PrintStringTo(s, os); } #endif // GTEST_HAS_GLOBAL_STRING GTEST_API_ void PrintStringTo(const ::std::string&s, ::std::ostream* os); inline void PrintTo(const ::std::string& s, ::std::ostream* os) { PrintStringTo(s, os); } // Overloads for ::wstring and ::std::wstring. #if GTEST_HAS_GLOBAL_WSTRING GTEST_API_ void PrintWideStringTo(const ::wstring&s, ::std::ostream* os); inline void PrintTo(const ::wstring& s, ::std::ostream* os) { PrintWideStringTo(s, os); } #endif // GTEST_HAS_GLOBAL_WSTRING #if GTEST_HAS_STD_WSTRING GTEST_API_ void PrintWideStringTo(const ::std::wstring&s, ::std::ostream* os); inline void PrintTo(const ::std::wstring& s, ::std::ostream* os) { PrintWideStringTo(s, os); } #endif // GTEST_HAS_STD_WSTRING #if GTEST_HAS_TR1_TUPLE // Overload for ::stdt::tuple. Needed for printing function arguments, // which are packed as tuples. // Helper function for printing a tuple. T must be instantiated with // a tuple type. template void PrintTupleTo(const T& t, ::std::ostream* os); // Overloaded PrintTo() for tuples of various arities. We support // tuples of up-to 10 fields. The following implementation works // regardless of whether tr1::tuple is implemented using the // non-standard variadic template feature or not. inline void PrintTo(const ::stdt::tuple<>& t, ::std::ostream* os) { PrintTupleTo(t, os); } template void PrintTo(const ::stdt::tuple& t, ::std::ostream* os) { PrintTupleTo(t, os); } template void PrintTo(const ::stdt::tuple& t, ::std::ostream* os) { PrintTupleTo(t, os); } template void PrintTo(const ::stdt::tuple& t, ::std::ostream* os) { PrintTupleTo(t, os); } template void PrintTo(const ::stdt::tuple& t, ::std::ostream* os) { PrintTupleTo(t, os); } template void PrintTo(const ::stdt::tuple& t, ::std::ostream* os) { PrintTupleTo(t, os); } template void PrintTo(const ::stdt::tuple& t, ::std::ostream* os) { PrintTupleTo(t, os); } template void PrintTo(const ::stdt::tuple& t, ::std::ostream* os) { PrintTupleTo(t, os); } template void PrintTo(const ::stdt::tuple& t, ::std::ostream* os) { PrintTupleTo(t, os); } template void PrintTo(const ::stdt::tuple& t, ::std::ostream* os) { PrintTupleTo(t, os); } template void PrintTo( const ::stdt::tuple& t, ::std::ostream* os) { PrintTupleTo(t, os); } #endif // GTEST_HAS_TR1_TUPLE // Overload for std::pair. template void PrintTo(const ::std::pair& value, ::std::ostream* os) { *os << '('; // We cannot use UniversalPrint(value.first, os) here, as T1 may be // a reference type. The same for printing value.second. UniversalPrinter::Print(value.first, os); *os << ", "; UniversalPrinter::Print(value.second, os); *os << ')'; } // Implements printing a non-reference type T by letting the compiler // pick the right overload of PrintTo() for T. template class UniversalPrinter { public: // MSVC warns about adding const to a function type, so we want to // disable the warning. #ifdef _MSC_VER # pragma warning(push) // Saves the current warning state. # pragma warning(disable:4180) // Temporarily disables warning 4180. #endif // _MSC_VER // Note: we deliberately don't call this PrintTo(), as that name // conflicts with ::testing::internal::PrintTo in the body of the // function. static void Print(const T& value, ::std::ostream* os) { // By default, ::testing::internal::PrintTo() is used for printing // the value. // // Thanks to Koenig look-up, if T is a class and has its own // PrintTo() function defined in its namespace, that function will // be visible here. Since it is more specific than the generic ones // in ::testing::internal, it will be picked by the compiler in the // following statement - exactly what we want. PrintTo(value, os); } #ifdef _MSC_VER # pragma warning(pop) // Restores the warning state. #endif // _MSC_VER }; // UniversalPrintArray(begin, len, os) prints an array of 'len' // elements, starting at address 'begin'. template void UniversalPrintArray(const T* begin, size_t len, ::std::ostream* os) { if (len == 0) { *os << "{}"; } else { *os << "{ "; const size_t kThreshold = 18; const size_t kChunkSize = 8; // If the array has more than kThreshold elements, we'll have to // omit some details by printing only the first and the last // kChunkSize elements. // TODO(wan@google.com): let the user control the threshold using a flag. if (len <= kThreshold) { PrintRawArrayTo(begin, len, os); } else { PrintRawArrayTo(begin, kChunkSize, os); *os << ", ..., "; PrintRawArrayTo(begin + len - kChunkSize, kChunkSize, os); } *os << " }"; } } // This overload prints a (const) char array compactly. GTEST_API_ void UniversalPrintArray( const char* begin, size_t len, ::std::ostream* os); // This overload prints a (const) wchar_t array compactly. GTEST_API_ void UniversalPrintArray( const wchar_t* begin, size_t len, ::std::ostream* os); // Implements printing an array type T[N]. template class UniversalPrinter { public: // Prints the given array, omitting some elements when there are too // many. static void Print(const T(&a)[N], ::std::ostream* os) { UniversalPrintArray(a, N, os); } }; // Implements printing a reference type T&. template class UniversalPrinter { public: // MSVC warns about adding const to a function type, so we want to // disable the warning. #ifdef _MSC_VER # pragma warning(push) // Saves the current warning state. # pragma warning(disable:4180) // Temporarily disables warning 4180. #endif // _MSC_VER static void Print(const T& value, ::std::ostream* os) { // Prints the address of the value. We use reinterpret_cast here // as static_cast doesn't compile when T is a function type. *os << "@" << reinterpret_cast(&value) << " "; // Then prints the value itself. UniversalPrint(value, os); } #ifdef _MSC_VER # pragma warning(pop) // Restores the warning state. #endif // _MSC_VER }; // Prints a value tersely: for a reference type, the referenced value // (but not the address) is printed; for a (const) char pointer, the // NUL-terminated string (but not the pointer) is printed. template class UniversalTersePrinter { public: static void Print(const T& value, ::std::ostream* os) { UniversalPrint(value, os); } }; template class UniversalTersePrinter { public: static void Print(const T& value, ::std::ostream* os) { UniversalPrint(value, os); } }; template class UniversalTersePrinter { public: static void Print(const T(&value)[N], ::std::ostream* os) { UniversalPrinter::Print(value, os); } }; template <> class UniversalTersePrinter { public: static void Print(const char* str, ::std::ostream* os) { if (str == NULL) { *os << "NULL"; } else { UniversalPrint(string(str), os); } } }; template <> class UniversalTersePrinter { public: static void Print(char* str, ::std::ostream* os) { UniversalTersePrinter::Print(str, os); } }; #if GTEST_HAS_STD_WSTRING template <> class UniversalTersePrinter { public: static void Print(const wchar_t* str, ::std::ostream* os) { if (str == NULL) { *os << "NULL"; } else { UniversalPrint(::std::wstring(str), os); } } }; #endif template <> class UniversalTersePrinter { public: static void Print(wchar_t* str, ::std::ostream* os) { UniversalTersePrinter::Print(str, os); } }; template void UniversalTersePrint(const T& value, ::std::ostream* os) { UniversalTersePrinter::Print(value, os); } // Prints a value using the type inferred by the compiler. The // difference between this and UniversalTersePrint() is that for a // (const) char pointer, this prints both the pointer and the // NUL-terminated string. template void UniversalPrint(const T& value, ::std::ostream* os) { // A workarond for the bug in VC++ 7.1 that prevents us from instantiating // UniversalPrinter with T directly. typedef T T1; UniversalPrinter::Print(value, os); } #if GTEST_HAS_TR1_TUPLE typedef ::std::vector Strings; // This helper template allows PrintTo() for tuples and // UniversalTersePrintTupleFieldsToStrings() to be defined by // induction on the number of tuple fields. The idea is that // TuplePrefixPrinter::PrintPrefixTo(t, os) prints the first N // fields in tuple t, and can be defined in terms of // TuplePrefixPrinter. // The inductive case. template struct TuplePrefixPrinter { // Prints the first N fields of a tuple. template static void PrintPrefixTo(const Tuple& t, ::std::ostream* os) { TuplePrefixPrinter::PrintPrefixTo(t, os); *os << ", "; UniversalPrinter::type> ::Print(::stdt::get(t), os); } // Tersely prints the first N fields of a tuple to a string vector, // one element for each field. template static void TersePrintPrefixToStrings(const Tuple& t, Strings* strings) { TuplePrefixPrinter::TersePrintPrefixToStrings(t, strings); ::std::stringstream ss; UniversalTersePrint(::stdt::get(t), &ss); strings->push_back(ss.str()); } }; // Base cases. template <> struct TuplePrefixPrinter<0> { template static void PrintPrefixTo(const Tuple&, ::std::ostream*) {} template static void TersePrintPrefixToStrings(const Tuple&, Strings*) {} }; // We have to specialize the entire TuplePrefixPrinter<> class // template here, even though the definition of // TersePrintPrefixToStrings() is the same as the generic version, as // Embarcadero (formerly CodeGear, formerly Borland) C++ doesn't // support specializing a method template of a class template. template <> struct TuplePrefixPrinter<1> { template static void PrintPrefixTo(const Tuple& t, ::std::ostream* os) { UniversalPrinter::type>:: Print(::stdt::get<0>(t), os); } template static void TersePrintPrefixToStrings(const Tuple& t, Strings* strings) { ::std::stringstream ss; UniversalTersePrint(::stdt::get<0>(t), &ss); strings->push_back(ss.str()); } }; // Helper function for printing a tuple. T must be instantiated with // a tuple type. template void PrintTupleTo(const T& t, ::std::ostream* os) { *os << "("; TuplePrefixPrinter< ::stdt::tuple_size::value>:: PrintPrefixTo(t, os); *os << ")"; } // Prints the fields of a tuple tersely to a string vector, one // element for each field. See the comment before // UniversalTersePrint() for how we define "tersely". template Strings UniversalTersePrintTupleFieldsToStrings(const Tuple& value) { Strings result; TuplePrefixPrinter< ::stdt::tuple_size::value>:: TersePrintPrefixToStrings(value, &result); return result; } #endif // GTEST_HAS_TR1_TUPLE } // namespace internal template ::std::string PrintToString(const T& value) { ::std::stringstream ss; internal::UniversalTersePrinter::Print(value, &ss); return ss.str(); } } // namespace testing #endif // GTEST_INCLUDE_GTEST_GTEST_PRINTERS_H_ #if GTEST_HAS_PARAM_TEST namespace testing { namespace internal { // INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. // // Outputs a message explaining invalid registration of different // fixture class for the same test case. This may happen when // TEST_P macro is used to define two tests with the same name // but in different namespaces. GTEST_API_ void ReportInvalidTestCaseType(const char* test_case_name, const char* file, int line); template class ParamGeneratorInterface; template class ParamGenerator; // Interface for iterating over elements provided by an implementation // of ParamGeneratorInterface. template class ParamIteratorInterface { public: virtual ~ParamIteratorInterface() {} // A pointer to the base generator instance. // Used only for the purposes of iterator comparison // to make sure that two iterators belong to the same generator. virtual const ParamGeneratorInterface* BaseGenerator() const = 0; // Advances iterator to point to the next element // provided by the generator. The caller is responsible // for not calling Advance() on an iterator equal to // BaseGenerator()->End(). virtual void Advance() = 0; // Clones the iterator object. Used for implementing copy semantics // of ParamIterator. virtual ParamIteratorInterface* Clone() const = 0; // Dereferences the current iterator and provides (read-only) access // to the pointed value. It is the caller's responsibility not to call // Current() on an iterator equal to BaseGenerator()->End(). // Used for implementing ParamGenerator::operator*(). virtual const T* Current() const = 0; // Determines whether the given iterator and other point to the same // element in the sequence generated by the generator. // Used for implementing ParamGenerator::operator==(). virtual bool Equals(const ParamIteratorInterface& other) const = 0; }; // Class iterating over elements provided by an implementation of // ParamGeneratorInterface. It wraps ParamIteratorInterface // and implements the const forward iterator concept. template class ParamIterator { public: typedef T value_type; typedef const T& reference; typedef ptrdiff_t difference_type; // ParamIterator assumes ownership of the impl_ pointer. ParamIterator(const ParamIterator& other) : impl_(other.impl_->Clone()) {} ParamIterator& operator=(const ParamIterator& other) { if (this != &other) impl_.reset(other.impl_->Clone()); return *this; } const T& operator*() const { return *impl_->Current(); } const T* operator->() const { return impl_->Current(); } // Prefix version of operator++. ParamIterator& operator++() { impl_->Advance(); return *this; } // Postfix version of operator++. ParamIterator operator++(int /*unused*/) { ParamIteratorInterface* clone = impl_->Clone(); impl_->Advance(); return ParamIterator(clone); } bool operator==(const ParamIterator& other) const { return impl_.get() == other.impl_.get() || impl_->Equals(*other.impl_); } bool operator!=(const ParamIterator& other) const { return !(*this == other); } private: friend class ParamGenerator; explicit ParamIterator(ParamIteratorInterface* impl) : impl_(impl) {} scoped_ptr > impl_; }; // ParamGeneratorInterface is the binary interface to access generators // defined in other translation units. template class ParamGeneratorInterface { public: typedef T ParamType; virtual ~ParamGeneratorInterface() {} // Generator interface definition virtual ParamIteratorInterface* Begin() const = 0; virtual ParamIteratorInterface* End() const = 0; }; // Wraps ParamGeneratorInterface and provides general generator syntax // compatible with the STL Container concept. // This class implements copy initialization semantics and the contained // ParamGeneratorInterface instance is shared among all copies // of the original object. This is possible because that instance is immutable. template class ParamGenerator { public: typedef ParamIterator iterator; explicit ParamGenerator(ParamGeneratorInterface* impl) : impl_(impl) {} ParamGenerator(const ParamGenerator& other) : impl_(other.impl_) {} ParamGenerator& operator=(const ParamGenerator& other) { impl_ = other.impl_; return *this; } iterator begin() const { return iterator(impl_->Begin()); } iterator end() const { return iterator(impl_->End()); } private: linked_ptr > impl_; }; // Generates values from a range of two comparable values. Can be used to // generate sequences of user-defined types that implement operator+() and // operator<(). // This class is used in the Range() function. template class RangeGenerator : public ParamGeneratorInterface { public: RangeGenerator(T begin, T end, IncrementT step) : begin_(begin), end_(end), step_(step), end_index_(CalculateEndIndex(begin, end, step)) {} virtual ~RangeGenerator() {} virtual ParamIteratorInterface* Begin() const { return new Iterator(this, begin_, 0, step_); } virtual ParamIteratorInterface* End() const { return new Iterator(this, end_, end_index_, step_); } private: class Iterator : public ParamIteratorInterface { public: Iterator(const ParamGeneratorInterface* base, T value, int index, IncrementT step) : base_(base), value_(value), index_(index), step_(step) {} virtual ~Iterator() {} virtual const ParamGeneratorInterface* BaseGenerator() const { return base_; } virtual void Advance() { value_ = value_ + step_; index_++; } virtual ParamIteratorInterface* Clone() const { return new Iterator(*this); } virtual const T* Current() const { return &value_; } virtual bool Equals(const ParamIteratorInterface& other) const { // Having the same base generator guarantees that the other // iterator is of the same type and we can downcast. GTEST_CHECK_(BaseGenerator() == other.BaseGenerator()) << "The program attempted to compare iterators " << "from different generators." << std::endl; const int other_index = CheckedDowncastToActualType(&other)->index_; return index_ == other_index; } private: Iterator(const Iterator& other) : ParamIteratorInterface(), base_(other.base_), value_(other.value_), index_(other.index_), step_(other.step_) {} // No implementation - assignment is unsupported. void operator=(const Iterator& other); const ParamGeneratorInterface* const base_; T value_; int index_; const IncrementT step_; }; // class RangeGenerator::Iterator static int CalculateEndIndex(const T& begin, const T& end, const IncrementT& step) { int end_index = 0; for (T i = begin; i < end; i = i + step) end_index++; return end_index; } // No implementation - assignment is unsupported. void operator=(const RangeGenerator& other); const T begin_; const T end_; const IncrementT step_; // The index for the end() iterator. All the elements in the generated // sequence are indexed (0-based) to aid iterator comparison. const int end_index_; }; // class RangeGenerator // Generates values from a pair of STL-style iterators. Used in the // ValuesIn() function. The elements are copied from the source range // since the source can be located on the stack, and the generator // is likely to persist beyond that stack frame. template class ValuesInIteratorRangeGenerator : public ParamGeneratorInterface { public: template ValuesInIteratorRangeGenerator(ForwardIterator begin, ForwardIterator end) : container_(begin, end) {} virtual ~ValuesInIteratorRangeGenerator() {} virtual ParamIteratorInterface* Begin() const { return new Iterator(this, container_.begin()); } virtual ParamIteratorInterface* End() const { return new Iterator(this, container_.end()); } private: typedef typename ::std::vector ContainerType; class Iterator : public ParamIteratorInterface { public: Iterator(const ParamGeneratorInterface* base, typename ContainerType::const_iterator iterator) : base_(base), iterator_(iterator) {} virtual ~Iterator() {} virtual const ParamGeneratorInterface* BaseGenerator() const { return base_; } virtual void Advance() { ++iterator_; value_.reset(); } virtual ParamIteratorInterface* Clone() const { return new Iterator(*this); } // We need to use cached value referenced by iterator_ because *iterator_ // can return a temporary object (and of type other then T), so just // having "return &*iterator_;" doesn't work. // value_ is updated here and not in Advance() because Advance() // can advance iterator_ beyond the end of the range, and we cannot // detect that fact. The client code, on the other hand, is // responsible for not calling Current() on an out-of-range iterator. virtual const T* Current() const { if (value_.get() == NULL) value_.reset(new T(*iterator_)); return value_.get(); } virtual bool Equals(const ParamIteratorInterface& other) const { // Having the same base generator guarantees that the other // iterator is of the same type and we can downcast. GTEST_CHECK_(BaseGenerator() == other.BaseGenerator()) << "The program attempted to compare iterators " << "from different generators." << std::endl; return iterator_ == CheckedDowncastToActualType(&other)->iterator_; } private: Iterator(const Iterator& other) // The explicit constructor call suppresses a false warning // emitted by gcc when supplied with the -Wextra option. : ParamIteratorInterface(), base_(other.base_), iterator_(other.iterator_) {} const ParamGeneratorInterface* const base_; typename ContainerType::const_iterator iterator_; // A cached value of *iterator_. We keep it here to allow access by // pointer in the wrapping iterator's operator->(). // value_ needs to be mutable to be accessed in Current(). // Use of scoped_ptr helps manage cached value's lifetime, // which is bound by the lifespan of the iterator itself. mutable scoped_ptr value_; }; // class ValuesInIteratorRangeGenerator::Iterator // No implementation - assignment is unsupported. void operator=(const ValuesInIteratorRangeGenerator& other); const ContainerType container_; }; // class ValuesInIteratorRangeGenerator // INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. // // Stores a parameter value and later creates tests parameterized with that // value. template class ParameterizedTestFactory : public TestFactoryBase { public: typedef typename TestClass::ParamType ParamType; explicit ParameterizedTestFactory(ParamType parameter) : parameter_(parameter) {} virtual Test* CreateTest() { TestClass::SetParam(¶meter_); return new TestClass(); } private: const ParamType parameter_; GTEST_DISALLOW_COPY_AND_ASSIGN_(ParameterizedTestFactory); }; // INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. // // TestMetaFactoryBase is a base class for meta-factories that create // test factories for passing into MakeAndRegisterTestInfo function. template class TestMetaFactoryBase { public: virtual ~TestMetaFactoryBase() {} virtual TestFactoryBase* CreateTestFactory(ParamType parameter) = 0; }; // INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. // // TestMetaFactory creates test factories for passing into // MakeAndRegisterTestInfo function. Since MakeAndRegisterTestInfo receives // ownership of test factory pointer, same factory object cannot be passed // into that method twice. But ParameterizedTestCaseInfo is going to call // it for each Test/Parameter value combination. Thus it needs meta factory // creator class. template class TestMetaFactory : public TestMetaFactoryBase { public: typedef typename TestCase::ParamType ParamType; TestMetaFactory() {} virtual TestFactoryBase* CreateTestFactory(ParamType parameter) { return new ParameterizedTestFactory(parameter); } private: GTEST_DISALLOW_COPY_AND_ASSIGN_(TestMetaFactory); }; // INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. // // ParameterizedTestCaseInfoBase is a generic interface // to ParameterizedTestCaseInfo classes. ParameterizedTestCaseInfoBase // accumulates test information provided by TEST_P macro invocations // and generators provided by INSTANTIATE_TEST_CASE_P macro invocations // and uses that information to register all resulting test instances // in RegisterTests method. The ParameterizeTestCaseRegistry class holds // a collection of pointers to the ParameterizedTestCaseInfo objects // and calls RegisterTests() on each of them when asked. class ParameterizedTestCaseInfoBase { public: virtual ~ParameterizedTestCaseInfoBase() {} // Base part of test case name for display purposes. virtual const string& GetTestCaseName() const = 0; // Test case id to verify identity. virtual TypeId GetTestCaseTypeId() const = 0; // UnitTest class invokes this method to register tests in this // test case right before running them in RUN_ALL_TESTS macro. // This method should not be called more then once on any single // instance of a ParameterizedTestCaseInfoBase derived class. virtual void RegisterTests() = 0; protected: ParameterizedTestCaseInfoBase() {} private: GTEST_DISALLOW_COPY_AND_ASSIGN_(ParameterizedTestCaseInfoBase); }; // INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. // // ParameterizedTestCaseInfo accumulates tests obtained from TEST_P // macro invocations for a particular test case and generators // obtained from INSTANTIATE_TEST_CASE_P macro invocations for that // test case. It registers tests with all values generated by all // generators when asked. template class ParameterizedTestCaseInfo : public ParameterizedTestCaseInfoBase { public: // ParamType and GeneratorCreationFunc are private types but are required // for declarations of public methods AddTestPattern() and // AddTestCaseInstantiation(). typedef typename TestCase::ParamType ParamType; // A function that returns an instance of appropriate generator type. typedef ParamGenerator(GeneratorCreationFunc)(); explicit ParameterizedTestCaseInfo(const char* name) : test_case_name_(name) {} // Test case base name for display purposes. virtual const string& GetTestCaseName() const { return test_case_name_; } // Test case id to verify identity. virtual TypeId GetTestCaseTypeId() const { return GetTypeId(); } // TEST_P macro uses AddTestPattern() to record information // about a single test in a LocalTestInfo structure. // test_case_name is the base name of the test case (without invocation // prefix). test_base_name is the name of an individual test without // parameter index. For the test SequenceA/FooTest.DoBar/1 FooTest is // test case base name and DoBar is test base name. void AddTestPattern(const char* test_case_name, const char* test_base_name, TestMetaFactoryBase* meta_factory) { tests_.push_back(linked_ptr(new TestInfo(test_case_name, test_base_name, meta_factory))); } // INSTANTIATE_TEST_CASE_P macro uses AddGenerator() to record information // about a generator. int AddTestCaseInstantiation(const string& instantiation_name, GeneratorCreationFunc* func, const char* /* file */, int /* line */) { instantiations_.push_back(::std::make_pair(instantiation_name, func)); return 0; // Return value used only to run this method in namespace scope. } // UnitTest class invokes this method to register tests in this test case // test cases right before running tests in RUN_ALL_TESTS macro. // This method should not be called more then once on any single // instance of a ParameterizedTestCaseInfoBase derived class. // UnitTest has a guard to prevent from calling this method more then once. virtual void RegisterTests() { for (typename TestInfoContainer::iterator test_it = tests_.begin(); test_it != tests_.end(); ++test_it) { linked_ptr test_info = *test_it; for (typename InstantiationContainer::iterator gen_it = instantiations_.begin(); gen_it != instantiations_.end(); ++gen_it) { const string& instantiation_name = gen_it->first; ParamGenerator generator((*gen_it->second)()); string test_case_name; if (!instantiation_name.empty()) test_case_name = instantiation_name + "/"; test_case_name += test_info->test_case_base_name; int i = 0; for (typename ParamGenerator::iterator param_it = generator.begin(); param_it != generator.end(); ++param_it, ++i) { Message test_name_stream; test_name_stream << test_info->test_base_name << "/" << i; MakeAndRegisterTestInfo( test_case_name.c_str(), test_name_stream.GetString().c_str(), NULL, // No type parameter. PrintToString(*param_it).c_str(), GetTestCaseTypeId(), TestCase::SetUpTestCase, TestCase::TearDownTestCase, test_info->test_meta_factory->CreateTestFactory(*param_it)); } // for param_it } // for gen_it } // for test_it } // RegisterTests private: // LocalTestInfo structure keeps information about a single test registered // with TEST_P macro. struct TestInfo { TestInfo(const char* a_test_case_base_name, const char* a_test_base_name, TestMetaFactoryBase* a_test_meta_factory) : test_case_base_name(a_test_case_base_name), test_base_name(a_test_base_name), test_meta_factory(a_test_meta_factory) {} const string test_case_base_name; const string test_base_name; const scoped_ptr > test_meta_factory; }; typedef ::std::vector > TestInfoContainer; // Keeps pairs of // received from INSTANTIATE_TEST_CASE_P macros. typedef ::std::vector > InstantiationContainer; const string test_case_name_; TestInfoContainer tests_; InstantiationContainer instantiations_; GTEST_DISALLOW_COPY_AND_ASSIGN_(ParameterizedTestCaseInfo); }; // class ParameterizedTestCaseInfo // INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. // // ParameterizedTestCaseRegistry contains a map of ParameterizedTestCaseInfoBase // classes accessed by test case names. TEST_P and INSTANTIATE_TEST_CASE_P // macros use it to locate their corresponding ParameterizedTestCaseInfo // descriptors. class ParameterizedTestCaseRegistry { public: ParameterizedTestCaseRegistry() {} ~ParameterizedTestCaseRegistry() { for (TestCaseInfoContainer::iterator it = test_case_infos_.begin(); it != test_case_infos_.end(); ++it) { delete *it; } } // Looks up or creates and returns a structure containing information about // tests and instantiations of a particular test case. template ParameterizedTestCaseInfo* GetTestCasePatternHolder( const char* test_case_name, const char* file, int line) { ParameterizedTestCaseInfo* typed_test_info = NULL; for (TestCaseInfoContainer::iterator it = test_case_infos_.begin(); it != test_case_infos_.end(); ++it) { if ((*it)->GetTestCaseName() == test_case_name) { if ((*it)->GetTestCaseTypeId() != GetTypeId()) { // Complain about incorrect usage of Google Test facilities // and terminate the program since we cannot guaranty correct // test case setup and tear-down in this case. ReportInvalidTestCaseType(test_case_name, file, line); posix::Abort(); } else { // At this point we are sure that the object we found is of the same // type we are looking for, so we downcast it to that type // without further checks. typed_test_info = CheckedDowncastToActualType< ParameterizedTestCaseInfo >(*it); } break; } } if (typed_test_info == NULL) { typed_test_info = new ParameterizedTestCaseInfo(test_case_name); test_case_infos_.push_back(typed_test_info); } return typed_test_info; } void RegisterTests() { for (TestCaseInfoContainer::iterator it = test_case_infos_.begin(); it != test_case_infos_.end(); ++it) { (*it)->RegisterTests(); } } private: typedef ::std::vector TestCaseInfoContainer; TestCaseInfoContainer test_case_infos_; GTEST_DISALLOW_COPY_AND_ASSIGN_(ParameterizedTestCaseRegistry); }; } // namespace internal } // namespace testing #endif // GTEST_HAS_PARAM_TEST #endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_H_ // This file was GENERATED by command: // pump.py gtest-param-util-generated.h.pump // DO NOT EDIT BY HAND!!! // Copyright 2008 Google Inc. // All Rights Reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // Author: vladl@google.com (Vlad Losev) // Type and function utilities for implementing parameterized tests. // This file is generated by a SCRIPT. DO NOT EDIT BY HAND! // // Currently Google Test supports at most 50 arguments in Values, // and at most 10 arguments in Combine. Please contact // googletestframework@googlegroups.com if you need more. // Please note that the number of arguments to Combine is limited // by the maximum arity of the implementation of tr1::tuple which is // currently set at 10. #ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_GENERATED_H_ #define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_GENERATED_H_ // scripts/fuse_gtest.py depends on gtest's own header being #included // *unconditionally*. Therefore these #includes cannot be moved // inside #if GTEST_HAS_PARAM_TEST. #if GTEST_HAS_PARAM_TEST namespace testing { // Forward declarations of ValuesIn(), which is implemented in // include/gtest/gtest-param-test.h. template internal::ParamGenerator< typename ::testing::internal::IteratorTraits::value_type> ValuesIn(ForwardIterator begin, ForwardIterator end); template internal::ParamGenerator ValuesIn(const T(&array)[N]); template internal::ParamGenerator ValuesIn( const Container& container); namespace internal { // Used in the Values() function to provide polymorphic capabilities. template class ValueArray1 { public: explicit ValueArray1(T1 v1) : v1_(v1) {} template operator ParamGenerator() const { return ValuesIn(&v1_, &v1_ + 1); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray1& other); const T1 v1_; }; template class ValueArray2 { public: ValueArray2(T1 v1, T2 v2) : v1_(v1), v2_(v2) {} template operator ParamGenerator() const { const T array[] = { static_cast(v1_), static_cast(v2_) }; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray2& other); const T1 v1_; const T2 v2_; }; template class ValueArray3 { public: ValueArray3(T1 v1, T2 v2, T3 v3) : v1_(v1), v2_(v2), v3_(v3) {} template operator ParamGenerator() const { const T array[] = { static_cast(v1_), static_cast(v2_), static_cast(v3_) }; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray3& other); const T1 v1_; const T2 v2_; const T3 v3_; }; template class ValueArray4 { public: ValueArray4(T1 v1, T2 v2, T3 v3, T4 v4) : v1_(v1), v2_(v2), v3_(v3), v4_(v4) {} template operator ParamGenerator() const { const T array[] = { static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_) }; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray4& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; }; template class ValueArray5 { public: ValueArray5(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5) {} template operator ParamGenerator() const { const T array[] = { static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_) }; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray5& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; }; template class ValueArray6 { public: ValueArray6(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6) {} template operator ParamGenerator() const { const T array[] = { static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_) }; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray6& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; }; template class ValueArray7 { public: ValueArray7(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7) {} template operator ParamGenerator() const { const T array[] = { static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_) }; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray7& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; }; template class ValueArray8 { public: ValueArray8(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8) {} template operator ParamGenerator() const { const T array[] = { static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_) }; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray8& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; }; template class ValueArray9 { public: ValueArray9(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9) {} template operator ParamGenerator() const { const T array[] = { static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_) }; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray9& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; }; template class ValueArray10 { public: ValueArray10(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10) {} template operator ParamGenerator() const { const T array[] = { static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_) }; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray10& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; }; template class ValueArray11 { public: ValueArray11(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11) {} template operator ParamGenerator() const { const T array[] = { static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_) }; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray11& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; }; template class ValueArray12 { public: ValueArray12(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12) {} template operator ParamGenerator() const { const T array[] = { static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_) }; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray12& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; }; template class ValueArray13 { public: ValueArray13(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13) {} template operator ParamGenerator() const { const T array[] = { static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_) }; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray13& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; }; template class ValueArray14 { public: ValueArray14(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14) {} template operator ParamGenerator() const { const T array[] = { static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_), static_cast(v14_) }; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray14& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; const T14 v14_; }; template class ValueArray15 { public: ValueArray15(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15) {} template operator ParamGenerator() const { const T array[] = { static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_), static_cast(v14_), static_cast(v15_) }; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray15& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; const T14 v14_; const T15 v15_; }; template class ValueArray16 { public: ValueArray16(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16) {} template operator ParamGenerator() const { const T array[] = { static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_), static_cast(v14_), static_cast(v15_), static_cast(v16_) }; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray16& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; const T14 v14_; const T15 v15_; const T16 v16_; }; template class ValueArray17 { public: ValueArray17(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17) {} template operator ParamGenerator() const { const T array[] = { static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_), static_cast(v14_), static_cast(v15_), static_cast(v16_), static_cast(v17_) }; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray17& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; const T14 v14_; const T15 v15_; const T16 v16_; const T17 v17_; }; template class ValueArray18 { public: ValueArray18(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18) {} template operator ParamGenerator() const { const T array[] = { static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_), static_cast(v14_), static_cast(v15_), static_cast(v16_), static_cast(v17_), static_cast(v18_) }; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray18& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; const T14 v14_; const T15 v15_; const T16 v16_; const T17 v17_; const T18 v18_; }; template class ValueArray19 { public: ValueArray19(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19) {} template operator ParamGenerator() const { const T array[] = { static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_), static_cast(v14_), static_cast(v15_), static_cast(v16_), static_cast(v17_), static_cast(v18_), static_cast(v19_) }; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray19& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; const T14 v14_; const T15 v15_; const T16 v16_; const T17 v17_; const T18 v18_; const T19 v19_; }; template class ValueArray20 { public: ValueArray20(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20) {} template operator ParamGenerator() const { const T array[] = { static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_), static_cast(v14_), static_cast(v15_), static_cast(v16_), static_cast(v17_), static_cast(v18_), static_cast(v19_), static_cast(v20_) }; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray20& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; const T14 v14_; const T15 v15_; const T16 v16_; const T17 v17_; const T18 v18_; const T19 v19_; const T20 v20_; }; template class ValueArray21 { public: ValueArray21(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21) {} template operator ParamGenerator() const { const T array[] = { static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_), static_cast(v14_), static_cast(v15_), static_cast(v16_), static_cast(v17_), static_cast(v18_), static_cast(v19_), static_cast(v20_), static_cast(v21_) }; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray21& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; const T14 v14_; const T15 v15_; const T16 v16_; const T17 v17_; const T18 v18_; const T19 v19_; const T20 v20_; const T21 v21_; }; template class ValueArray22 { public: ValueArray22(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22) {} template operator ParamGenerator() const { const T array[] = { static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_), static_cast(v14_), static_cast(v15_), static_cast(v16_), static_cast(v17_), static_cast(v18_), static_cast(v19_), static_cast(v20_), static_cast(v21_), static_cast(v22_) }; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray22& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; const T14 v14_; const T15 v15_; const T16 v16_; const T17 v17_; const T18 v18_; const T19 v19_; const T20 v20_; const T21 v21_; const T22 v22_; }; template class ValueArray23 { public: ValueArray23(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23) {} template operator ParamGenerator() const { const T array[] = { static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_), static_cast(v14_), static_cast(v15_), static_cast(v16_), static_cast(v17_), static_cast(v18_), static_cast(v19_), static_cast(v20_), static_cast(v21_), static_cast(v22_), static_cast(v23_) }; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray23& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; const T14 v14_; const T15 v15_; const T16 v16_; const T17 v17_; const T18 v18_; const T19 v19_; const T20 v20_; const T21 v21_; const T22 v22_; const T23 v23_; }; template class ValueArray24 { public: ValueArray24(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24) {} template operator ParamGenerator() const { const T array[] = { static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_), static_cast(v14_), static_cast(v15_), static_cast(v16_), static_cast(v17_), static_cast(v18_), static_cast(v19_), static_cast(v20_), static_cast(v21_), static_cast(v22_), static_cast(v23_), static_cast(v24_) }; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray24& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; const T14 v14_; const T15 v15_; const T16 v16_; const T17 v17_; const T18 v18_; const T19 v19_; const T20 v20_; const T21 v21_; const T22 v22_; const T23 v23_; const T24 v24_; }; template class ValueArray25 { public: ValueArray25(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25) {} template operator ParamGenerator() const { const T array[] = { static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_), static_cast(v14_), static_cast(v15_), static_cast(v16_), static_cast(v17_), static_cast(v18_), static_cast(v19_), static_cast(v20_), static_cast(v21_), static_cast(v22_), static_cast(v23_), static_cast(v24_), static_cast(v25_) }; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray25& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; const T14 v14_; const T15 v15_; const T16 v16_; const T17 v17_; const T18 v18_; const T19 v19_; const T20 v20_; const T21 v21_; const T22 v22_; const T23 v23_; const T24 v24_; const T25 v25_; }; template class ValueArray26 { public: ValueArray26(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26) {} template operator ParamGenerator() const { const T array[] = { static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_), static_cast(v14_), static_cast(v15_), static_cast(v16_), static_cast(v17_), static_cast(v18_), static_cast(v19_), static_cast(v20_), static_cast(v21_), static_cast(v22_), static_cast(v23_), static_cast(v24_), static_cast(v25_), static_cast(v26_) }; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray26& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; const T14 v14_; const T15 v15_; const T16 v16_; const T17 v17_; const T18 v18_; const T19 v19_; const T20 v20_; const T21 v21_; const T22 v22_; const T23 v23_; const T24 v24_; const T25 v25_; const T26 v26_; }; template class ValueArray27 { public: ValueArray27(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27) {} template operator ParamGenerator() const { const T array[] = { static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_), static_cast(v14_), static_cast(v15_), static_cast(v16_), static_cast(v17_), static_cast(v18_), static_cast(v19_), static_cast(v20_), static_cast(v21_), static_cast(v22_), static_cast(v23_), static_cast(v24_), static_cast(v25_), static_cast(v26_), static_cast(v27_) }; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray27& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; const T14 v14_; const T15 v15_; const T16 v16_; const T17 v17_; const T18 v18_; const T19 v19_; const T20 v20_; const T21 v21_; const T22 v22_; const T23 v23_; const T24 v24_; const T25 v25_; const T26 v26_; const T27 v27_; }; template class ValueArray28 { public: ValueArray28(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28) {} template operator ParamGenerator() const { const T array[] = { static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_), static_cast(v14_), static_cast(v15_), static_cast(v16_), static_cast(v17_), static_cast(v18_), static_cast(v19_), static_cast(v20_), static_cast(v21_), static_cast(v22_), static_cast(v23_), static_cast(v24_), static_cast(v25_), static_cast(v26_), static_cast(v27_), static_cast(v28_) }; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray28& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; const T14 v14_; const T15 v15_; const T16 v16_; const T17 v17_; const T18 v18_; const T19 v19_; const T20 v20_; const T21 v21_; const T22 v22_; const T23 v23_; const T24 v24_; const T25 v25_; const T26 v26_; const T27 v27_; const T28 v28_; }; template class ValueArray29 { public: ValueArray29(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29) {} template operator ParamGenerator() const { const T array[] = { static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_), static_cast(v14_), static_cast(v15_), static_cast(v16_), static_cast(v17_), static_cast(v18_), static_cast(v19_), static_cast(v20_), static_cast(v21_), static_cast(v22_), static_cast(v23_), static_cast(v24_), static_cast(v25_), static_cast(v26_), static_cast(v27_), static_cast(v28_), static_cast(v29_) }; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray29& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; const T14 v14_; const T15 v15_; const T16 v16_; const T17 v17_; const T18 v18_; const T19 v19_; const T20 v20_; const T21 v21_; const T22 v22_; const T23 v23_; const T24 v24_; const T25 v25_; const T26 v26_; const T27 v27_; const T28 v28_; const T29 v29_; }; template class ValueArray30 { public: ValueArray30(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29), v30_(v30) {} template operator ParamGenerator() const { const T array[] = { static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_), static_cast(v14_), static_cast(v15_), static_cast(v16_), static_cast(v17_), static_cast(v18_), static_cast(v19_), static_cast(v20_), static_cast(v21_), static_cast(v22_), static_cast(v23_), static_cast(v24_), static_cast(v25_), static_cast(v26_), static_cast(v27_), static_cast(v28_), static_cast(v29_), static_cast(v30_) }; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray30& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; const T14 v14_; const T15 v15_; const T16 v16_; const T17 v17_; const T18 v18_; const T19 v19_; const T20 v20_; const T21 v21_; const T22 v22_; const T23 v23_; const T24 v24_; const T25 v25_; const T26 v26_; const T27 v27_; const T28 v28_; const T29 v29_; const T30 v30_; }; template class ValueArray31 { public: ValueArray31(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31) {} template operator ParamGenerator() const { const T array[] = { static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_), static_cast(v14_), static_cast(v15_), static_cast(v16_), static_cast(v17_), static_cast(v18_), static_cast(v19_), static_cast(v20_), static_cast(v21_), static_cast(v22_), static_cast(v23_), static_cast(v24_), static_cast(v25_), static_cast(v26_), static_cast(v27_), static_cast(v28_), static_cast(v29_), static_cast(v30_), static_cast(v31_) }; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray31& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; const T14 v14_; const T15 v15_; const T16 v16_; const T17 v17_; const T18 v18_; const T19 v19_; const T20 v20_; const T21 v21_; const T22 v22_; const T23 v23_; const T24 v24_; const T25 v25_; const T26 v26_; const T27 v27_; const T28 v28_; const T29 v29_; const T30 v30_; const T31 v31_; }; template class ValueArray32 { public: ValueArray32(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32) {} template operator ParamGenerator() const { const T array[] = { static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_), static_cast(v14_), static_cast(v15_), static_cast(v16_), static_cast(v17_), static_cast(v18_), static_cast(v19_), static_cast(v20_), static_cast(v21_), static_cast(v22_), static_cast(v23_), static_cast(v24_), static_cast(v25_), static_cast(v26_), static_cast(v27_), static_cast(v28_), static_cast(v29_), static_cast(v30_), static_cast(v31_), static_cast(v32_) }; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray32& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; const T14 v14_; const T15 v15_; const T16 v16_; const T17 v17_; const T18 v18_; const T19 v19_; const T20 v20_; const T21 v21_; const T22 v22_; const T23 v23_; const T24 v24_; const T25 v25_; const T26 v26_; const T27 v27_; const T28 v28_; const T29 v29_; const T30 v30_; const T31 v31_; const T32 v32_; }; template class ValueArray33 { public: ValueArray33(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33) {} template operator ParamGenerator() const { const T array[] = { static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_), static_cast(v14_), static_cast(v15_), static_cast(v16_), static_cast(v17_), static_cast(v18_), static_cast(v19_), static_cast(v20_), static_cast(v21_), static_cast(v22_), static_cast(v23_), static_cast(v24_), static_cast(v25_), static_cast(v26_), static_cast(v27_), static_cast(v28_), static_cast(v29_), static_cast(v30_), static_cast(v31_), static_cast(v32_), static_cast(v33_) }; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray33& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; const T14 v14_; const T15 v15_; const T16 v16_; const T17 v17_; const T18 v18_; const T19 v19_; const T20 v20_; const T21 v21_; const T22 v22_; const T23 v23_; const T24 v24_; const T25 v25_; const T26 v26_; const T27 v27_; const T28 v28_; const T29 v29_; const T30 v30_; const T31 v31_; const T32 v32_; const T33 v33_; }; template class ValueArray34 { public: ValueArray34(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34) {} template operator ParamGenerator() const { const T array[] = { static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_), static_cast(v14_), static_cast(v15_), static_cast(v16_), static_cast(v17_), static_cast(v18_), static_cast(v19_), static_cast(v20_), static_cast(v21_), static_cast(v22_), static_cast(v23_), static_cast(v24_), static_cast(v25_), static_cast(v26_), static_cast(v27_), static_cast(v28_), static_cast(v29_), static_cast(v30_), static_cast(v31_), static_cast(v32_), static_cast(v33_), static_cast(v34_) }; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray34& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; const T14 v14_; const T15 v15_; const T16 v16_; const T17 v17_; const T18 v18_; const T19 v19_; const T20 v20_; const T21 v21_; const T22 v22_; const T23 v23_; const T24 v24_; const T25 v25_; const T26 v26_; const T27 v27_; const T28 v28_; const T29 v29_; const T30 v30_; const T31 v31_; const T32 v32_; const T33 v33_; const T34 v34_; }; template class ValueArray35 { public: ValueArray35(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34), v35_(v35) {} template operator ParamGenerator() const { const T array[] = { static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_), static_cast(v14_), static_cast(v15_), static_cast(v16_), static_cast(v17_), static_cast(v18_), static_cast(v19_), static_cast(v20_), static_cast(v21_), static_cast(v22_), static_cast(v23_), static_cast(v24_), static_cast(v25_), static_cast(v26_), static_cast(v27_), static_cast(v28_), static_cast(v29_), static_cast(v30_), static_cast(v31_), static_cast(v32_), static_cast(v33_), static_cast(v34_), static_cast(v35_) }; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray35& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; const T14 v14_; const T15 v15_; const T16 v16_; const T17 v17_; const T18 v18_; const T19 v19_; const T20 v20_; const T21 v21_; const T22 v22_; const T23 v23_; const T24 v24_; const T25 v25_; const T26 v26_; const T27 v27_; const T28 v28_; const T29 v29_; const T30 v30_; const T31 v31_; const T32 v32_; const T33 v33_; const T34 v34_; const T35 v35_; }; template class ValueArray36 { public: ValueArray36(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34), v35_(v35), v36_(v36) {} template operator ParamGenerator() const { const T array[] = { static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_), static_cast(v14_), static_cast(v15_), static_cast(v16_), static_cast(v17_), static_cast(v18_), static_cast(v19_), static_cast(v20_), static_cast(v21_), static_cast(v22_), static_cast(v23_), static_cast(v24_), static_cast(v25_), static_cast(v26_), static_cast(v27_), static_cast(v28_), static_cast(v29_), static_cast(v30_), static_cast(v31_), static_cast(v32_), static_cast(v33_), static_cast(v34_), static_cast(v35_), static_cast(v36_) }; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray36& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; const T14 v14_; const T15 v15_; const T16 v16_; const T17 v17_; const T18 v18_; const T19 v19_; const T20 v20_; const T21 v21_; const T22 v22_; const T23 v23_; const T24 v24_; const T25 v25_; const T26 v26_; const T27 v27_; const T28 v28_; const T29 v29_; const T30 v30_; const T31 v31_; const T32 v32_; const T33 v33_; const T34 v34_; const T35 v35_; const T36 v36_; }; template class ValueArray37 { public: ValueArray37(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34), v35_(v35), v36_(v36), v37_(v37) {} template operator ParamGenerator() const { const T array[] = { static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_), static_cast(v14_), static_cast(v15_), static_cast(v16_), static_cast(v17_), static_cast(v18_), static_cast(v19_), static_cast(v20_), static_cast(v21_), static_cast(v22_), static_cast(v23_), static_cast(v24_), static_cast(v25_), static_cast(v26_), static_cast(v27_), static_cast(v28_), static_cast(v29_), static_cast(v30_), static_cast(v31_), static_cast(v32_), static_cast(v33_), static_cast(v34_), static_cast(v35_), static_cast(v36_), static_cast(v37_) }; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray37& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; const T14 v14_; const T15 v15_; const T16 v16_; const T17 v17_; const T18 v18_; const T19 v19_; const T20 v20_; const T21 v21_; const T22 v22_; const T23 v23_; const T24 v24_; const T25 v25_; const T26 v26_; const T27 v27_; const T28 v28_; const T29 v29_; const T30 v30_; const T31 v31_; const T32 v32_; const T33 v33_; const T34 v34_; const T35 v35_; const T36 v36_; const T37 v37_; }; template class ValueArray38 { public: ValueArray38(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34), v35_(v35), v36_(v36), v37_(v37), v38_(v38) {} template operator ParamGenerator() const { const T array[] = { static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_), static_cast(v14_), static_cast(v15_), static_cast(v16_), static_cast(v17_), static_cast(v18_), static_cast(v19_), static_cast(v20_), static_cast(v21_), static_cast(v22_), static_cast(v23_), static_cast(v24_), static_cast(v25_), static_cast(v26_), static_cast(v27_), static_cast(v28_), static_cast(v29_), static_cast(v30_), static_cast(v31_), static_cast(v32_), static_cast(v33_), static_cast(v34_), static_cast(v35_), static_cast(v36_), static_cast(v37_), static_cast(v38_) }; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray38& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; const T14 v14_; const T15 v15_; const T16 v16_; const T17 v17_; const T18 v18_; const T19 v19_; const T20 v20_; const T21 v21_; const T22 v22_; const T23 v23_; const T24 v24_; const T25 v25_; const T26 v26_; const T27 v27_; const T28 v28_; const T29 v29_; const T30 v30_; const T31 v31_; const T32 v32_; const T33 v33_; const T34 v34_; const T35 v35_; const T36 v36_; const T37 v37_; const T38 v38_; }; template class ValueArray39 { public: ValueArray39(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34), v35_(v35), v36_(v36), v37_(v37), v38_(v38), v39_(v39) {} template operator ParamGenerator() const { const T array[] = { static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_), static_cast(v14_), static_cast(v15_), static_cast(v16_), static_cast(v17_), static_cast(v18_), static_cast(v19_), static_cast(v20_), static_cast(v21_), static_cast(v22_), static_cast(v23_), static_cast(v24_), static_cast(v25_), static_cast(v26_), static_cast(v27_), static_cast(v28_), static_cast(v29_), static_cast(v30_), static_cast(v31_), static_cast(v32_), static_cast(v33_), static_cast(v34_), static_cast(v35_), static_cast(v36_), static_cast(v37_), static_cast(v38_), static_cast(v39_) }; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray39& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; const T14 v14_; const T15 v15_; const T16 v16_; const T17 v17_; const T18 v18_; const T19 v19_; const T20 v20_; const T21 v21_; const T22 v22_; const T23 v23_; const T24 v24_; const T25 v25_; const T26 v26_; const T27 v27_; const T28 v28_; const T29 v29_; const T30 v30_; const T31 v31_; const T32 v32_; const T33 v33_; const T34 v34_; const T35 v35_; const T36 v36_; const T37 v37_; const T38 v38_; const T39 v39_; }; template class ValueArray40 { public: ValueArray40(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34), v35_(v35), v36_(v36), v37_(v37), v38_(v38), v39_(v39), v40_(v40) {} template operator ParamGenerator() const { const T array[] = { static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_), static_cast(v14_), static_cast(v15_), static_cast(v16_), static_cast(v17_), static_cast(v18_), static_cast(v19_), static_cast(v20_), static_cast(v21_), static_cast(v22_), static_cast(v23_), static_cast(v24_), static_cast(v25_), static_cast(v26_), static_cast(v27_), static_cast(v28_), static_cast(v29_), static_cast(v30_), static_cast(v31_), static_cast(v32_), static_cast(v33_), static_cast(v34_), static_cast(v35_), static_cast(v36_), static_cast(v37_), static_cast(v38_), static_cast(v39_), static_cast(v40_) }; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray40& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; const T14 v14_; const T15 v15_; const T16 v16_; const T17 v17_; const T18 v18_; const T19 v19_; const T20 v20_; const T21 v21_; const T22 v22_; const T23 v23_; const T24 v24_; const T25 v25_; const T26 v26_; const T27 v27_; const T28 v28_; const T29 v29_; const T30 v30_; const T31 v31_; const T32 v32_; const T33 v33_; const T34 v34_; const T35 v35_; const T36 v36_; const T37 v37_; const T38 v38_; const T39 v39_; const T40 v40_; }; template class ValueArray41 { public: ValueArray41(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34), v35_(v35), v36_(v36), v37_(v37), v38_(v38), v39_(v39), v40_(v40), v41_(v41) {} template operator ParamGenerator() const { const T array[] = { static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_), static_cast(v14_), static_cast(v15_), static_cast(v16_), static_cast(v17_), static_cast(v18_), static_cast(v19_), static_cast(v20_), static_cast(v21_), static_cast(v22_), static_cast(v23_), static_cast(v24_), static_cast(v25_), static_cast(v26_), static_cast(v27_), static_cast(v28_), static_cast(v29_), static_cast(v30_), static_cast(v31_), static_cast(v32_), static_cast(v33_), static_cast(v34_), static_cast(v35_), static_cast(v36_), static_cast(v37_), static_cast(v38_), static_cast(v39_), static_cast(v40_), static_cast(v41_) }; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray41& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; const T14 v14_; const T15 v15_; const T16 v16_; const T17 v17_; const T18 v18_; const T19 v19_; const T20 v20_; const T21 v21_; const T22 v22_; const T23 v23_; const T24 v24_; const T25 v25_; const T26 v26_; const T27 v27_; const T28 v28_; const T29 v29_; const T30 v30_; const T31 v31_; const T32 v32_; const T33 v33_; const T34 v34_; const T35 v35_; const T36 v36_; const T37 v37_; const T38 v38_; const T39 v39_; const T40 v40_; const T41 v41_; }; template class ValueArray42 { public: ValueArray42(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, T42 v42) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34), v35_(v35), v36_(v36), v37_(v37), v38_(v38), v39_(v39), v40_(v40), v41_(v41), v42_(v42) {} template operator ParamGenerator() const { const T array[] = { static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_), static_cast(v14_), static_cast(v15_), static_cast(v16_), static_cast(v17_), static_cast(v18_), static_cast(v19_), static_cast(v20_), static_cast(v21_), static_cast(v22_), static_cast(v23_), static_cast(v24_), static_cast(v25_), static_cast(v26_), static_cast(v27_), static_cast(v28_), static_cast(v29_), static_cast(v30_), static_cast(v31_), static_cast(v32_), static_cast(v33_), static_cast(v34_), static_cast(v35_), static_cast(v36_), static_cast(v37_), static_cast(v38_), static_cast(v39_), static_cast(v40_), static_cast(v41_), static_cast(v42_) }; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray42& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; const T14 v14_; const T15 v15_; const T16 v16_; const T17 v17_; const T18 v18_; const T19 v19_; const T20 v20_; const T21 v21_; const T22 v22_; const T23 v23_; const T24 v24_; const T25 v25_; const T26 v26_; const T27 v27_; const T28 v28_; const T29 v29_; const T30 v30_; const T31 v31_; const T32 v32_; const T33 v33_; const T34 v34_; const T35 v35_; const T36 v36_; const T37 v37_; const T38 v38_; const T39 v39_; const T40 v40_; const T41 v41_; const T42 v42_; }; template class ValueArray43 { public: ValueArray43(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, T42 v42, T43 v43) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34), v35_(v35), v36_(v36), v37_(v37), v38_(v38), v39_(v39), v40_(v40), v41_(v41), v42_(v42), v43_(v43) {} template operator ParamGenerator() const { const T array[] = { static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_), static_cast(v14_), static_cast(v15_), static_cast(v16_), static_cast(v17_), static_cast(v18_), static_cast(v19_), static_cast(v20_), static_cast(v21_), static_cast(v22_), static_cast(v23_), static_cast(v24_), static_cast(v25_), static_cast(v26_), static_cast(v27_), static_cast(v28_), static_cast(v29_), static_cast(v30_), static_cast(v31_), static_cast(v32_), static_cast(v33_), static_cast(v34_), static_cast(v35_), static_cast(v36_), static_cast(v37_), static_cast(v38_), static_cast(v39_), static_cast(v40_), static_cast(v41_), static_cast(v42_), static_cast(v43_) }; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray43& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; const T14 v14_; const T15 v15_; const T16 v16_; const T17 v17_; const T18 v18_; const T19 v19_; const T20 v20_; const T21 v21_; const T22 v22_; const T23 v23_; const T24 v24_; const T25 v25_; const T26 v26_; const T27 v27_; const T28 v28_; const T29 v29_; const T30 v30_; const T31 v31_; const T32 v32_; const T33 v33_; const T34 v34_; const T35 v35_; const T36 v36_; const T37 v37_; const T38 v38_; const T39 v39_; const T40 v40_; const T41 v41_; const T42 v42_; const T43 v43_; }; template class ValueArray44 { public: ValueArray44(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, T42 v42, T43 v43, T44 v44) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34), v35_(v35), v36_(v36), v37_(v37), v38_(v38), v39_(v39), v40_(v40), v41_(v41), v42_(v42), v43_(v43), v44_(v44) {} template operator ParamGenerator() const { const T array[] = { static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_), static_cast(v14_), static_cast(v15_), static_cast(v16_), static_cast(v17_), static_cast(v18_), static_cast(v19_), static_cast(v20_), static_cast(v21_), static_cast(v22_), static_cast(v23_), static_cast(v24_), static_cast(v25_), static_cast(v26_), static_cast(v27_), static_cast(v28_), static_cast(v29_), static_cast(v30_), static_cast(v31_), static_cast(v32_), static_cast(v33_), static_cast(v34_), static_cast(v35_), static_cast(v36_), static_cast(v37_), static_cast(v38_), static_cast(v39_), static_cast(v40_), static_cast(v41_), static_cast(v42_), static_cast(v43_), static_cast(v44_) }; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray44& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; const T14 v14_; const T15 v15_; const T16 v16_; const T17 v17_; const T18 v18_; const T19 v19_; const T20 v20_; const T21 v21_; const T22 v22_; const T23 v23_; const T24 v24_; const T25 v25_; const T26 v26_; const T27 v27_; const T28 v28_; const T29 v29_; const T30 v30_; const T31 v31_; const T32 v32_; const T33 v33_; const T34 v34_; const T35 v35_; const T36 v36_; const T37 v37_; const T38 v38_; const T39 v39_; const T40 v40_; const T41 v41_; const T42 v42_; const T43 v43_; const T44 v44_; }; template class ValueArray45 { public: ValueArray45(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, T42 v42, T43 v43, T44 v44, T45 v45) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34), v35_(v35), v36_(v36), v37_(v37), v38_(v38), v39_(v39), v40_(v40), v41_(v41), v42_(v42), v43_(v43), v44_(v44), v45_(v45) {} template operator ParamGenerator() const { const T array[] = { static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_), static_cast(v14_), static_cast(v15_), static_cast(v16_), static_cast(v17_), static_cast(v18_), static_cast(v19_), static_cast(v20_), static_cast(v21_), static_cast(v22_), static_cast(v23_), static_cast(v24_), static_cast(v25_), static_cast(v26_), static_cast(v27_), static_cast(v28_), static_cast(v29_), static_cast(v30_), static_cast(v31_), static_cast(v32_), static_cast(v33_), static_cast(v34_), static_cast(v35_), static_cast(v36_), static_cast(v37_), static_cast(v38_), static_cast(v39_), static_cast(v40_), static_cast(v41_), static_cast(v42_), static_cast(v43_), static_cast(v44_), static_cast(v45_) }; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray45& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; const T14 v14_; const T15 v15_; const T16 v16_; const T17 v17_; const T18 v18_; const T19 v19_; const T20 v20_; const T21 v21_; const T22 v22_; const T23 v23_; const T24 v24_; const T25 v25_; const T26 v26_; const T27 v27_; const T28 v28_; const T29 v29_; const T30 v30_; const T31 v31_; const T32 v32_; const T33 v33_; const T34 v34_; const T35 v35_; const T36 v36_; const T37 v37_; const T38 v38_; const T39 v39_; const T40 v40_; const T41 v41_; const T42 v42_; const T43 v43_; const T44 v44_; const T45 v45_; }; template class ValueArray46 { public: ValueArray46(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, T42 v42, T43 v43, T44 v44, T45 v45, T46 v46) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34), v35_(v35), v36_(v36), v37_(v37), v38_(v38), v39_(v39), v40_(v40), v41_(v41), v42_(v42), v43_(v43), v44_(v44), v45_(v45), v46_(v46) {} template operator ParamGenerator() const { const T array[] = { static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_), static_cast(v14_), static_cast(v15_), static_cast(v16_), static_cast(v17_), static_cast(v18_), static_cast(v19_), static_cast(v20_), static_cast(v21_), static_cast(v22_), static_cast(v23_), static_cast(v24_), static_cast(v25_), static_cast(v26_), static_cast(v27_), static_cast(v28_), static_cast(v29_), static_cast(v30_), static_cast(v31_), static_cast(v32_), static_cast(v33_), static_cast(v34_), static_cast(v35_), static_cast(v36_), static_cast(v37_), static_cast(v38_), static_cast(v39_), static_cast(v40_), static_cast(v41_), static_cast(v42_), static_cast(v43_), static_cast(v44_), static_cast(v45_), static_cast(v46_) }; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray46& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; const T14 v14_; const T15 v15_; const T16 v16_; const T17 v17_; const T18 v18_; const T19 v19_; const T20 v20_; const T21 v21_; const T22 v22_; const T23 v23_; const T24 v24_; const T25 v25_; const T26 v26_; const T27 v27_; const T28 v28_; const T29 v29_; const T30 v30_; const T31 v31_; const T32 v32_; const T33 v33_; const T34 v34_; const T35 v35_; const T36 v36_; const T37 v37_; const T38 v38_; const T39 v39_; const T40 v40_; const T41 v41_; const T42 v42_; const T43 v43_; const T44 v44_; const T45 v45_; const T46 v46_; }; template class ValueArray47 { public: ValueArray47(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, T42 v42, T43 v43, T44 v44, T45 v45, T46 v46, T47 v47) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34), v35_(v35), v36_(v36), v37_(v37), v38_(v38), v39_(v39), v40_(v40), v41_(v41), v42_(v42), v43_(v43), v44_(v44), v45_(v45), v46_(v46), v47_(v47) {} template operator ParamGenerator() const { const T array[] = { static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_), static_cast(v14_), static_cast(v15_), static_cast(v16_), static_cast(v17_), static_cast(v18_), static_cast(v19_), static_cast(v20_), static_cast(v21_), static_cast(v22_), static_cast(v23_), static_cast(v24_), static_cast(v25_), static_cast(v26_), static_cast(v27_), static_cast(v28_), static_cast(v29_), static_cast(v30_), static_cast(v31_), static_cast(v32_), static_cast(v33_), static_cast(v34_), static_cast(v35_), static_cast(v36_), static_cast(v37_), static_cast(v38_), static_cast(v39_), static_cast(v40_), static_cast(v41_), static_cast(v42_), static_cast(v43_), static_cast(v44_), static_cast(v45_), static_cast(v46_), static_cast(v47_) }; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray47& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; const T14 v14_; const T15 v15_; const T16 v16_; const T17 v17_; const T18 v18_; const T19 v19_; const T20 v20_; const T21 v21_; const T22 v22_; const T23 v23_; const T24 v24_; const T25 v25_; const T26 v26_; const T27 v27_; const T28 v28_; const T29 v29_; const T30 v30_; const T31 v31_; const T32 v32_; const T33 v33_; const T34 v34_; const T35 v35_; const T36 v36_; const T37 v37_; const T38 v38_; const T39 v39_; const T40 v40_; const T41 v41_; const T42 v42_; const T43 v43_; const T44 v44_; const T45 v45_; const T46 v46_; const T47 v47_; }; template class ValueArray48 { public: ValueArray48(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, T42 v42, T43 v43, T44 v44, T45 v45, T46 v46, T47 v47, T48 v48) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34), v35_(v35), v36_(v36), v37_(v37), v38_(v38), v39_(v39), v40_(v40), v41_(v41), v42_(v42), v43_(v43), v44_(v44), v45_(v45), v46_(v46), v47_(v47), v48_(v48) {} template operator ParamGenerator() const { const T array[] = { static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_), static_cast(v14_), static_cast(v15_), static_cast(v16_), static_cast(v17_), static_cast(v18_), static_cast(v19_), static_cast(v20_), static_cast(v21_), static_cast(v22_), static_cast(v23_), static_cast(v24_), static_cast(v25_), static_cast(v26_), static_cast(v27_), static_cast(v28_), static_cast(v29_), static_cast(v30_), static_cast(v31_), static_cast(v32_), static_cast(v33_), static_cast(v34_), static_cast(v35_), static_cast(v36_), static_cast(v37_), static_cast(v38_), static_cast(v39_), static_cast(v40_), static_cast(v41_), static_cast(v42_), static_cast(v43_), static_cast(v44_), static_cast(v45_), static_cast(v46_), static_cast(v47_), static_cast(v48_) }; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray48& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; const T14 v14_; const T15 v15_; const T16 v16_; const T17 v17_; const T18 v18_; const T19 v19_; const T20 v20_; const T21 v21_; const T22 v22_; const T23 v23_; const T24 v24_; const T25 v25_; const T26 v26_; const T27 v27_; const T28 v28_; const T29 v29_; const T30 v30_; const T31 v31_; const T32 v32_; const T33 v33_; const T34 v34_; const T35 v35_; const T36 v36_; const T37 v37_; const T38 v38_; const T39 v39_; const T40 v40_; const T41 v41_; const T42 v42_; const T43 v43_; const T44 v44_; const T45 v45_; const T46 v46_; const T47 v47_; const T48 v48_; }; template class ValueArray49 { public: ValueArray49(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, T42 v42, T43 v43, T44 v44, T45 v45, T46 v46, T47 v47, T48 v48, T49 v49) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34), v35_(v35), v36_(v36), v37_(v37), v38_(v38), v39_(v39), v40_(v40), v41_(v41), v42_(v42), v43_(v43), v44_(v44), v45_(v45), v46_(v46), v47_(v47), v48_(v48), v49_(v49) {} template operator ParamGenerator() const { const T array[] = { static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_), static_cast(v14_), static_cast(v15_), static_cast(v16_), static_cast(v17_), static_cast(v18_), static_cast(v19_), static_cast(v20_), static_cast(v21_), static_cast(v22_), static_cast(v23_), static_cast(v24_), static_cast(v25_), static_cast(v26_), static_cast(v27_), static_cast(v28_), static_cast(v29_), static_cast(v30_), static_cast(v31_), static_cast(v32_), static_cast(v33_), static_cast(v34_), static_cast(v35_), static_cast(v36_), static_cast(v37_), static_cast(v38_), static_cast(v39_), static_cast(v40_), static_cast(v41_), static_cast(v42_), static_cast(v43_), static_cast(v44_), static_cast(v45_), static_cast(v46_), static_cast(v47_), static_cast(v48_), static_cast(v49_) }; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray49& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; const T14 v14_; const T15 v15_; const T16 v16_; const T17 v17_; const T18 v18_; const T19 v19_; const T20 v20_; const T21 v21_; const T22 v22_; const T23 v23_; const T24 v24_; const T25 v25_; const T26 v26_; const T27 v27_; const T28 v28_; const T29 v29_; const T30 v30_; const T31 v31_; const T32 v32_; const T33 v33_; const T34 v34_; const T35 v35_; const T36 v36_; const T37 v37_; const T38 v38_; const T39 v39_; const T40 v40_; const T41 v41_; const T42 v42_; const T43 v43_; const T44 v44_; const T45 v45_; const T46 v46_; const T47 v47_; const T48 v48_; const T49 v49_; }; template class ValueArray50 { public: ValueArray50(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, T42 v42, T43 v43, T44 v44, T45 v45, T46 v46, T47 v47, T48 v48, T49 v49, T50 v50) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34), v35_(v35), v36_(v36), v37_(v37), v38_(v38), v39_(v39), v40_(v40), v41_(v41), v42_(v42), v43_(v43), v44_(v44), v45_(v45), v46_(v46), v47_(v47), v48_(v48), v49_(v49), v50_(v50) {} template operator ParamGenerator() const { const T array[] = { static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_), static_cast(v14_), static_cast(v15_), static_cast(v16_), static_cast(v17_), static_cast(v18_), static_cast(v19_), static_cast(v20_), static_cast(v21_), static_cast(v22_), static_cast(v23_), static_cast(v24_), static_cast(v25_), static_cast(v26_), static_cast(v27_), static_cast(v28_), static_cast(v29_), static_cast(v30_), static_cast(v31_), static_cast(v32_), static_cast(v33_), static_cast(v34_), static_cast(v35_), static_cast(v36_), static_cast(v37_), static_cast(v38_), static_cast(v39_), static_cast(v40_), static_cast(v41_), static_cast(v42_), static_cast(v43_), static_cast(v44_), static_cast(v45_), static_cast(v46_), static_cast(v47_), static_cast(v48_), static_cast(v49_), static_cast(v50_) }; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray50& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; const T14 v14_; const T15 v15_; const T16 v16_; const T17 v17_; const T18 v18_; const T19 v19_; const T20 v20_; const T21 v21_; const T22 v22_; const T23 v23_; const T24 v24_; const T25 v25_; const T26 v26_; const T27 v27_; const T28 v28_; const T29 v29_; const T30 v30_; const T31 v31_; const T32 v32_; const T33 v33_; const T34 v34_; const T35 v35_; const T36 v36_; const T37 v37_; const T38 v38_; const T39 v39_; const T40 v40_; const T41 v41_; const T42 v42_; const T43 v43_; const T44 v44_; const T45 v45_; const T46 v46_; const T47 v47_; const T48 v48_; const T49 v49_; const T50 v50_; }; # if GTEST_HAS_COMBINE // INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. // // Generates values from the Cartesian product of values produced // by the argument generators. // template class CartesianProductGenerator2 : public ParamGeneratorInterface< ::stdt::tuple > { public: typedef ::stdt::tuple ParamType; CartesianProductGenerator2(const ParamGenerator& g1, const ParamGenerator& g2) : g1_(g1), g2_(g2) {} virtual ~CartesianProductGenerator2() {} virtual ParamIteratorInterface* Begin() const { return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin()); } virtual ParamIteratorInterface* End() const { return new Iterator(this, g1_, g1_.end(), g2_, g2_.end()); } private: class Iterator : public ParamIteratorInterface { public: Iterator(const ParamGeneratorInterface* base, const ParamGenerator& g1, const typename ParamGenerator::iterator& current1, const ParamGenerator& g2, const typename ParamGenerator::iterator& current2) : base_(base), begin1_(g1.begin()), end1_(g1.end()), current1_(current1), begin2_(g2.begin()), end2_(g2.end()), current2_(current2) { ComputeCurrentValue(); } virtual ~Iterator() {} virtual const ParamGeneratorInterface* BaseGenerator() const { return base_; } // Advance should not be called on beyond-of-range iterators // so no component iterators must be beyond end of range, either. virtual void Advance() { assert(!AtEnd()); ++current2_; if (current2_ == end2_) { current2_ = begin2_; ++current1_; } ComputeCurrentValue(); } virtual ParamIteratorInterface* Clone() const { return new Iterator(*this); } virtual const ParamType* Current() const { return ¤t_value_; } virtual bool Equals(const ParamIteratorInterface& other) const { // Having the same base generator guarantees that the other // iterator is of the same type and we can downcast. GTEST_CHECK_(BaseGenerator() == other.BaseGenerator()) << "The program attempted to compare iterators " << "from different generators." << std::endl; const Iterator* typed_other = CheckedDowncastToActualType(&other); // We must report iterators equal if they both point beyond their // respective ranges. That can happen in a variety of fashions, // so we have to consult AtEnd(). return (AtEnd() && typed_other->AtEnd()) || ( current1_ == typed_other->current1_ && current2_ == typed_other->current2_); } private: Iterator(const Iterator& other) : base_(other.base_), begin1_(other.begin1_), end1_(other.end1_), current1_(other.current1_), begin2_(other.begin2_), end2_(other.end2_), current2_(other.current2_) { ComputeCurrentValue(); } void ComputeCurrentValue() { if (!AtEnd()) current_value_ = ParamType(*current1_, *current2_); } bool AtEnd() const { // We must report iterator past the end of the range when either of the // component iterators has reached the end of its range. return current1_ == end1_ || current2_ == end2_; } // No implementation - assignment is unsupported. void operator=(const Iterator& other); const ParamGeneratorInterface* const base_; // begin[i]_ and end[i]_ define the i-th range that Iterator traverses. // current[i]_ is the actual traversing iterator. const typename ParamGenerator::iterator begin1_; const typename ParamGenerator::iterator end1_; typename ParamGenerator::iterator current1_; const typename ParamGenerator::iterator begin2_; const typename ParamGenerator::iterator end2_; typename ParamGenerator::iterator current2_; ParamType current_value_; }; // class CartesianProductGenerator2::Iterator // No implementation - assignment is unsupported. void operator=(const CartesianProductGenerator2& other); const ParamGenerator g1_; const ParamGenerator g2_; }; // class CartesianProductGenerator2 template class CartesianProductGenerator3 : public ParamGeneratorInterface< ::stdt::tuple > { public: typedef ::stdt::tuple ParamType; CartesianProductGenerator3(const ParamGenerator& g1, const ParamGenerator& g2, const ParamGenerator& g3) : g1_(g1), g2_(g2), g3_(g3) {} virtual ~CartesianProductGenerator3() {} virtual ParamIteratorInterface* Begin() const { return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_, g3_.begin()); } virtual ParamIteratorInterface* End() const { return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end()); } private: class Iterator : public ParamIteratorInterface { public: Iterator(const ParamGeneratorInterface* base, const ParamGenerator& g1, const typename ParamGenerator::iterator& current1, const ParamGenerator& g2, const typename ParamGenerator::iterator& current2, const ParamGenerator& g3, const typename ParamGenerator::iterator& current3) : base_(base), begin1_(g1.begin()), end1_(g1.end()), current1_(current1), begin2_(g2.begin()), end2_(g2.end()), current2_(current2), begin3_(g3.begin()), end3_(g3.end()), current3_(current3) { ComputeCurrentValue(); } virtual ~Iterator() {} virtual const ParamGeneratorInterface* BaseGenerator() const { return base_; } // Advance should not be called on beyond-of-range iterators // so no component iterators must be beyond end of range, either. virtual void Advance() { assert(!AtEnd()); ++current3_; if (current3_ == end3_) { current3_ = begin3_; ++current2_; } if (current2_ == end2_) { current2_ = begin2_; ++current1_; } ComputeCurrentValue(); } virtual ParamIteratorInterface* Clone() const { return new Iterator(*this); } virtual const ParamType* Current() const { return ¤t_value_; } virtual bool Equals(const ParamIteratorInterface& other) const { // Having the same base generator guarantees that the other // iterator is of the same type and we can downcast. GTEST_CHECK_(BaseGenerator() == other.BaseGenerator()) << "The program attempted to compare iterators " << "from different generators." << std::endl; const Iterator* typed_other = CheckedDowncastToActualType(&other); // We must report iterators equal if they both point beyond their // respective ranges. That can happen in a variety of fashions, // so we have to consult AtEnd(). return (AtEnd() && typed_other->AtEnd()) || ( current1_ == typed_other->current1_ && current2_ == typed_other->current2_ && current3_ == typed_other->current3_); } private: Iterator(const Iterator& other) : base_(other.base_), begin1_(other.begin1_), end1_(other.end1_), current1_(other.current1_), begin2_(other.begin2_), end2_(other.end2_), current2_(other.current2_), begin3_(other.begin3_), end3_(other.end3_), current3_(other.current3_) { ComputeCurrentValue(); } void ComputeCurrentValue() { if (!AtEnd()) current_value_ = ParamType(*current1_, *current2_, *current3_); } bool AtEnd() const { // We must report iterator past the end of the range when either of the // component iterators has reached the end of its range. return current1_ == end1_ || current2_ == end2_ || current3_ == end3_; } // No implementation - assignment is unsupported. void operator=(const Iterator& other); const ParamGeneratorInterface* const base_; // begin[i]_ and end[i]_ define the i-th range that Iterator traverses. // current[i]_ is the actual traversing iterator. const typename ParamGenerator::iterator begin1_; const typename ParamGenerator::iterator end1_; typename ParamGenerator::iterator current1_; const typename ParamGenerator::iterator begin2_; const typename ParamGenerator::iterator end2_; typename ParamGenerator::iterator current2_; const typename ParamGenerator::iterator begin3_; const typename ParamGenerator::iterator end3_; typename ParamGenerator::iterator current3_; ParamType current_value_; }; // class CartesianProductGenerator3::Iterator // No implementation - assignment is unsupported. void operator=(const CartesianProductGenerator3& other); const ParamGenerator g1_; const ParamGenerator g2_; const ParamGenerator g3_; }; // class CartesianProductGenerator3 template class CartesianProductGenerator4 : public ParamGeneratorInterface< ::stdt::tuple > { public: typedef ::stdt::tuple ParamType; CartesianProductGenerator4(const ParamGenerator& g1, const ParamGenerator& g2, const ParamGenerator& g3, const ParamGenerator& g4) : g1_(g1), g2_(g2), g3_(g3), g4_(g4) {} virtual ~CartesianProductGenerator4() {} virtual ParamIteratorInterface* Begin() const { return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_, g3_.begin(), g4_, g4_.begin()); } virtual ParamIteratorInterface* End() const { return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end(), g4_, g4_.end()); } private: class Iterator : public ParamIteratorInterface { public: Iterator(const ParamGeneratorInterface* base, const ParamGenerator& g1, const typename ParamGenerator::iterator& current1, const ParamGenerator& g2, const typename ParamGenerator::iterator& current2, const ParamGenerator& g3, const typename ParamGenerator::iterator& current3, const ParamGenerator& g4, const typename ParamGenerator::iterator& current4) : base_(base), begin1_(g1.begin()), end1_(g1.end()), current1_(current1), begin2_(g2.begin()), end2_(g2.end()), current2_(current2), begin3_(g3.begin()), end3_(g3.end()), current3_(current3), begin4_(g4.begin()), end4_(g4.end()), current4_(current4) { ComputeCurrentValue(); } virtual ~Iterator() {} virtual const ParamGeneratorInterface* BaseGenerator() const { return base_; } // Advance should not be called on beyond-of-range iterators // so no component iterators must be beyond end of range, either. virtual void Advance() { assert(!AtEnd()); ++current4_; if (current4_ == end4_) { current4_ = begin4_; ++current3_; } if (current3_ == end3_) { current3_ = begin3_; ++current2_; } if (current2_ == end2_) { current2_ = begin2_; ++current1_; } ComputeCurrentValue(); } virtual ParamIteratorInterface* Clone() const { return new Iterator(*this); } virtual const ParamType* Current() const { return ¤t_value_; } virtual bool Equals(const ParamIteratorInterface& other) const { // Having the same base generator guarantees that the other // iterator is of the same type and we can downcast. GTEST_CHECK_(BaseGenerator() == other.BaseGenerator()) << "The program attempted to compare iterators " << "from different generators." << std::endl; const Iterator* typed_other = CheckedDowncastToActualType(&other); // We must report iterators equal if they both point beyond their // respective ranges. That can happen in a variety of fashions, // so we have to consult AtEnd(). return (AtEnd() && typed_other->AtEnd()) || ( current1_ == typed_other->current1_ && current2_ == typed_other->current2_ && current3_ == typed_other->current3_ && current4_ == typed_other->current4_); } private: Iterator(const Iterator& other) : base_(other.base_), begin1_(other.begin1_), end1_(other.end1_), current1_(other.current1_), begin2_(other.begin2_), end2_(other.end2_), current2_(other.current2_), begin3_(other.begin3_), end3_(other.end3_), current3_(other.current3_), begin4_(other.begin4_), end4_(other.end4_), current4_(other.current4_) { ComputeCurrentValue(); } void ComputeCurrentValue() { if (!AtEnd()) current_value_ = ParamType(*current1_, *current2_, *current3_, *current4_); } bool AtEnd() const { // We must report iterator past the end of the range when either of the // component iterators has reached the end of its range. return current1_ == end1_ || current2_ == end2_ || current3_ == end3_ || current4_ == end4_; } // No implementation - assignment is unsupported. void operator=(const Iterator& other); const ParamGeneratorInterface* const base_; // begin[i]_ and end[i]_ define the i-th range that Iterator traverses. // current[i]_ is the actual traversing iterator. const typename ParamGenerator::iterator begin1_; const typename ParamGenerator::iterator end1_; typename ParamGenerator::iterator current1_; const typename ParamGenerator::iterator begin2_; const typename ParamGenerator::iterator end2_; typename ParamGenerator::iterator current2_; const typename ParamGenerator::iterator begin3_; const typename ParamGenerator::iterator end3_; typename ParamGenerator::iterator current3_; const typename ParamGenerator::iterator begin4_; const typename ParamGenerator::iterator end4_; typename ParamGenerator::iterator current4_; ParamType current_value_; }; // class CartesianProductGenerator4::Iterator // No implementation - assignment is unsupported. void operator=(const CartesianProductGenerator4& other); const ParamGenerator g1_; const ParamGenerator g2_; const ParamGenerator g3_; const ParamGenerator g4_; }; // class CartesianProductGenerator4 template class CartesianProductGenerator5 : public ParamGeneratorInterface< ::stdt::tuple > { public: typedef ::stdt::tuple ParamType; CartesianProductGenerator5(const ParamGenerator& g1, const ParamGenerator& g2, const ParamGenerator& g3, const ParamGenerator& g4, const ParamGenerator& g5) : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5) {} virtual ~CartesianProductGenerator5() {} virtual ParamIteratorInterface* Begin() const { return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_, g3_.begin(), g4_, g4_.begin(), g5_, g5_.begin()); } virtual ParamIteratorInterface* End() const { return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end(), g4_, g4_.end(), g5_, g5_.end()); } private: class Iterator : public ParamIteratorInterface { public: Iterator(const ParamGeneratorInterface* base, const ParamGenerator& g1, const typename ParamGenerator::iterator& current1, const ParamGenerator& g2, const typename ParamGenerator::iterator& current2, const ParamGenerator& g3, const typename ParamGenerator::iterator& current3, const ParamGenerator& g4, const typename ParamGenerator::iterator& current4, const ParamGenerator& g5, const typename ParamGenerator::iterator& current5) : base_(base), begin1_(g1.begin()), end1_(g1.end()), current1_(current1), begin2_(g2.begin()), end2_(g2.end()), current2_(current2), begin3_(g3.begin()), end3_(g3.end()), current3_(current3), begin4_(g4.begin()), end4_(g4.end()), current4_(current4), begin5_(g5.begin()), end5_(g5.end()), current5_(current5) { ComputeCurrentValue(); } virtual ~Iterator() {} virtual const ParamGeneratorInterface* BaseGenerator() const { return base_; } // Advance should not be called on beyond-of-range iterators // so no component iterators must be beyond end of range, either. virtual void Advance() { assert(!AtEnd()); ++current5_; if (current5_ == end5_) { current5_ = begin5_; ++current4_; } if (current4_ == end4_) { current4_ = begin4_; ++current3_; } if (current3_ == end3_) { current3_ = begin3_; ++current2_; } if (current2_ == end2_) { current2_ = begin2_; ++current1_; } ComputeCurrentValue(); } virtual ParamIteratorInterface* Clone() const { return new Iterator(*this); } virtual const ParamType* Current() const { return ¤t_value_; } virtual bool Equals(const ParamIteratorInterface& other) const { // Having the same base generator guarantees that the other // iterator is of the same type and we can downcast. GTEST_CHECK_(BaseGenerator() == other.BaseGenerator()) << "The program attempted to compare iterators " << "from different generators." << std::endl; const Iterator* typed_other = CheckedDowncastToActualType(&other); // We must report iterators equal if they both point beyond their // respective ranges. That can happen in a variety of fashions, // so we have to consult AtEnd(). return (AtEnd() && typed_other->AtEnd()) || ( current1_ == typed_other->current1_ && current2_ == typed_other->current2_ && current3_ == typed_other->current3_ && current4_ == typed_other->current4_ && current5_ == typed_other->current5_); } private: Iterator(const Iterator& other) : base_(other.base_), begin1_(other.begin1_), end1_(other.end1_), current1_(other.current1_), begin2_(other.begin2_), end2_(other.end2_), current2_(other.current2_), begin3_(other.begin3_), end3_(other.end3_), current3_(other.current3_), begin4_(other.begin4_), end4_(other.end4_), current4_(other.current4_), begin5_(other.begin5_), end5_(other.end5_), current5_(other.current5_) { ComputeCurrentValue(); } void ComputeCurrentValue() { if (!AtEnd()) current_value_ = ParamType(*current1_, *current2_, *current3_, *current4_, *current5_); } bool AtEnd() const { // We must report iterator past the end of the range when either of the // component iterators has reached the end of its range. return current1_ == end1_ || current2_ == end2_ || current3_ == end3_ || current4_ == end4_ || current5_ == end5_; } // No implementation - assignment is unsupported. void operator=(const Iterator& other); const ParamGeneratorInterface* const base_; // begin[i]_ and end[i]_ define the i-th range that Iterator traverses. // current[i]_ is the actual traversing iterator. const typename ParamGenerator::iterator begin1_; const typename ParamGenerator::iterator end1_; typename ParamGenerator::iterator current1_; const typename ParamGenerator::iterator begin2_; const typename ParamGenerator::iterator end2_; typename ParamGenerator::iterator current2_; const typename ParamGenerator::iterator begin3_; const typename ParamGenerator::iterator end3_; typename ParamGenerator::iterator current3_; const typename ParamGenerator::iterator begin4_; const typename ParamGenerator::iterator end4_; typename ParamGenerator::iterator current4_; const typename ParamGenerator::iterator begin5_; const typename ParamGenerator::iterator end5_; typename ParamGenerator::iterator current5_; ParamType current_value_; }; // class CartesianProductGenerator5::Iterator // No implementation - assignment is unsupported. void operator=(const CartesianProductGenerator5& other); const ParamGenerator g1_; const ParamGenerator g2_; const ParamGenerator g3_; const ParamGenerator g4_; const ParamGenerator g5_; }; // class CartesianProductGenerator5 template class CartesianProductGenerator6 : public ParamGeneratorInterface< ::stdt::tuple > { public: typedef ::stdt::tuple ParamType; CartesianProductGenerator6(const ParamGenerator& g1, const ParamGenerator& g2, const ParamGenerator& g3, const ParamGenerator& g4, const ParamGenerator& g5, const ParamGenerator& g6) : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6) {} virtual ~CartesianProductGenerator6() {} virtual ParamIteratorInterface* Begin() const { return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_, g3_.begin(), g4_, g4_.begin(), g5_, g5_.begin(), g6_, g6_.begin()); } virtual ParamIteratorInterface* End() const { return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end(), g4_, g4_.end(), g5_, g5_.end(), g6_, g6_.end()); } private: class Iterator : public ParamIteratorInterface { public: Iterator(const ParamGeneratorInterface* base, const ParamGenerator& g1, const typename ParamGenerator::iterator& current1, const ParamGenerator& g2, const typename ParamGenerator::iterator& current2, const ParamGenerator& g3, const typename ParamGenerator::iterator& current3, const ParamGenerator& g4, const typename ParamGenerator::iterator& current4, const ParamGenerator& g5, const typename ParamGenerator::iterator& current5, const ParamGenerator& g6, const typename ParamGenerator::iterator& current6) : base_(base), begin1_(g1.begin()), end1_(g1.end()), current1_(current1), begin2_(g2.begin()), end2_(g2.end()), current2_(current2), begin3_(g3.begin()), end3_(g3.end()), current3_(current3), begin4_(g4.begin()), end4_(g4.end()), current4_(current4), begin5_(g5.begin()), end5_(g5.end()), current5_(current5), begin6_(g6.begin()), end6_(g6.end()), current6_(current6) { ComputeCurrentValue(); } virtual ~Iterator() {} virtual const ParamGeneratorInterface* BaseGenerator() const { return base_; } // Advance should not be called on beyond-of-range iterators // so no component iterators must be beyond end of range, either. virtual void Advance() { assert(!AtEnd()); ++current6_; if (current6_ == end6_) { current6_ = begin6_; ++current5_; } if (current5_ == end5_) { current5_ = begin5_; ++current4_; } if (current4_ == end4_) { current4_ = begin4_; ++current3_; } if (current3_ == end3_) { current3_ = begin3_; ++current2_; } if (current2_ == end2_) { current2_ = begin2_; ++current1_; } ComputeCurrentValue(); } virtual ParamIteratorInterface* Clone() const { return new Iterator(*this); } virtual const ParamType* Current() const { return ¤t_value_; } virtual bool Equals(const ParamIteratorInterface& other) const { // Having the same base generator guarantees that the other // iterator is of the same type and we can downcast. GTEST_CHECK_(BaseGenerator() == other.BaseGenerator()) << "The program attempted to compare iterators " << "from different generators." << std::endl; const Iterator* typed_other = CheckedDowncastToActualType(&other); // We must report iterators equal if they both point beyond their // respective ranges. That can happen in a variety of fashions, // so we have to consult AtEnd(). return (AtEnd() && typed_other->AtEnd()) || ( current1_ == typed_other->current1_ && current2_ == typed_other->current2_ && current3_ == typed_other->current3_ && current4_ == typed_other->current4_ && current5_ == typed_other->current5_ && current6_ == typed_other->current6_); } private: Iterator(const Iterator& other) : base_(other.base_), begin1_(other.begin1_), end1_(other.end1_), current1_(other.current1_), begin2_(other.begin2_), end2_(other.end2_), current2_(other.current2_), begin3_(other.begin3_), end3_(other.end3_), current3_(other.current3_), begin4_(other.begin4_), end4_(other.end4_), current4_(other.current4_), begin5_(other.begin5_), end5_(other.end5_), current5_(other.current5_), begin6_(other.begin6_), end6_(other.end6_), current6_(other.current6_) { ComputeCurrentValue(); } void ComputeCurrentValue() { if (!AtEnd()) current_value_ = ParamType(*current1_, *current2_, *current3_, *current4_, *current5_, *current6_); } bool AtEnd() const { // We must report iterator past the end of the range when either of the // component iterators has reached the end of its range. return current1_ == end1_ || current2_ == end2_ || current3_ == end3_ || current4_ == end4_ || current5_ == end5_ || current6_ == end6_; } // No implementation - assignment is unsupported. void operator=(const Iterator& other); const ParamGeneratorInterface* const base_; // begin[i]_ and end[i]_ define the i-th range that Iterator traverses. // current[i]_ is the actual traversing iterator. const typename ParamGenerator::iterator begin1_; const typename ParamGenerator::iterator end1_; typename ParamGenerator::iterator current1_; const typename ParamGenerator::iterator begin2_; const typename ParamGenerator::iterator end2_; typename ParamGenerator::iterator current2_; const typename ParamGenerator::iterator begin3_; const typename ParamGenerator::iterator end3_; typename ParamGenerator::iterator current3_; const typename ParamGenerator::iterator begin4_; const typename ParamGenerator::iterator end4_; typename ParamGenerator::iterator current4_; const typename ParamGenerator::iterator begin5_; const typename ParamGenerator::iterator end5_; typename ParamGenerator::iterator current5_; const typename ParamGenerator::iterator begin6_; const typename ParamGenerator::iterator end6_; typename ParamGenerator::iterator current6_; ParamType current_value_; }; // class CartesianProductGenerator6::Iterator // No implementation - assignment is unsupported. void operator=(const CartesianProductGenerator6& other); const ParamGenerator g1_; const ParamGenerator g2_; const ParamGenerator g3_; const ParamGenerator g4_; const ParamGenerator g5_; const ParamGenerator g6_; }; // class CartesianProductGenerator6 template class CartesianProductGenerator7 : public ParamGeneratorInterface< ::stdt::tuple > { public: typedef ::stdt::tuple ParamType; CartesianProductGenerator7(const ParamGenerator& g1, const ParamGenerator& g2, const ParamGenerator& g3, const ParamGenerator& g4, const ParamGenerator& g5, const ParamGenerator& g6, const ParamGenerator& g7) : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7) {} virtual ~CartesianProductGenerator7() {} virtual ParamIteratorInterface* Begin() const { return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_, g3_.begin(), g4_, g4_.begin(), g5_, g5_.begin(), g6_, g6_.begin(), g7_, g7_.begin()); } virtual ParamIteratorInterface* End() const { return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end(), g4_, g4_.end(), g5_, g5_.end(), g6_, g6_.end(), g7_, g7_.end()); } private: class Iterator : public ParamIteratorInterface { public: Iterator(const ParamGeneratorInterface* base, const ParamGenerator& g1, const typename ParamGenerator::iterator& current1, const ParamGenerator& g2, const typename ParamGenerator::iterator& current2, const ParamGenerator& g3, const typename ParamGenerator::iterator& current3, const ParamGenerator& g4, const typename ParamGenerator::iterator& current4, const ParamGenerator& g5, const typename ParamGenerator::iterator& current5, const ParamGenerator& g6, const typename ParamGenerator::iterator& current6, const ParamGenerator& g7, const typename ParamGenerator::iterator& current7) : base_(base), begin1_(g1.begin()), end1_(g1.end()), current1_(current1), begin2_(g2.begin()), end2_(g2.end()), current2_(current2), begin3_(g3.begin()), end3_(g3.end()), current3_(current3), begin4_(g4.begin()), end4_(g4.end()), current4_(current4), begin5_(g5.begin()), end5_(g5.end()), current5_(current5), begin6_(g6.begin()), end6_(g6.end()), current6_(current6), begin7_(g7.begin()), end7_(g7.end()), current7_(current7) { ComputeCurrentValue(); } virtual ~Iterator() {} virtual const ParamGeneratorInterface* BaseGenerator() const { return base_; } // Advance should not be called on beyond-of-range iterators // so no component iterators must be beyond end of range, either. virtual void Advance() { assert(!AtEnd()); ++current7_; if (current7_ == end7_) { current7_ = begin7_; ++current6_; } if (current6_ == end6_) { current6_ = begin6_; ++current5_; } if (current5_ == end5_) { current5_ = begin5_; ++current4_; } if (current4_ == end4_) { current4_ = begin4_; ++current3_; } if (current3_ == end3_) { current3_ = begin3_; ++current2_; } if (current2_ == end2_) { current2_ = begin2_; ++current1_; } ComputeCurrentValue(); } virtual ParamIteratorInterface* Clone() const { return new Iterator(*this); } virtual const ParamType* Current() const { return ¤t_value_; } virtual bool Equals(const ParamIteratorInterface& other) const { // Having the same base generator guarantees that the other // iterator is of the same type and we can downcast. GTEST_CHECK_(BaseGenerator() == other.BaseGenerator()) << "The program attempted to compare iterators " << "from different generators." << std::endl; const Iterator* typed_other = CheckedDowncastToActualType(&other); // We must report iterators equal if they both point beyond their // respective ranges. That can happen in a variety of fashions, // so we have to consult AtEnd(). return (AtEnd() && typed_other->AtEnd()) || ( current1_ == typed_other->current1_ && current2_ == typed_other->current2_ && current3_ == typed_other->current3_ && current4_ == typed_other->current4_ && current5_ == typed_other->current5_ && current6_ == typed_other->current6_ && current7_ == typed_other->current7_); } private: Iterator(const Iterator& other) : base_(other.base_), begin1_(other.begin1_), end1_(other.end1_), current1_(other.current1_), begin2_(other.begin2_), end2_(other.end2_), current2_(other.current2_), begin3_(other.begin3_), end3_(other.end3_), current3_(other.current3_), begin4_(other.begin4_), end4_(other.end4_), current4_(other.current4_), begin5_(other.begin5_), end5_(other.end5_), current5_(other.current5_), begin6_(other.begin6_), end6_(other.end6_), current6_(other.current6_), begin7_(other.begin7_), end7_(other.end7_), current7_(other.current7_) { ComputeCurrentValue(); } void ComputeCurrentValue() { if (!AtEnd()) current_value_ = ParamType(*current1_, *current2_, *current3_, *current4_, *current5_, *current6_, *current7_); } bool AtEnd() const { // We must report iterator past the end of the range when either of the // component iterators has reached the end of its range. return current1_ == end1_ || current2_ == end2_ || current3_ == end3_ || current4_ == end4_ || current5_ == end5_ || current6_ == end6_ || current7_ == end7_; } // No implementation - assignment is unsupported. void operator=(const Iterator& other); const ParamGeneratorInterface* const base_; // begin[i]_ and end[i]_ define the i-th range that Iterator traverses. // current[i]_ is the actual traversing iterator. const typename ParamGenerator::iterator begin1_; const typename ParamGenerator::iterator end1_; typename ParamGenerator::iterator current1_; const typename ParamGenerator::iterator begin2_; const typename ParamGenerator::iterator end2_; typename ParamGenerator::iterator current2_; const typename ParamGenerator::iterator begin3_; const typename ParamGenerator::iterator end3_; typename ParamGenerator::iterator current3_; const typename ParamGenerator::iterator begin4_; const typename ParamGenerator::iterator end4_; typename ParamGenerator::iterator current4_; const typename ParamGenerator::iterator begin5_; const typename ParamGenerator::iterator end5_; typename ParamGenerator::iterator current5_; const typename ParamGenerator::iterator begin6_; const typename ParamGenerator::iterator end6_; typename ParamGenerator::iterator current6_; const typename ParamGenerator::iterator begin7_; const typename ParamGenerator::iterator end7_; typename ParamGenerator::iterator current7_; ParamType current_value_; }; // class CartesianProductGenerator7::Iterator // No implementation - assignment is unsupported. void operator=(const CartesianProductGenerator7& other); const ParamGenerator g1_; const ParamGenerator g2_; const ParamGenerator g3_; const ParamGenerator g4_; const ParamGenerator g5_; const ParamGenerator g6_; const ParamGenerator g7_; }; // class CartesianProductGenerator7 template class CartesianProductGenerator8 : public ParamGeneratorInterface< ::stdt::tuple > { public: typedef ::stdt::tuple ParamType; CartesianProductGenerator8(const ParamGenerator& g1, const ParamGenerator& g2, const ParamGenerator& g3, const ParamGenerator& g4, const ParamGenerator& g5, const ParamGenerator& g6, const ParamGenerator& g7, const ParamGenerator& g8) : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7), g8_(g8) {} virtual ~CartesianProductGenerator8() {} virtual ParamIteratorInterface* Begin() const { return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_, g3_.begin(), g4_, g4_.begin(), g5_, g5_.begin(), g6_, g6_.begin(), g7_, g7_.begin(), g8_, g8_.begin()); } virtual ParamIteratorInterface* End() const { return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end(), g4_, g4_.end(), g5_, g5_.end(), g6_, g6_.end(), g7_, g7_.end(), g8_, g8_.end()); } private: class Iterator : public ParamIteratorInterface { public: Iterator(const ParamGeneratorInterface* base, const ParamGenerator& g1, const typename ParamGenerator::iterator& current1, const ParamGenerator& g2, const typename ParamGenerator::iterator& current2, const ParamGenerator& g3, const typename ParamGenerator::iterator& current3, const ParamGenerator& g4, const typename ParamGenerator::iterator& current4, const ParamGenerator& g5, const typename ParamGenerator::iterator& current5, const ParamGenerator& g6, const typename ParamGenerator::iterator& current6, const ParamGenerator& g7, const typename ParamGenerator::iterator& current7, const ParamGenerator& g8, const typename ParamGenerator::iterator& current8) : base_(base), begin1_(g1.begin()), end1_(g1.end()), current1_(current1), begin2_(g2.begin()), end2_(g2.end()), current2_(current2), begin3_(g3.begin()), end3_(g3.end()), current3_(current3), begin4_(g4.begin()), end4_(g4.end()), current4_(current4), begin5_(g5.begin()), end5_(g5.end()), current5_(current5), begin6_(g6.begin()), end6_(g6.end()), current6_(current6), begin7_(g7.begin()), end7_(g7.end()), current7_(current7), begin8_(g8.begin()), end8_(g8.end()), current8_(current8) { ComputeCurrentValue(); } virtual ~Iterator() {} virtual const ParamGeneratorInterface* BaseGenerator() const { return base_; } // Advance should not be called on beyond-of-range iterators // so no component iterators must be beyond end of range, either. virtual void Advance() { assert(!AtEnd()); ++current8_; if (current8_ == end8_) { current8_ = begin8_; ++current7_; } if (current7_ == end7_) { current7_ = begin7_; ++current6_; } if (current6_ == end6_) { current6_ = begin6_; ++current5_; } if (current5_ == end5_) { current5_ = begin5_; ++current4_; } if (current4_ == end4_) { current4_ = begin4_; ++current3_; } if (current3_ == end3_) { current3_ = begin3_; ++current2_; } if (current2_ == end2_) { current2_ = begin2_; ++current1_; } ComputeCurrentValue(); } virtual ParamIteratorInterface* Clone() const { return new Iterator(*this); } virtual const ParamType* Current() const { return ¤t_value_; } virtual bool Equals(const ParamIteratorInterface& other) const { // Having the same base generator guarantees that the other // iterator is of the same type and we can downcast. GTEST_CHECK_(BaseGenerator() == other.BaseGenerator()) << "The program attempted to compare iterators " << "from different generators." << std::endl; const Iterator* typed_other = CheckedDowncastToActualType(&other); // We must report iterators equal if they both point beyond their // respective ranges. That can happen in a variety of fashions, // so we have to consult AtEnd(). return (AtEnd() && typed_other->AtEnd()) || ( current1_ == typed_other->current1_ && current2_ == typed_other->current2_ && current3_ == typed_other->current3_ && current4_ == typed_other->current4_ && current5_ == typed_other->current5_ && current6_ == typed_other->current6_ && current7_ == typed_other->current7_ && current8_ == typed_other->current8_); } private: Iterator(const Iterator& other) : base_(other.base_), begin1_(other.begin1_), end1_(other.end1_), current1_(other.current1_), begin2_(other.begin2_), end2_(other.end2_), current2_(other.current2_), begin3_(other.begin3_), end3_(other.end3_), current3_(other.current3_), begin4_(other.begin4_), end4_(other.end4_), current4_(other.current4_), begin5_(other.begin5_), end5_(other.end5_), current5_(other.current5_), begin6_(other.begin6_), end6_(other.end6_), current6_(other.current6_), begin7_(other.begin7_), end7_(other.end7_), current7_(other.current7_), begin8_(other.begin8_), end8_(other.end8_), current8_(other.current8_) { ComputeCurrentValue(); } void ComputeCurrentValue() { if (!AtEnd()) current_value_ = ParamType(*current1_, *current2_, *current3_, *current4_, *current5_, *current6_, *current7_, *current8_); } bool AtEnd() const { // We must report iterator past the end of the range when either of the // component iterators has reached the end of its range. return current1_ == end1_ || current2_ == end2_ || current3_ == end3_ || current4_ == end4_ || current5_ == end5_ || current6_ == end6_ || current7_ == end7_ || current8_ == end8_; } // No implementation - assignment is unsupported. void operator=(const Iterator& other); const ParamGeneratorInterface* const base_; // begin[i]_ and end[i]_ define the i-th range that Iterator traverses. // current[i]_ is the actual traversing iterator. const typename ParamGenerator::iterator begin1_; const typename ParamGenerator::iterator end1_; typename ParamGenerator::iterator current1_; const typename ParamGenerator::iterator begin2_; const typename ParamGenerator::iterator end2_; typename ParamGenerator::iterator current2_; const typename ParamGenerator::iterator begin3_; const typename ParamGenerator::iterator end3_; typename ParamGenerator::iterator current3_; const typename ParamGenerator::iterator begin4_; const typename ParamGenerator::iterator end4_; typename ParamGenerator::iterator current4_; const typename ParamGenerator::iterator begin5_; const typename ParamGenerator::iterator end5_; typename ParamGenerator::iterator current5_; const typename ParamGenerator::iterator begin6_; const typename ParamGenerator::iterator end6_; typename ParamGenerator::iterator current6_; const typename ParamGenerator::iterator begin7_; const typename ParamGenerator::iterator end7_; typename ParamGenerator::iterator current7_; const typename ParamGenerator::iterator begin8_; const typename ParamGenerator::iterator end8_; typename ParamGenerator::iterator current8_; ParamType current_value_; }; // class CartesianProductGenerator8::Iterator // No implementation - assignment is unsupported. void operator=(const CartesianProductGenerator8& other); const ParamGenerator g1_; const ParamGenerator g2_; const ParamGenerator g3_; const ParamGenerator g4_; const ParamGenerator g5_; const ParamGenerator g6_; const ParamGenerator g7_; const ParamGenerator g8_; }; // class CartesianProductGenerator8 template class CartesianProductGenerator9 : public ParamGeneratorInterface< ::stdt::tuple > { public: typedef ::stdt::tuple ParamType; CartesianProductGenerator9(const ParamGenerator& g1, const ParamGenerator& g2, const ParamGenerator& g3, const ParamGenerator& g4, const ParamGenerator& g5, const ParamGenerator& g6, const ParamGenerator& g7, const ParamGenerator& g8, const ParamGenerator& g9) : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7), g8_(g8), g9_(g9) {} virtual ~CartesianProductGenerator9() {} virtual ParamIteratorInterface* Begin() const { return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_, g3_.begin(), g4_, g4_.begin(), g5_, g5_.begin(), g6_, g6_.begin(), g7_, g7_.begin(), g8_, g8_.begin(), g9_, g9_.begin()); } virtual ParamIteratorInterface* End() const { return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end(), g4_, g4_.end(), g5_, g5_.end(), g6_, g6_.end(), g7_, g7_.end(), g8_, g8_.end(), g9_, g9_.end()); } private: class Iterator : public ParamIteratorInterface { public: Iterator(const ParamGeneratorInterface* base, const ParamGenerator& g1, const typename ParamGenerator::iterator& current1, const ParamGenerator& g2, const typename ParamGenerator::iterator& current2, const ParamGenerator& g3, const typename ParamGenerator::iterator& current3, const ParamGenerator& g4, const typename ParamGenerator::iterator& current4, const ParamGenerator& g5, const typename ParamGenerator::iterator& current5, const ParamGenerator& g6, const typename ParamGenerator::iterator& current6, const ParamGenerator& g7, const typename ParamGenerator::iterator& current7, const ParamGenerator& g8, const typename ParamGenerator::iterator& current8, const ParamGenerator& g9, const typename ParamGenerator::iterator& current9) : base_(base), begin1_(g1.begin()), end1_(g1.end()), current1_(current1), begin2_(g2.begin()), end2_(g2.end()), current2_(current2), begin3_(g3.begin()), end3_(g3.end()), current3_(current3), begin4_(g4.begin()), end4_(g4.end()), current4_(current4), begin5_(g5.begin()), end5_(g5.end()), current5_(current5), begin6_(g6.begin()), end6_(g6.end()), current6_(current6), begin7_(g7.begin()), end7_(g7.end()), current7_(current7), begin8_(g8.begin()), end8_(g8.end()), current8_(current8), begin9_(g9.begin()), end9_(g9.end()), current9_(current9) { ComputeCurrentValue(); } virtual ~Iterator() {} virtual const ParamGeneratorInterface* BaseGenerator() const { return base_; } // Advance should not be called on beyond-of-range iterators // so no component iterators must be beyond end of range, either. virtual void Advance() { assert(!AtEnd()); ++current9_; if (current9_ == end9_) { current9_ = begin9_; ++current8_; } if (current8_ == end8_) { current8_ = begin8_; ++current7_; } if (current7_ == end7_) { current7_ = begin7_; ++current6_; } if (current6_ == end6_) { current6_ = begin6_; ++current5_; } if (current5_ == end5_) { current5_ = begin5_; ++current4_; } if (current4_ == end4_) { current4_ = begin4_; ++current3_; } if (current3_ == end3_) { current3_ = begin3_; ++current2_; } if (current2_ == end2_) { current2_ = begin2_; ++current1_; } ComputeCurrentValue(); } virtual ParamIteratorInterface* Clone() const { return new Iterator(*this); } virtual const ParamType* Current() const { return ¤t_value_; } virtual bool Equals(const ParamIteratorInterface& other) const { // Having the same base generator guarantees that the other // iterator is of the same type and we can downcast. GTEST_CHECK_(BaseGenerator() == other.BaseGenerator()) << "The program attempted to compare iterators " << "from different generators." << std::endl; const Iterator* typed_other = CheckedDowncastToActualType(&other); // We must report iterators equal if they both point beyond their // respective ranges. That can happen in a variety of fashions, // so we have to consult AtEnd(). return (AtEnd() && typed_other->AtEnd()) || ( current1_ == typed_other->current1_ && current2_ == typed_other->current2_ && current3_ == typed_other->current3_ && current4_ == typed_other->current4_ && current5_ == typed_other->current5_ && current6_ == typed_other->current6_ && current7_ == typed_other->current7_ && current8_ == typed_other->current8_ && current9_ == typed_other->current9_); } private: Iterator(const Iterator& other) : base_(other.base_), begin1_(other.begin1_), end1_(other.end1_), current1_(other.current1_), begin2_(other.begin2_), end2_(other.end2_), current2_(other.current2_), begin3_(other.begin3_), end3_(other.end3_), current3_(other.current3_), begin4_(other.begin4_), end4_(other.end4_), current4_(other.current4_), begin5_(other.begin5_), end5_(other.end5_), current5_(other.current5_), begin6_(other.begin6_), end6_(other.end6_), current6_(other.current6_), begin7_(other.begin7_), end7_(other.end7_), current7_(other.current7_), begin8_(other.begin8_), end8_(other.end8_), current8_(other.current8_), begin9_(other.begin9_), end9_(other.end9_), current9_(other.current9_) { ComputeCurrentValue(); } void ComputeCurrentValue() { if (!AtEnd()) current_value_ = ParamType(*current1_, *current2_, *current3_, *current4_, *current5_, *current6_, *current7_, *current8_, *current9_); } bool AtEnd() const { // We must report iterator past the end of the range when either of the // component iterators has reached the end of its range. return current1_ == end1_ || current2_ == end2_ || current3_ == end3_ || current4_ == end4_ || current5_ == end5_ || current6_ == end6_ || current7_ == end7_ || current8_ == end8_ || current9_ == end9_; } // No implementation - assignment is unsupported. void operator=(const Iterator& other); const ParamGeneratorInterface* const base_; // begin[i]_ and end[i]_ define the i-th range that Iterator traverses. // current[i]_ is the actual traversing iterator. const typename ParamGenerator::iterator begin1_; const typename ParamGenerator::iterator end1_; typename ParamGenerator::iterator current1_; const typename ParamGenerator::iterator begin2_; const typename ParamGenerator::iterator end2_; typename ParamGenerator::iterator current2_; const typename ParamGenerator::iterator begin3_; const typename ParamGenerator::iterator end3_; typename ParamGenerator::iterator current3_; const typename ParamGenerator::iterator begin4_; const typename ParamGenerator::iterator end4_; typename ParamGenerator::iterator current4_; const typename ParamGenerator::iterator begin5_; const typename ParamGenerator::iterator end5_; typename ParamGenerator::iterator current5_; const typename ParamGenerator::iterator begin6_; const typename ParamGenerator::iterator end6_; typename ParamGenerator::iterator current6_; const typename ParamGenerator::iterator begin7_; const typename ParamGenerator::iterator end7_; typename ParamGenerator::iterator current7_; const typename ParamGenerator::iterator begin8_; const typename ParamGenerator::iterator end8_; typename ParamGenerator::iterator current8_; const typename ParamGenerator::iterator begin9_; const typename ParamGenerator::iterator end9_; typename ParamGenerator::iterator current9_; ParamType current_value_; }; // class CartesianProductGenerator9::Iterator // No implementation - assignment is unsupported. void operator=(const CartesianProductGenerator9& other); const ParamGenerator g1_; const ParamGenerator g2_; const ParamGenerator g3_; const ParamGenerator g4_; const ParamGenerator g5_; const ParamGenerator g6_; const ParamGenerator g7_; const ParamGenerator g8_; const ParamGenerator g9_; }; // class CartesianProductGenerator9 template class CartesianProductGenerator10 : public ParamGeneratorInterface< ::stdt::tuple > { public: typedef ::stdt::tuple ParamType; CartesianProductGenerator10(const ParamGenerator& g1, const ParamGenerator& g2, const ParamGenerator& g3, const ParamGenerator& g4, const ParamGenerator& g5, const ParamGenerator& g6, const ParamGenerator& g7, const ParamGenerator& g8, const ParamGenerator& g9, const ParamGenerator& g10) : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7), g8_(g8), g9_(g9), g10_(g10) {} virtual ~CartesianProductGenerator10() {} virtual ParamIteratorInterface* Begin() const { return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_, g3_.begin(), g4_, g4_.begin(), g5_, g5_.begin(), g6_, g6_.begin(), g7_, g7_.begin(), g8_, g8_.begin(), g9_, g9_.begin(), g10_, g10_.begin()); } virtual ParamIteratorInterface* End() const { return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end(), g4_, g4_.end(), g5_, g5_.end(), g6_, g6_.end(), g7_, g7_.end(), g8_, g8_.end(), g9_, g9_.end(), g10_, g10_.end()); } private: class Iterator : public ParamIteratorInterface { public: Iterator(const ParamGeneratorInterface* base, const ParamGenerator& g1, const typename ParamGenerator::iterator& current1, const ParamGenerator& g2, const typename ParamGenerator::iterator& current2, const ParamGenerator& g3, const typename ParamGenerator::iterator& current3, const ParamGenerator& g4, const typename ParamGenerator::iterator& current4, const ParamGenerator& g5, const typename ParamGenerator::iterator& current5, const ParamGenerator& g6, const typename ParamGenerator::iterator& current6, const ParamGenerator& g7, const typename ParamGenerator::iterator& current7, const ParamGenerator& g8, const typename ParamGenerator::iterator& current8, const ParamGenerator& g9, const typename ParamGenerator::iterator& current9, const ParamGenerator& g10, const typename ParamGenerator::iterator& current10) : base_(base), begin1_(g1.begin()), end1_(g1.end()), current1_(current1), begin2_(g2.begin()), end2_(g2.end()), current2_(current2), begin3_(g3.begin()), end3_(g3.end()), current3_(current3), begin4_(g4.begin()), end4_(g4.end()), current4_(current4), begin5_(g5.begin()), end5_(g5.end()), current5_(current5), begin6_(g6.begin()), end6_(g6.end()), current6_(current6), begin7_(g7.begin()), end7_(g7.end()), current7_(current7), begin8_(g8.begin()), end8_(g8.end()), current8_(current8), begin9_(g9.begin()), end9_(g9.end()), current9_(current9), begin10_(g10.begin()), end10_(g10.end()), current10_(current10) { ComputeCurrentValue(); } virtual ~Iterator() {} virtual const ParamGeneratorInterface* BaseGenerator() const { return base_; } // Advance should not be called on beyond-of-range iterators // so no component iterators must be beyond end of range, either. virtual void Advance() { assert(!AtEnd()); ++current10_; if (current10_ == end10_) { current10_ = begin10_; ++current9_; } if (current9_ == end9_) { current9_ = begin9_; ++current8_; } if (current8_ == end8_) { current8_ = begin8_; ++current7_; } if (current7_ == end7_) { current7_ = begin7_; ++current6_; } if (current6_ == end6_) { current6_ = begin6_; ++current5_; } if (current5_ == end5_) { current5_ = begin5_; ++current4_; } if (current4_ == end4_) { current4_ = begin4_; ++current3_; } if (current3_ == end3_) { current3_ = begin3_; ++current2_; } if (current2_ == end2_) { current2_ = begin2_; ++current1_; } ComputeCurrentValue(); } virtual ParamIteratorInterface* Clone() const { return new Iterator(*this); } virtual const ParamType* Current() const { return ¤t_value_; } virtual bool Equals(const ParamIteratorInterface& other) const { // Having the same base generator guarantees that the other // iterator is of the same type and we can downcast. GTEST_CHECK_(BaseGenerator() == other.BaseGenerator()) << "The program attempted to compare iterators " << "from different generators." << std::endl; const Iterator* typed_other = CheckedDowncastToActualType(&other); // We must report iterators equal if they both point beyond their // respective ranges. That can happen in a variety of fashions, // so we have to consult AtEnd(). return (AtEnd() && typed_other->AtEnd()) || ( current1_ == typed_other->current1_ && current2_ == typed_other->current2_ && current3_ == typed_other->current3_ && current4_ == typed_other->current4_ && current5_ == typed_other->current5_ && current6_ == typed_other->current6_ && current7_ == typed_other->current7_ && current8_ == typed_other->current8_ && current9_ == typed_other->current9_ && current10_ == typed_other->current10_); } private: Iterator(const Iterator& other) : base_(other.base_), begin1_(other.begin1_), end1_(other.end1_), current1_(other.current1_), begin2_(other.begin2_), end2_(other.end2_), current2_(other.current2_), begin3_(other.begin3_), end3_(other.end3_), current3_(other.current3_), begin4_(other.begin4_), end4_(other.end4_), current4_(other.current4_), begin5_(other.begin5_), end5_(other.end5_), current5_(other.current5_), begin6_(other.begin6_), end6_(other.end6_), current6_(other.current6_), begin7_(other.begin7_), end7_(other.end7_), current7_(other.current7_), begin8_(other.begin8_), end8_(other.end8_), current8_(other.current8_), begin9_(other.begin9_), end9_(other.end9_), current9_(other.current9_), begin10_(other.begin10_), end10_(other.end10_), current10_(other.current10_) { ComputeCurrentValue(); } void ComputeCurrentValue() { if (!AtEnd()) current_value_ = ParamType(*current1_, *current2_, *current3_, *current4_, *current5_, *current6_, *current7_, *current8_, *current9_, *current10_); } bool AtEnd() const { // We must report iterator past the end of the range when either of the // component iterators has reached the end of its range. return current1_ == end1_ || current2_ == end2_ || current3_ == end3_ || current4_ == end4_ || current5_ == end5_ || current6_ == end6_ || current7_ == end7_ || current8_ == end8_ || current9_ == end9_ || current10_ == end10_; } // No implementation - assignment is unsupported. void operator=(const Iterator& other); const ParamGeneratorInterface* const base_; // begin[i]_ and end[i]_ define the i-th range that Iterator traverses. // current[i]_ is the actual traversing iterator. const typename ParamGenerator::iterator begin1_; const typename ParamGenerator::iterator end1_; typename ParamGenerator::iterator current1_; const typename ParamGenerator::iterator begin2_; const typename ParamGenerator::iterator end2_; typename ParamGenerator::iterator current2_; const typename ParamGenerator::iterator begin3_; const typename ParamGenerator::iterator end3_; typename ParamGenerator::iterator current3_; const typename ParamGenerator::iterator begin4_; const typename ParamGenerator::iterator end4_; typename ParamGenerator::iterator current4_; const typename ParamGenerator::iterator begin5_; const typename ParamGenerator::iterator end5_; typename ParamGenerator::iterator current5_; const typename ParamGenerator::iterator begin6_; const typename ParamGenerator::iterator end6_; typename ParamGenerator::iterator current6_; const typename ParamGenerator::iterator begin7_; const typename ParamGenerator::iterator end7_; typename ParamGenerator::iterator current7_; const typename ParamGenerator::iterator begin8_; const typename ParamGenerator::iterator end8_; typename ParamGenerator::iterator current8_; const typename ParamGenerator::iterator begin9_; const typename ParamGenerator::iterator end9_; typename ParamGenerator::iterator current9_; const typename ParamGenerator::iterator begin10_; const typename ParamGenerator::iterator end10_; typename ParamGenerator::iterator current10_; ParamType current_value_; }; // class CartesianProductGenerator10::Iterator // No implementation - assignment is unsupported. void operator=(const CartesianProductGenerator10& other); const ParamGenerator g1_; const ParamGenerator g2_; const ParamGenerator g3_; const ParamGenerator g4_; const ParamGenerator g5_; const ParamGenerator g6_; const ParamGenerator g7_; const ParamGenerator g8_; const ParamGenerator g9_; const ParamGenerator g10_; }; // class CartesianProductGenerator10 // INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. // // Helper classes providing Combine() with polymorphic features. They allow // casting CartesianProductGeneratorN to ParamGenerator if T is // convertible to U. // template class CartesianProductHolder2 { public: CartesianProductHolder2(const Generator1& g1, const Generator2& g2) : g1_(g1), g2_(g2) {} template operator ParamGenerator< ::stdt::tuple >() const { return ParamGenerator< ::stdt::tuple >( new CartesianProductGenerator2( static_cast >(g1_), static_cast >(g2_))); } private: // No implementation - assignment is unsupported. void operator=(const CartesianProductHolder2& other); const Generator1 g1_; const Generator2 g2_; }; // class CartesianProductHolder2 template class CartesianProductHolder3 { public: CartesianProductHolder3(const Generator1& g1, const Generator2& g2, const Generator3& g3) : g1_(g1), g2_(g2), g3_(g3) {} template operator ParamGenerator< ::stdt::tuple >() const { return ParamGenerator< ::stdt::tuple >( new CartesianProductGenerator3( static_cast >(g1_), static_cast >(g2_), static_cast >(g3_))); } private: // No implementation - assignment is unsupported. void operator=(const CartesianProductHolder3& other); const Generator1 g1_; const Generator2 g2_; const Generator3 g3_; }; // class CartesianProductHolder3 template class CartesianProductHolder4 { public: CartesianProductHolder4(const Generator1& g1, const Generator2& g2, const Generator3& g3, const Generator4& g4) : g1_(g1), g2_(g2), g3_(g3), g4_(g4) {} template operator ParamGenerator< ::stdt::tuple >() const { return ParamGenerator< ::stdt::tuple >( new CartesianProductGenerator4( static_cast >(g1_), static_cast >(g2_), static_cast >(g3_), static_cast >(g4_))); } private: // No implementation - assignment is unsupported. void operator=(const CartesianProductHolder4& other); const Generator1 g1_; const Generator2 g2_; const Generator3 g3_; const Generator4 g4_; }; // class CartesianProductHolder4 template class CartesianProductHolder5 { public: CartesianProductHolder5(const Generator1& g1, const Generator2& g2, const Generator3& g3, const Generator4& g4, const Generator5& g5) : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5) {} template operator ParamGenerator< ::stdt::tuple >() const { return ParamGenerator< ::stdt::tuple >( new CartesianProductGenerator5( static_cast >(g1_), static_cast >(g2_), static_cast >(g3_), static_cast >(g4_), static_cast >(g5_))); } private: // No implementation - assignment is unsupported. void operator=(const CartesianProductHolder5& other); const Generator1 g1_; const Generator2 g2_; const Generator3 g3_; const Generator4 g4_; const Generator5 g5_; }; // class CartesianProductHolder5 template class CartesianProductHolder6 { public: CartesianProductHolder6(const Generator1& g1, const Generator2& g2, const Generator3& g3, const Generator4& g4, const Generator5& g5, const Generator6& g6) : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6) {} template operator ParamGenerator< ::stdt::tuple >() const { return ParamGenerator< ::stdt::tuple >( new CartesianProductGenerator6( static_cast >(g1_), static_cast >(g2_), static_cast >(g3_), static_cast >(g4_), static_cast >(g5_), static_cast >(g6_))); } private: // No implementation - assignment is unsupported. void operator=(const CartesianProductHolder6& other); const Generator1 g1_; const Generator2 g2_; const Generator3 g3_; const Generator4 g4_; const Generator5 g5_; const Generator6 g6_; }; // class CartesianProductHolder6 template class CartesianProductHolder7 { public: CartesianProductHolder7(const Generator1& g1, const Generator2& g2, const Generator3& g3, const Generator4& g4, const Generator5& g5, const Generator6& g6, const Generator7& g7) : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7) {} template operator ParamGenerator< ::stdt::tuple >() const { return ParamGenerator< ::stdt::tuple >( new CartesianProductGenerator7( static_cast >(g1_), static_cast >(g2_), static_cast >(g3_), static_cast >(g4_), static_cast >(g5_), static_cast >(g6_), static_cast >(g7_))); } private: // No implementation - assignment is unsupported. void operator=(const CartesianProductHolder7& other); const Generator1 g1_; const Generator2 g2_; const Generator3 g3_; const Generator4 g4_; const Generator5 g5_; const Generator6 g6_; const Generator7 g7_; }; // class CartesianProductHolder7 template class CartesianProductHolder8 { public: CartesianProductHolder8(const Generator1& g1, const Generator2& g2, const Generator3& g3, const Generator4& g4, const Generator5& g5, const Generator6& g6, const Generator7& g7, const Generator8& g8) : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7), g8_(g8) {} template operator ParamGenerator< ::stdt::tuple >() const { return ParamGenerator< ::stdt::tuple >( new CartesianProductGenerator8( static_cast >(g1_), static_cast >(g2_), static_cast >(g3_), static_cast >(g4_), static_cast >(g5_), static_cast >(g6_), static_cast >(g7_), static_cast >(g8_))); } private: // No implementation - assignment is unsupported. void operator=(const CartesianProductHolder8& other); const Generator1 g1_; const Generator2 g2_; const Generator3 g3_; const Generator4 g4_; const Generator5 g5_; const Generator6 g6_; const Generator7 g7_; const Generator8 g8_; }; // class CartesianProductHolder8 template class CartesianProductHolder9 { public: CartesianProductHolder9(const Generator1& g1, const Generator2& g2, const Generator3& g3, const Generator4& g4, const Generator5& g5, const Generator6& g6, const Generator7& g7, const Generator8& g8, const Generator9& g9) : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7), g8_(g8), g9_(g9) {} template operator ParamGenerator< ::stdt::tuple >() const { return ParamGenerator< ::stdt::tuple >( new CartesianProductGenerator9( static_cast >(g1_), static_cast >(g2_), static_cast >(g3_), static_cast >(g4_), static_cast >(g5_), static_cast >(g6_), static_cast >(g7_), static_cast >(g8_), static_cast >(g9_))); } private: // No implementation - assignment is unsupported. void operator=(const CartesianProductHolder9& other); const Generator1 g1_; const Generator2 g2_; const Generator3 g3_; const Generator4 g4_; const Generator5 g5_; const Generator6 g6_; const Generator7 g7_; const Generator8 g8_; const Generator9 g9_; }; // class CartesianProductHolder9 template class CartesianProductHolder10 { public: CartesianProductHolder10(const Generator1& g1, const Generator2& g2, const Generator3& g3, const Generator4& g4, const Generator5& g5, const Generator6& g6, const Generator7& g7, const Generator8& g8, const Generator9& g9, const Generator10& g10) : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7), g8_(g8), g9_(g9), g10_(g10) {} template operator ParamGenerator< ::stdt::tuple >() const { return ParamGenerator< ::stdt::tuple >( new CartesianProductGenerator10( static_cast >(g1_), static_cast >(g2_), static_cast >(g3_), static_cast >(g4_), static_cast >(g5_), static_cast >(g6_), static_cast >(g7_), static_cast >(g8_), static_cast >(g9_), static_cast >(g10_))); } private: // No implementation - assignment is unsupported. void operator=(const CartesianProductHolder10& other); const Generator1 g1_; const Generator2 g2_; const Generator3 g3_; const Generator4 g4_; const Generator5 g5_; const Generator6 g6_; const Generator7 g7_; const Generator8 g8_; const Generator9 g9_; const Generator10 g10_; }; // class CartesianProductHolder10 # endif // GTEST_HAS_COMBINE } // namespace internal } // namespace testing #endif // GTEST_HAS_PARAM_TEST #endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_GENERATED_H_ #if GTEST_HAS_PARAM_TEST namespace testing { // Functions producing parameter generators. // // Google Test uses these generators to produce parameters for value- // parameterized tests. When a parameterized test case is instantiated // with a particular generator, Google Test creates and runs tests // for each element in the sequence produced by the generator. // // In the following sample, tests from test case FooTest are instantiated // each three times with parameter values 3, 5, and 8: // // class FooTest : public TestWithParam { ... }; // // TEST_P(FooTest, TestThis) { // } // TEST_P(FooTest, TestThat) { // } // INSTANTIATE_TEST_CASE_P(TestSequence, FooTest, Values(3, 5, 8)); // // Range() returns generators providing sequences of values in a range. // // Synopsis: // Range(start, end) // - returns a generator producing a sequence of values {start, start+1, // start+2, ..., }. // Range(start, end, step) // - returns a generator producing a sequence of values {start, start+step, // start+step+step, ..., }. // Notes: // * The generated sequences never include end. For example, Range(1, 5) // returns a generator producing a sequence {1, 2, 3, 4}. Range(1, 9, 2) // returns a generator producing {1, 3, 5, 7}. // * start and end must have the same type. That type may be any integral or // floating-point type or a user defined type satisfying these conditions: // * It must be assignable (have operator=() defined). // * It must have operator+() (operator+(int-compatible type) for // two-operand version). // * It must have operator<() defined. // Elements in the resulting sequences will also have that type. // * Condition start < end must be satisfied in order for resulting sequences // to contain any elements. // template internal::ParamGenerator Range(T start, T end, IncrementT step) { return internal::ParamGenerator( new internal::RangeGenerator(start, end, step)); } template internal::ParamGenerator Range(T start, T end) { return Range(start, end, 1); } // ValuesIn() function allows generation of tests with parameters coming from // a container. // // Synopsis: // ValuesIn(const T (&array)[N]) // - returns a generator producing sequences with elements from // a C-style array. // ValuesIn(const Container& container) // - returns a generator producing sequences with elements from // an STL-style container. // ValuesIn(Iterator begin, Iterator end) // - returns a generator producing sequences with elements from // a range [begin, end) defined by a pair of STL-style iterators. These // iterators can also be plain C pointers. // // Please note that ValuesIn copies the values from the containers // passed in and keeps them to generate tests in RUN_ALL_TESTS(). // // Examples: // // This instantiates tests from test case StringTest // each with C-string values of "foo", "bar", and "baz": // // const char* strings[] = {"foo", "bar", "baz"}; // INSTANTIATE_TEST_CASE_P(StringSequence, SrtingTest, ValuesIn(strings)); // // This instantiates tests from test case StlStringTest // each with STL strings with values "a" and "b": // // ::std::vector< ::std::string> GetParameterStrings() { // ::std::vector< ::std::string> v; // v.push_back("a"); // v.push_back("b"); // return v; // } // // INSTANTIATE_TEST_CASE_P(CharSequence, // StlStringTest, // ValuesIn(GetParameterStrings())); // // // This will also instantiate tests from CharTest // each with parameter values 'a' and 'b': // // ::std::list GetParameterChars() { // ::std::list list; // list.push_back('a'); // list.push_back('b'); // return list; // } // ::std::list l = GetParameterChars(); // INSTANTIATE_TEST_CASE_P(CharSequence2, // CharTest, // ValuesIn(l.begin(), l.end())); // template internal::ParamGenerator< typename ::testing::internal::IteratorTraits::value_type> ValuesIn(ForwardIterator begin, ForwardIterator end) { typedef typename ::testing::internal::IteratorTraits ::value_type ParamType; return internal::ParamGenerator( new internal::ValuesInIteratorRangeGenerator(begin, end)); } template internal::ParamGenerator ValuesIn(const T(&array)[N]) { return ValuesIn(array, array + N); } template internal::ParamGenerator ValuesIn( const Container& container) { return ValuesIn(container.begin(), container.end()); } // Values() allows generating tests from explicitly specified list of // parameters. // // Synopsis: // Values(T v1, T v2, ..., T vN) // - returns a generator producing sequences with elements v1, v2, ..., vN. // // For example, this instantiates tests from test case BarTest each // with values "one", "two", and "three": // // INSTANTIATE_TEST_CASE_P(NumSequence, BarTest, Values("one", "two", "three")); // // This instantiates tests from test case BazTest each with values 1, 2, 3.5. // The exact type of values will depend on the type of parameter in BazTest. // // INSTANTIATE_TEST_CASE_P(FloatingNumbers, BazTest, Values(1, 2, 3.5)); // // Currently, Values() supports from 1 to 50 parameters. // template internal::ValueArray1 Values(T1 v1) { return internal::ValueArray1(v1); } template internal::ValueArray2 Values(T1 v1, T2 v2) { return internal::ValueArray2(v1, v2); } template internal::ValueArray3 Values(T1 v1, T2 v2, T3 v3) { return internal::ValueArray3(v1, v2, v3); } template internal::ValueArray4 Values(T1 v1, T2 v2, T3 v3, T4 v4) { return internal::ValueArray4(v1, v2, v3, v4); } template internal::ValueArray5 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5) { return internal::ValueArray5(v1, v2, v3, v4, v5); } template internal::ValueArray6 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6) { return internal::ValueArray6(v1, v2, v3, v4, v5, v6); } template internal::ValueArray7 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7) { return internal::ValueArray7(v1, v2, v3, v4, v5, v6, v7); } template internal::ValueArray8 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8) { return internal::ValueArray8(v1, v2, v3, v4, v5, v6, v7, v8); } template internal::ValueArray9 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9) { return internal::ValueArray9(v1, v2, v3, v4, v5, v6, v7, v8, v9); } template internal::ValueArray10 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10) { return internal::ValueArray10(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10); } template internal::ValueArray11 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11) { return internal::ValueArray11(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11); } template internal::ValueArray12 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12) { return internal::ValueArray12(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12); } template internal::ValueArray13 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13) { return internal::ValueArray13(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13); } template internal::ValueArray14 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14) { return internal::ValueArray14(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14); } template internal::ValueArray15 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15) { return internal::ValueArray15(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15); } template internal::ValueArray16 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16) { return internal::ValueArray16(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16); } template internal::ValueArray17 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17) { return internal::ValueArray17(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17); } template internal::ValueArray18 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18) { return internal::ValueArray18(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18); } template internal::ValueArray19 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19) { return internal::ValueArray19(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19); } template internal::ValueArray20 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20) { return internal::ValueArray20(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20); } template internal::ValueArray21 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21) { return internal::ValueArray21(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21); } template internal::ValueArray22 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22) { return internal::ValueArray22(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22); } template internal::ValueArray23 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23) { return internal::ValueArray23(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23); } template internal::ValueArray24 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24) { return internal::ValueArray24(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24); } template internal::ValueArray25 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25) { return internal::ValueArray25(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25); } template internal::ValueArray26 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26) { return internal::ValueArray26(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26); } template internal::ValueArray27 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27) { return internal::ValueArray27(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27); } template internal::ValueArray28 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28) { return internal::ValueArray28(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28); } template internal::ValueArray29 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29) { return internal::ValueArray29(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29); } template internal::ValueArray30 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30) { return internal::ValueArray30(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30); } template internal::ValueArray31 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31) { return internal::ValueArray31(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31); } template internal::ValueArray32 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32) { return internal::ValueArray32(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32); } template internal::ValueArray33 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33) { return internal::ValueArray33(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33); } template internal::ValueArray34 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34) { return internal::ValueArray34(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34); } template internal::ValueArray35 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35) { return internal::ValueArray35(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35); } template internal::ValueArray36 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36) { return internal::ValueArray36(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36); } template internal::ValueArray37 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37) { return internal::ValueArray37(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37); } template internal::ValueArray38 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38) { return internal::ValueArray38(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38); } template internal::ValueArray39 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39) { return internal::ValueArray39(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39); } template internal::ValueArray40 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40) { return internal::ValueArray40(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40); } template internal::ValueArray41 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41) { return internal::ValueArray41(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41); } template internal::ValueArray42 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, T42 v42) { return internal::ValueArray42(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42); } template internal::ValueArray43 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, T42 v42, T43 v43) { return internal::ValueArray43(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43); } template internal::ValueArray44 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, T42 v42, T43 v43, T44 v44) { return internal::ValueArray44(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44); } template internal::ValueArray45 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, T42 v42, T43 v43, T44 v44, T45 v45) { return internal::ValueArray45(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45); } template internal::ValueArray46 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, T42 v42, T43 v43, T44 v44, T45 v45, T46 v46) { return internal::ValueArray46(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46); } template internal::ValueArray47 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, T42 v42, T43 v43, T44 v44, T45 v45, T46 v46, T47 v47) { return internal::ValueArray47(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47); } template internal::ValueArray48 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, T42 v42, T43 v43, T44 v44, T45 v45, T46 v46, T47 v47, T48 v48) { return internal::ValueArray48(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48); } template internal::ValueArray49 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, T42 v42, T43 v43, T44 v44, T45 v45, T46 v46, T47 v47, T48 v48, T49 v49) { return internal::ValueArray49(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49); } template internal::ValueArray50 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, T42 v42, T43 v43, T44 v44, T45 v45, T46 v46, T47 v47, T48 v48, T49 v49, T50 v50) { return internal::ValueArray50(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50); } // Bool() allows generating tests with parameters in a set of (false, true). // // Synopsis: // Bool() // - returns a generator producing sequences with elements {false, true}. // // It is useful when testing code that depends on Boolean flags. Combinations // of multiple flags can be tested when several Bool()'s are combined using // Combine() function. // // In the following example all tests in the test case FlagDependentTest // will be instantiated twice with parameters false and true. // // class FlagDependentTest : public testing::TestWithParam { // virtual void SetUp() { // external_flag = GetParam(); // } // } // INSTANTIATE_TEST_CASE_P(BoolSequence, FlagDependentTest, Bool()); // inline internal::ParamGenerator Bool() { return Values(false, true); } # if GTEST_HAS_COMBINE // Combine() allows the user to combine two or more sequences to produce // values of a Cartesian product of those sequences' elements. // // Synopsis: // Combine(gen1, gen2, ..., genN) // - returns a generator producing sequences with elements coming from // the Cartesian product of elements from the sequences generated by // gen1, gen2, ..., genN. The sequence elements will have a type of // tuple where T1, T2, ..., TN are the types // of elements from sequences produces by gen1, gen2, ..., genN. // // Combine can have up to 10 arguments. This number is currently limited // by the maximum number of elements in the tuple implementation used by Google // Test. // // Example: // // This will instantiate tests in test case AnimalTest each one with // the parameter values tuple("cat", BLACK), tuple("cat", WHITE), // tuple("dog", BLACK), and tuple("dog", WHITE): // // enum Color { BLACK, GRAY, WHITE }; // class AnimalTest // : public testing::TestWithParam > {...}; // // TEST_P(AnimalTest, AnimalLooksNice) {...} // // INSTANTIATE_TEST_CASE_P(AnimalVariations, AnimalTest, // Combine(Values("cat", "dog"), // Values(BLACK, WHITE))); // // This will instantiate tests in FlagDependentTest with all variations of two // Boolean flags: // // class FlagDependentTest // : public testing::TestWithParam > { // virtual void SetUp() { // // Assigns external_flag_1 and external_flag_2 values from the tuple. // tie(external_flag_1, external_flag_2) = GetParam(); // } // }; // // TEST_P(FlagDependentTest, TestFeature1) { // // Test your code using external_flag_1 and external_flag_2 here. // } // INSTANTIATE_TEST_CASE_P(TwoBoolSequence, FlagDependentTest, // Combine(Bool(), Bool())); // template internal::CartesianProductHolder2 Combine( const Generator1& g1, const Generator2& g2) { return internal::CartesianProductHolder2( g1, g2); } template internal::CartesianProductHolder3 Combine( const Generator1& g1, const Generator2& g2, const Generator3& g3) { return internal::CartesianProductHolder3( g1, g2, g3); } template internal::CartesianProductHolder4 Combine( const Generator1& g1, const Generator2& g2, const Generator3& g3, const Generator4& g4) { return internal::CartesianProductHolder4( g1, g2, g3, g4); } template internal::CartesianProductHolder5 Combine( const Generator1& g1, const Generator2& g2, const Generator3& g3, const Generator4& g4, const Generator5& g5) { return internal::CartesianProductHolder5( g1, g2, g3, g4, g5); } template internal::CartesianProductHolder6 Combine( const Generator1& g1, const Generator2& g2, const Generator3& g3, const Generator4& g4, const Generator5& g5, const Generator6& g6) { return internal::CartesianProductHolder6( g1, g2, g3, g4, g5, g6); } template internal::CartesianProductHolder7 Combine( const Generator1& g1, const Generator2& g2, const Generator3& g3, const Generator4& g4, const Generator5& g5, const Generator6& g6, const Generator7& g7) { return internal::CartesianProductHolder7( g1, g2, g3, g4, g5, g6, g7); } template internal::CartesianProductHolder8 Combine( const Generator1& g1, const Generator2& g2, const Generator3& g3, const Generator4& g4, const Generator5& g5, const Generator6& g6, const Generator7& g7, const Generator8& g8) { return internal::CartesianProductHolder8( g1, g2, g3, g4, g5, g6, g7, g8); } template internal::CartesianProductHolder9 Combine( const Generator1& g1, const Generator2& g2, const Generator3& g3, const Generator4& g4, const Generator5& g5, const Generator6& g6, const Generator7& g7, const Generator8& g8, const Generator9& g9) { return internal::CartesianProductHolder9( g1, g2, g3, g4, g5, g6, g7, g8, g9); } template internal::CartesianProductHolder10 Combine( const Generator1& g1, const Generator2& g2, const Generator3& g3, const Generator4& g4, const Generator5& g5, const Generator6& g6, const Generator7& g7, const Generator8& g8, const Generator9& g9, const Generator10& g10) { return internal::CartesianProductHolder10( g1, g2, g3, g4, g5, g6, g7, g8, g9, g10); } # endif // GTEST_HAS_COMBINE # define TEST_P(test_case_name, test_name) \ class GTEST_TEST_CLASS_NAME_(test_case_name, test_name) \ : public test_case_name{ \ public: \ GTEST_TEST_CLASS_NAME_(test_case_name, test_name)() {} \ virtual void TestBody(); \ private: \ static int AddToRegistry() { \ ::testing::UnitTest::GetInstance()->parameterized_test_registry(). \ GetTestCasePatternHolder(\ #test_case_name, __FILE__, __LINE__)->AddTestPattern(\ #test_case_name, \ #test_name, \ new ::testing::internal::TestMetaFactory< \ GTEST_TEST_CLASS_NAME_(test_case_name, test_name)>()); \ return 0; \ } \ static int gtest_registering_dummy_; \ GTEST_DISALLOW_COPY_AND_ASSIGN_(\ GTEST_TEST_CLASS_NAME_(test_case_name, test_name)); \ }; \ int GTEST_TEST_CLASS_NAME_(test_case_name, \ test_name)::gtest_registering_dummy_ = \ GTEST_TEST_CLASS_NAME_(test_case_name, test_name)::AddToRegistry(); \ void GTEST_TEST_CLASS_NAME_(test_case_name, test_name)::TestBody() # define INSTANTIATE_TEST_CASE_P(prefix, test_case_name, generator) \ ::testing::internal::ParamGenerator \ gtest_##prefix##test_case_name##_EvalGenerator_() { return generator; } \ int gtest_##prefix##test_case_name##_dummy_ = \ ::testing::UnitTest::GetInstance()->parameterized_test_registry(). \ GetTestCasePatternHolder(\ #test_case_name, __FILE__, __LINE__)->AddTestCaseInstantiation(\ #prefix, \ >est_##prefix##test_case_name##_EvalGenerator_, \ __FILE__, __LINE__) } // namespace testing #endif // GTEST_HAS_PARAM_TEST #endif // GTEST_INCLUDE_GTEST_GTEST_PARAM_TEST_H_ // Copyright 2006, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // Author: wan@google.com (Zhanyong Wan) // // Google C++ Testing Framework definitions useful in production code. #ifndef GTEST_INCLUDE_GTEST_GTEST_PROD_H_ #define GTEST_INCLUDE_GTEST_GTEST_PROD_H_ // When you need to test the private or protected members of a class, // use the FRIEND_TEST macro to declare your tests as friends of the // class. For example: // // class MyClass { // private: // void MyMethod(); // FRIEND_TEST(MyClassTest, MyMethod); // }; // // class MyClassTest : public testing::Test { // // ... // }; // // TEST_F(MyClassTest, MyMethod) { // // Can call MyClass::MyMethod() here. // } #define FRIEND_TEST(test_case_name, test_name)\ friend class test_case_name##_##test_name##_Test #endif // GTEST_INCLUDE_GTEST_GTEST_PROD_H_ // Copyright 2008, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // Author: mheule@google.com (Markus Heule) // #ifndef GTEST_INCLUDE_GTEST_GTEST_TEST_PART_H_ #define GTEST_INCLUDE_GTEST_GTEST_TEST_PART_H_ #include #include namespace testing { // A copyable object representing the result of a test part (i.e. an // assertion or an explicit FAIL(), ADD_FAILURE(), or SUCCESS()). // // Don't inherit from TestPartResult as its destructor is not virtual. class GTEST_API_ TestPartResult { public: // The possible outcomes of a test part (i.e. an assertion or an // explicit SUCCEED(), FAIL(), or ADD_FAILURE()). enum Type { kSuccess, // Succeeded. kNonFatalFailure, // Failed but the test can continue. kFatalFailure // Failed and the test should be terminated. }; // C'tor. TestPartResult does NOT have a default constructor. // Always use this constructor (with parameters) to create a // TestPartResult object. TestPartResult(Type a_type, const char* a_file_name, int a_line_number, const char* a_message) : type_(a_type), file_name_(a_file_name == NULL ? "" : a_file_name), line_number_(a_line_number), summary_(ExtractSummary(a_message)), message_(a_message) { } // Gets the outcome of the test part. Type type() const { return type_; } // Gets the name of the source file where the test part took place, or // NULL if it's unknown. const char* file_name() const { return file_name_.empty() ? NULL : file_name_.c_str(); } // Gets the line in the source file where the test part took place, // or -1 if it's unknown. int line_number() const { return line_number_; } // Gets the summary of the failure message. const char* summary() const { return summary_.c_str(); } // Gets the message associated with the test part. const char* message() const { return message_.c_str(); } // Returns true iff the test part passed. bool passed() const { return type_ == kSuccess; } // Returns true iff the test part failed. bool failed() const { return type_ != kSuccess; } // Returns true iff the test part non-fatally failed. bool nonfatally_failed() const { return type_ == kNonFatalFailure; } // Returns true iff the test part fatally failed. bool fatally_failed() const { return type_ == kFatalFailure; } private: Type type_; // Gets the summary of the failure message by omitting the stack // trace in it. static std::string ExtractSummary(const char* message); // The name of the source file where the test part took place, or // "" if the source file is unknown. std::string file_name_; // The line in the source file where the test part took place, or -1 // if the line number is unknown. int line_number_; std::string summary_; // The test failure summary. std::string message_; // The test failure message. }; // Prints a TestPartResult object. std::ostream& operator<<(std::ostream& os, const TestPartResult& result); // An array of TestPartResult objects. // // Don't inherit from TestPartResultArray as its destructor is not // virtual. class GTEST_API_ TestPartResultArray { public: TestPartResultArray() {} // Appends the given TestPartResult to the array. void Append(const TestPartResult& result); // Returns the TestPartResult at the given index (0-based). const TestPartResult& GetTestPartResult(int index) const; // Returns the number of TestPartResult objects in the array. int size() const; private: std::vector array_; GTEST_DISALLOW_COPY_AND_ASSIGN_(TestPartResultArray); }; // This interface knows how to report a test part result. class TestPartResultReporterInterface { public: virtual ~TestPartResultReporterInterface() {} virtual void ReportTestPartResult(const TestPartResult& result) = 0; }; namespace internal { // This helper class is used by {ASSERT|EXPECT}_NO_FATAL_FAILURE to check if a // statement generates new fatal failures. To do so it registers itself as the // current test part result reporter. Besides checking if fatal failures were // reported, it only delegates the reporting to the former result reporter. // The original result reporter is restored in the destructor. // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. class GTEST_API_ HasNewFatalFailureHelper : public TestPartResultReporterInterface { public: HasNewFatalFailureHelper(); virtual ~HasNewFatalFailureHelper(); virtual void ReportTestPartResult(const TestPartResult& result); bool has_new_fatal_failure() const { return has_new_fatal_failure_; } private: bool has_new_fatal_failure_; TestPartResultReporterInterface* original_reporter_; GTEST_DISALLOW_COPY_AND_ASSIGN_(HasNewFatalFailureHelper); }; } // namespace internal } // namespace testing #endif // GTEST_INCLUDE_GTEST_GTEST_TEST_PART_H_ // Copyright 2008 Google Inc. // All Rights Reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // Author: wan@google.com (Zhanyong Wan) #ifndef GTEST_INCLUDE_GTEST_GTEST_TYPED_TEST_H_ #define GTEST_INCLUDE_GTEST_GTEST_TYPED_TEST_H_ // This header implements typed tests and type-parameterized tests. // Typed (aka type-driven) tests repeat the same test for types in a // list. You must know which types you want to test with when writing // typed tests. Here's how you do it: #if 0 // First, define a fixture class template. It should be parameterized // by a type. Remember to derive it from testing::Test. template class FooTest : public testing::Test { public: ... typedef std::list List; static T shared_; T value_; }; // Next, associate a list of types with the test case, which will be // repeated for each type in the list. The typedef is necessary for // the macro to parse correctly. typedef testing::Types MyTypes; TYPED_TEST_CASE(FooTest, MyTypes); // If the type list contains only one type, you can write that type // directly without Types<...>: // TYPED_TEST_CASE(FooTest, int); // Then, use TYPED_TEST() instead of TEST_F() to define as many typed // tests for this test case as you want. TYPED_TEST(FooTest, DoesBlah) { // Inside a test, refer to TypeParam to get the type parameter. // Since we are inside a derived class template, C++ requires use to // visit the members of FooTest via 'this'. TypeParam n = this->value_; // To visit static members of the fixture, add the TestFixture:: // prefix. n += TestFixture::shared_; // To refer to typedefs in the fixture, add the "typename // TestFixture::" prefix. typename TestFixture::List values; values.push_back(n); ... } TYPED_TEST(FooTest, HasPropertyA) { ... } #endif // 0 // Type-parameterized tests are abstract test patterns parameterized // by a type. Compared with typed tests, type-parameterized tests // allow you to define the test pattern without knowing what the type // parameters are. The defined pattern can be instantiated with // different types any number of times, in any number of translation // units. // // If you are designing an interface or concept, you can define a // suite of type-parameterized tests to verify properties that any // valid implementation of the interface/concept should have. Then, // each implementation can easily instantiate the test suite to verify // that it conforms to the requirements, without having to write // similar tests repeatedly. Here's an example: #if 0 // First, define a fixture class template. It should be parameterized // by a type. Remember to derive it from testing::Test. template class FooTest : public testing::Test { ... }; // Next, declare that you will define a type-parameterized test case // (the _P suffix is for "parameterized" or "pattern", whichever you // prefer): TYPED_TEST_CASE_P(FooTest); // Then, use TYPED_TEST_P() to define as many type-parameterized tests // for this type-parameterized test case as you want. TYPED_TEST_P(FooTest, DoesBlah) { // Inside a test, refer to TypeParam to get the type parameter. TypeParam n = 0; ... } TYPED_TEST_P(FooTest, HasPropertyA) { ... } // Now the tricky part: you need to register all test patterns before // you can instantiate them. The first argument of the macro is the // test case name; the rest are the names of the tests in this test // case. REGISTER_TYPED_TEST_CASE_P(FooTest, DoesBlah, HasPropertyA); // Finally, you are free to instantiate the pattern with the types you // want. If you put the above code in a header file, you can #include // it in multiple C++ source files and instantiate it multiple times. // // To distinguish different instances of the pattern, the first // argument to the INSTANTIATE_* macro is a prefix that will be added // to the actual test case name. Remember to pick unique prefixes for // different instances. typedef testing::Types MyTypes; INSTANTIATE_TYPED_TEST_CASE_P(My, FooTest, MyTypes); // If the type list contains only one type, you can write that type // directly without Types<...>: // INSTANTIATE_TYPED_TEST_CASE_P(My, FooTest, int); #endif // 0 // Implements typed tests. #if GTEST_HAS_TYPED_TEST // INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. // // Expands to the name of the typedef for the type parameters of the // given test case. # define GTEST_TYPE_PARAMS_(TestCaseName) gtest_type_params_##TestCaseName##_ // The 'Types' template argument below must have spaces around it // since some compilers may choke on '>>' when passing a template // instance (e.g. Types) # define TYPED_TEST_CASE(CaseName, Types) \ typedef ::testing::internal::TypeList< Types >::type \ GTEST_TYPE_PARAMS_(CaseName) # define TYPED_TEST(CaseName, TestName) \ template \ class GTEST_TEST_CLASS_NAME_(CaseName, TestName) \ : public CaseName{ \ private: \ typedef CaseName TestFixture; \ typedef gtest_TypeParam_ TypeParam; \ virtual void TestBody(); \ }; \ bool gtest_##CaseName##_##TestName##_registered_ GTEST_ATTRIBUTE_UNUSED_ = \ ::testing::internal::TypeParameterizedTest< \ CaseName, \ ::testing::internal::TemplateSel< \ GTEST_TEST_CLASS_NAME_(CaseName, TestName)>, \ GTEST_TYPE_PARAMS_(CaseName)>::Register(\ "", #CaseName, #TestName, 0); \ template \ void GTEST_TEST_CLASS_NAME_(CaseName, TestName)::TestBody() #endif // GTEST_HAS_TYPED_TEST // Implements type-parameterized tests. #if GTEST_HAS_TYPED_TEST_P // INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. // // Expands to the namespace name that the type-parameterized tests for // the given type-parameterized test case are defined in. The exact // name of the namespace is subject to change without notice. # define GTEST_CASE_NAMESPACE_(TestCaseName) \ gtest_case_##TestCaseName##_ // INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. // // Expands to the name of the variable used to remember the names of // the defined tests in the given test case. # define GTEST_TYPED_TEST_CASE_P_STATE_(TestCaseName) \ gtest_typed_test_case_p_state_##TestCaseName##_ // INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE DIRECTLY. // // Expands to the name of the variable used to remember the names of // the registered tests in the given test case. # define GTEST_REGISTERED_TEST_NAMES_(TestCaseName) \ gtest_registered_test_names_##TestCaseName##_ // The variables defined in the type-parameterized test macros are // static as typically these macros are used in a .h file that can be // #included in multiple translation units linked together. # define TYPED_TEST_CASE_P(CaseName) \ static ::testing::internal::TypedTestCasePState \ GTEST_TYPED_TEST_CASE_P_STATE_(CaseName) # define TYPED_TEST_P(CaseName, TestName) \ namespace GTEST_CASE_NAMESPACE_(CaseName) { \ template \ class TestName : public CaseName { \ private: \ typedef CaseName TestFixture; \ typedef gtest_TypeParam_ TypeParam; \ virtual void TestBody(); \ }; \ static bool gtest_##TestName##_defined_ GTEST_ATTRIBUTE_UNUSED_ = \ GTEST_TYPED_TEST_CASE_P_STATE_(CaseName).AddTestName(\ __FILE__, __LINE__, #CaseName, #TestName); \ } \ template \ void GTEST_CASE_NAMESPACE_(CaseName)::TestName::TestBody() # define REGISTER_TYPED_TEST_CASE_P(CaseName, ...) \ namespace GTEST_CASE_NAMESPACE_(CaseName) { \ typedef ::testing::internal::Templates<__VA_ARGS__>::type gtest_AllTests_; \ } \ static const char* const GTEST_REGISTERED_TEST_NAMES_(CaseName) = \ GTEST_TYPED_TEST_CASE_P_STATE_(CaseName).VerifyRegisteredTestNames(\ __FILE__, __LINE__, #__VA_ARGS__) // The 'Types' template argument below must have spaces around it // since some compilers may choke on '>>' when passing a template // instance (e.g. Types) # define INSTANTIATE_TYPED_TEST_CASE_P(Prefix, CaseName, Types) \ bool gtest_##Prefix##_##CaseName GTEST_ATTRIBUTE_UNUSED_ = \ ::testing::internal::TypeParameterizedTestCase::type>::Register(\ #Prefix, #CaseName, GTEST_REGISTERED_TEST_NAMES_(CaseName)) #endif // GTEST_HAS_TYPED_TEST_P #endif // GTEST_INCLUDE_GTEST_GTEST_TYPED_TEST_H_ // Depending on the platform, different string classes are available. // On Linux, in addition to ::std::string, Google also makes use of // class ::string, which has the same interface as ::std::string, but // has a different implementation. // // The user can define GTEST_HAS_GLOBAL_STRING to 1 to indicate that // ::string is available AND is a distinct type to ::std::string, or // define it to 0 to indicate otherwise. // // If the user's ::std::string and ::string are the same class due to // aliasing, he should define GTEST_HAS_GLOBAL_STRING to 0. // // If the user doesn't define GTEST_HAS_GLOBAL_STRING, it is defined // heuristically. namespace testing { // Declares the flags. // This flag temporary enables the disabled tests. GTEST_DECLARE_bool_(also_run_disabled_tests); // This flag brings the debugger on an assertion failure. GTEST_DECLARE_bool_(break_on_failure); // This flag controls whether Google Test catches all test-thrown exceptions // and logs them as failures. GTEST_DECLARE_bool_(catch_exceptions); // This flag enables using colors in terminal output. Available values are // "yes" to enable colors, "no" (disable colors), or "auto" (the default) // to let Google Test decide. GTEST_DECLARE_string_(color); // This flag sets up the filter to select by name using a glob pattern // the tests to run. If the filter is not given all tests are executed. GTEST_DECLARE_string_(filter); // This flag causes the Google Test to list tests. None of the tests listed // are actually run if the flag is provided. GTEST_DECLARE_bool_(list_tests); // This flag controls whether Google Test emits a detailed XML report to a file // in addition to its normal textual output. GTEST_DECLARE_string_(output); // This flags control whether Google Test prints the elapsed time for each // test. GTEST_DECLARE_bool_(print_time); // This flag specifies the random number seed. GTEST_DECLARE_int32_(random_seed); // This flag sets how many times the tests are repeated. The default value // is 1. If the value is -1 the tests are repeating forever. GTEST_DECLARE_int32_(repeat); // This flag controls whether Google Test includes Google Test internal // stack frames in failure stack traces. GTEST_DECLARE_bool_(show_internal_stack_frames); // When this flag is specified, tests' order is randomized on every iteration. GTEST_DECLARE_bool_(shuffle); // This flag specifies the maximum number of stack frames to be // printed in a failure message. GTEST_DECLARE_int32_(stack_trace_depth); // When this flag is specified, a failed assertion will throw an // exception if exceptions are enabled, or exit the program with a // non-zero code otherwise. GTEST_DECLARE_bool_(throw_on_failure); // When this flag is set with a "host:port" string, on supported // platforms test results are streamed to the specified port on // the specified host machine. GTEST_DECLARE_string_(stream_result_to); // The upper limit for valid stack trace depths. const int kMaxStackTraceDepth = 100; namespace internal { class AssertHelper; class DefaultGlobalTestPartResultReporter; class ExecDeathTest; class NoExecDeathTest; class FinalSuccessChecker; class GTestFlagSaver; class StreamingListenerTest; class TestResultAccessor; class TestEventListenersAccessor; class TestEventRepeater; class UnitTestRecordPropertyTestHelper; class WindowsDeathTest; class UnitTestImpl* GetUnitTestImpl(); void ReportFailureInUnknownLocation(TestPartResult::Type result_type, const std::string& message); } // namespace internal // The friend relationship of some of these classes is cyclic. // If we don't forward declare them the compiler might confuse the classes // in friendship clauses with same named classes on the scope. class Test; class TestCase; class TestInfo; class UnitTest; // A class for indicating whether an assertion was successful. When // the assertion wasn't successful, the AssertionResult object // remembers a non-empty message that describes how it failed. // // To create an instance of this class, use one of the factory functions // (AssertionSuccess() and AssertionFailure()). // // This class is useful for two purposes: // 1. Defining predicate functions to be used with Boolean test assertions // EXPECT_TRUE/EXPECT_FALSE and their ASSERT_ counterparts // 2. Defining predicate-format functions to be // used with predicate assertions (ASSERT_PRED_FORMAT*, etc). // // For example, if you define IsEven predicate: // // testing::AssertionResult IsEven(int n) { // if ((n % 2) == 0) // return testing::AssertionSuccess(); // else // return testing::AssertionFailure() << n << " is odd"; // } // // Then the failed expectation EXPECT_TRUE(IsEven(Fib(5))) // will print the message // // Value of: IsEven(Fib(5)) // Actual: false (5 is odd) // Expected: true // // instead of a more opaque // // Value of: IsEven(Fib(5)) // Actual: false // Expected: true // // in case IsEven is a simple Boolean predicate. // // If you expect your predicate to be reused and want to support informative // messages in EXPECT_FALSE and ASSERT_FALSE (negative assertions show up // about half as often as positive ones in our tests), supply messages for // both success and failure cases: // // testing::AssertionResult IsEven(int n) { // if ((n % 2) == 0) // return testing::AssertionSuccess() << n << " is even"; // else // return testing::AssertionFailure() << n << " is odd"; // } // // Then a statement EXPECT_FALSE(IsEven(Fib(6))) will print // // Value of: IsEven(Fib(6)) // Actual: true (8 is even) // Expected: false // // NB: Predicates that support negative Boolean assertions have reduced // performance in positive ones so be careful not to use them in tests // that have lots (tens of thousands) of positive Boolean assertions. // // To use this class with EXPECT_PRED_FORMAT assertions such as: // // // Verifies that Foo() returns an even number. // EXPECT_PRED_FORMAT1(IsEven, Foo()); // // you need to define: // // testing::AssertionResult IsEven(const char* expr, int n) { // if ((n % 2) == 0) // return testing::AssertionSuccess(); // else // return testing::AssertionFailure() // << "Expected: " << expr << " is even\n Actual: it's " << n; // } // // If Foo() returns 5, you will see the following message: // // Expected: Foo() is even // Actual: it's 5 // class GTEST_API_ AssertionResult { public: // Copy constructor. // Used in EXPECT_TRUE/FALSE(assertion_result). AssertionResult(const AssertionResult& other); // Used in the EXPECT_TRUE/FALSE(bool_expression). explicit AssertionResult(bool success) : success_(success) {} // Returns true iff the assertion succeeded. operator bool() const { return success_; } // NOLINT // Returns the assertion's negation. Used with EXPECT/ASSERT_FALSE. AssertionResult operator!() const; // Returns the text streamed into this AssertionResult. Test assertions // use it when they fail (i.e., the predicate's outcome doesn't match the // assertion's expectation). When nothing has been streamed into the // object, returns an empty string. const char* message() const { return message_.get() != NULL ? message_->c_str() : ""; } // TODO(vladl@google.com): Remove this after making sure no clients use it. // Deprecated; please use message() instead. const char* failure_message() const { return message(); } // Streams a custom failure message into this object. template AssertionResult& operator<<(const T& value) { AppendMessage(Message() << value); return *this; } // Allows streaming basic output manipulators such as endl or flush into // this object. AssertionResult& operator<<( ::std::ostream& (*basic_manipulator)(::std::ostream& stream)) { AppendMessage(Message() << basic_manipulator); return *this; } private: // Appends the contents of message to message_. void AppendMessage(const Message& a_message) { if (message_.get() == NULL) message_.reset(new ::std::string); message_->append(a_message.GetString().c_str()); } // Stores result of the assertion predicate. bool success_; // Stores the message describing the condition in case the expectation // construct is not satisfied with the predicate's outcome. // Referenced via a pointer to avoid taking too much stack frame space // with test assertions. internal::scoped_ptr< ::std::string> message_; GTEST_DISALLOW_ASSIGN_(AssertionResult); }; // Makes a successful assertion result. GTEST_API_ AssertionResult AssertionSuccess(); // Makes a failed assertion result. GTEST_API_ AssertionResult AssertionFailure(); // Makes a failed assertion result with the given failure message. // Deprecated; use AssertionFailure() << msg. GTEST_API_ AssertionResult AssertionFailure(const Message& msg); // The abstract class that all tests inherit from. // // In Google Test, a unit test program contains one or many TestCases, and // each TestCase contains one or many Tests. // // When you define a test using the TEST macro, you don't need to // explicitly derive from Test - the TEST macro automatically does // this for you. // // The only time you derive from Test is when defining a test fixture // to be used a TEST_F. For example: // // class FooTest : public testing::Test { // protected: // virtual void SetUp() { ... } // virtual void TearDown() { ... } // ... // }; // // TEST_F(FooTest, Bar) { ... } // TEST_F(FooTest, Baz) { ... } // // Test is not copyable. class GTEST_API_ Test { public: friend class TestInfo; // Defines types for pointers to functions that set up and tear down // a test case. typedef internal::SetUpTestCaseFunc SetUpTestCaseFunc; typedef internal::TearDownTestCaseFunc TearDownTestCaseFunc; // The d'tor is virtual as we intend to inherit from Test. virtual ~Test(); // Sets up the stuff shared by all tests in this test case. // // Google Test will call Foo::SetUpTestCase() before running the first // test in test case Foo. Hence a sub-class can define its own // SetUpTestCase() method to shadow the one defined in the super // class. static void SetUpTestCase() {} // Tears down the stuff shared by all tests in this test case. // // Google Test will call Foo::TearDownTestCase() after running the last // test in test case Foo. Hence a sub-class can define its own // TearDownTestCase() method to shadow the one defined in the super // class. static void TearDownTestCase() {} // Returns true iff the current test has a fatal failure. static bool HasFatalFailure(); // Returns true iff the current test has a non-fatal failure. static bool HasNonfatalFailure(); // Returns true iff the current test has a (either fatal or // non-fatal) failure. static bool HasFailure() { return HasFatalFailure() || HasNonfatalFailure(); } // Logs a property for the current test, test case, or for the entire // invocation of the test program when used outside of the context of a // test case. Only the last value for a given key is remembered. These // are public static so they can be called from utility functions that are // not members of the test fixture. Calls to RecordProperty made during // lifespan of the test (from the moment its constructor starts to the // moment its destructor finishes) will be output in XML as attributes of // the element. Properties recorded from fixture's // SetUpTestCase or TearDownTestCase are logged as attributes of the // corresponding element. Calls to RecordProperty made in the // global context (before or after invocation of RUN_ALL_TESTS and from // SetUp/TearDown method of Environment objects registered with Google // Test) will be output as attributes of the element. static void RecordProperty(const std::string& key, const std::string& value); static void RecordProperty(const std::string& key, int value); protected: // Creates a Test object. Test(); // Sets up the test fixture. virtual void SetUp(); // Tears down the test fixture. virtual void TearDown(); private: // Returns true iff the current test has the same fixture class as // the first test in the current test case. static bool HasSameFixtureClass(); // Runs the test after the test fixture has been set up. // // A sub-class must implement this to define the test logic. // // DO NOT OVERRIDE THIS FUNCTION DIRECTLY IN A USER PROGRAM. // Instead, use the TEST or TEST_F macro. virtual void TestBody() = 0; // Sets up, executes, and tears down the test. void Run(); // Deletes self. We deliberately pick an unusual name for this // internal method to avoid clashing with names used in user TESTs. void DeleteSelf_() { delete this; } // Uses a GTestFlagSaver to save and restore all Google Test flags. const internal::GTestFlagSaver* const gtest_flag_saver_; // Often a user mis-spells SetUp() as Setup() and spends a long time // wondering why it is never called by Google Test. The declaration of // the following method is solely for catching such an error at // compile time: // // - The return type is deliberately chosen to be not void, so it // will be a conflict if a user declares void Setup() in his test // fixture. // // - This method is private, so it will be another compiler error // if a user calls it from his test fixture. // // DO NOT OVERRIDE THIS FUNCTION. // // If you see an error about overriding the following function or // about it being private, you have mis-spelled SetUp() as Setup(). struct Setup_should_be_spelled_SetUp {}; virtual Setup_should_be_spelled_SetUp* Setup() { return NULL; } // We disallow copying Tests. GTEST_DISALLOW_COPY_AND_ASSIGN_(Test); }; typedef internal::TimeInMillis TimeInMillis; // A copyable object representing a user specified test property which can be // output as a key/value string pair. // // Don't inherit from TestProperty as its destructor is not virtual. class TestProperty { public: // C'tor. TestProperty does NOT have a default constructor. // Always use this constructor (with parameters) to create a // TestProperty object. TestProperty(const std::string& a_key, const std::string& a_value) : key_(a_key), value_(a_value) { } // Gets the user supplied key. const char* key() const { return key_.c_str(); } // Gets the user supplied value. const char* value() const { return value_.c_str(); } // Sets a new value, overriding the one supplied in the constructor. void SetValue(const std::string& new_value) { value_ = new_value; } private: // The key supplied by the user. std::string key_; // The value supplied by the user. std::string value_; }; // The result of a single Test. This includes a list of // TestPartResults, a list of TestProperties, a count of how many // death tests there are in the Test, and how much time it took to run // the Test. // // TestResult is not copyable. class GTEST_API_ TestResult { public: // Creates an empty TestResult. TestResult(); // D'tor. Do not inherit from TestResult. ~TestResult(); // Gets the number of all test parts. This is the sum of the number // of successful test parts and the number of failed test parts. int total_part_count() const; // Returns the number of the test properties. int test_property_count() const; // Returns true iff the test passed (i.e. no test part failed). bool Passed() const { return !Failed(); } // Returns true iff the test failed. bool Failed() const; // Returns true iff the test fatally failed. bool HasFatalFailure() const; // Returns true iff the test has a non-fatal failure. bool HasNonfatalFailure() const; // Returns the elapsed time, in milliseconds. TimeInMillis elapsed_time() const { return elapsed_time_; } // Returns the i-th test part result among all the results. i can range // from 0 to test_property_count() - 1. If i is not in that range, aborts // the program. const TestPartResult& GetTestPartResult(int i) const; // Returns the i-th test property. i can range from 0 to // test_property_count() - 1. If i is not in that range, aborts the // program. const TestProperty& GetTestProperty(int i) const; private: friend class TestInfo; friend class TestCase; friend class UnitTest; friend class internal::DefaultGlobalTestPartResultReporter; friend class internal::ExecDeathTest; friend class internal::TestResultAccessor; friend class internal::UnitTestImpl; friend class internal::WindowsDeathTest; // Gets the vector of TestPartResults. const std::vector& test_part_results() const { return test_part_results_; } // Gets the vector of TestProperties. const std::vector& test_properties() const { return test_properties_; } // Sets the elapsed time. void set_elapsed_time(TimeInMillis elapsed) { elapsed_time_ = elapsed; } // Adds a test property to the list. The property is validated and may add // a non-fatal failure if invalid (e.g., if it conflicts with reserved // key names). If a property is already recorded for the same key, the // value will be updated, rather than storing multiple values for the same // key. xml_element specifies the element for which the property is being // recorded and is used for validation. void RecordProperty(const std::string& xml_element, const TestProperty& test_property); // Adds a failure if the key is a reserved attribute of Google Test // testcase tags. Returns true if the property is valid. // TODO(russr): Validate attribute names are legal and human readable. static bool ValidateTestProperty(const std::string& xml_element, const TestProperty& test_property); // Adds a test part result to the list. void AddTestPartResult(const TestPartResult& test_part_result); // Returns the death test count. int death_test_count() const { return death_test_count_; } // Increments the death test count, returning the new count. int increment_death_test_count() { return ++death_test_count_; } // Clears the test part results. void ClearTestPartResults(); // Clears the object. void Clear(); // Protects mutable state of the property vector and of owned // properties, whose values may be updated. internal::Mutex test_properites_mutex_; // The vector of TestPartResults std::vector test_part_results_; // The vector of TestProperties std::vector test_properties_; // Running count of death tests. int death_test_count_; // The elapsed time, in milliseconds. TimeInMillis elapsed_time_; // We disallow copying TestResult. GTEST_DISALLOW_COPY_AND_ASSIGN_(TestResult); }; // class TestResult // A TestInfo object stores the following information about a test: // // Test case name // Test name // Whether the test should be run // A function pointer that creates the test object when invoked // Test result // // The constructor of TestInfo registers itself with the UnitTest // singleton such that the RUN_ALL_TESTS() macro knows which tests to // run. class GTEST_API_ TestInfo { public: // Destructs a TestInfo object. This function is not virtual, so // don't inherit from TestInfo. ~TestInfo(); // Returns the test case name. const char* test_case_name() const { return test_case_name_.c_str(); } // Returns the test name. const char* name() const { return name_.c_str(); } // Returns the name of the parameter type, or NULL if this is not a typed // or a type-parameterized test. const char* type_param() const { if (type_param_.get() != NULL) return type_param_->c_str(); return NULL; } // Returns the text representation of the value parameter, or NULL if this // is not a value-parameterized test. const char* value_param() const { if (value_param_.get() != NULL) return value_param_->c_str(); return NULL; } // Returns true if this test should run, that is if the test is not // disabled (or it is disabled but the also_run_disabled_tests flag has // been specified) and its full name matches the user-specified filter. // // Google Test allows the user to filter the tests by their full names. // The full name of a test Bar in test case Foo is defined as // "Foo.Bar". Only the tests that match the filter will run. // // A filter is a colon-separated list of glob (not regex) patterns, // optionally followed by a '-' and a colon-separated list of // negative patterns (tests to exclude). A test is run if it // matches one of the positive patterns and does not match any of // the negative patterns. // // For example, *A*:Foo.* is a filter that matches any string that // contains the character 'A' or starts with "Foo.". bool should_run() const { return should_run_; } // Returns true iff this test will appear in the XML report. bool is_reportable() const { // For now, the XML report includes all tests matching the filter. // In the future, we may trim tests that are excluded because of // sharding. return matches_filter_; } // Returns the result of the test. const TestResult* result() const { return &result_; } private: #if GTEST_HAS_DEATH_TEST friend class internal::DefaultDeathTestFactory; #endif // GTEST_HAS_DEATH_TEST friend class Test; friend class TestCase; friend class internal::UnitTestImpl; friend class internal::StreamingListenerTest; friend TestInfo* internal::MakeAndRegisterTestInfo( const char* test_case_name, const char* name, const char* type_param, const char* value_param, internal::TypeId fixture_class_id, Test::SetUpTestCaseFunc set_up_tc, Test::TearDownTestCaseFunc tear_down_tc, internal::TestFactoryBase* factory); // Constructs a TestInfo object. The newly constructed instance assumes // ownership of the factory object. TestInfo(const std::string& test_case_name, const std::string& name, const char* a_type_param, // NULL if not a type-parameterized test const char* a_value_param, // NULL if not a value-parameterized test internal::TypeId fixture_class_id, internal::TestFactoryBase* factory); // Increments the number of death tests encountered in this test so // far. int increment_death_test_count() { return result_.increment_death_test_count(); } // Creates the test object, runs it, records its result, and then // deletes it. void Run(); static void ClearTestResult(TestInfo* test_info) { test_info->result_.Clear(); } // These fields are immutable properties of the test. const std::string test_case_name_; // Test case name const std::string name_; // Test name // Name of the parameter type, or NULL if this is not a typed or a // type-parameterized test. const internal::scoped_ptr type_param_; // Text representation of the value parameter, or NULL if this is not a // value-parameterized test. const internal::scoped_ptr value_param_; const internal::TypeId fixture_class_id_; // ID of the test fixture class bool should_run_; // True iff this test should run bool is_disabled_; // True iff this test is disabled bool matches_filter_; // True if this test matches the // user-specified filter. internal::TestFactoryBase* const factory_; // The factory that creates // the test object // This field is mutable and needs to be reset before running the // test for the second time. TestResult result_; GTEST_DISALLOW_COPY_AND_ASSIGN_(TestInfo); }; // A test case, which consists of a vector of TestInfos. // // TestCase is not copyable. class GTEST_API_ TestCase { public: // Creates a TestCase with the given name. // // TestCase does NOT have a default constructor. Always use this // constructor to create a TestCase object. // // Arguments: // // name: name of the test case // a_type_param: the name of the test's type parameter, or NULL if // this is not a type-parameterized test. // set_up_tc: pointer to the function that sets up the test case // tear_down_tc: pointer to the function that tears down the test case TestCase(const char* name, const char* a_type_param, Test::SetUpTestCaseFunc set_up_tc, Test::TearDownTestCaseFunc tear_down_tc); // Destructor of TestCase. virtual ~TestCase(); // Gets the name of the TestCase. const char* name() const { return name_.c_str(); } // Returns the name of the parameter type, or NULL if this is not a // type-parameterized test case. const char* type_param() const { if (type_param_.get() != NULL) return type_param_->c_str(); return NULL; } // Returns true if any test in this test case should run. bool should_run() const { return should_run_; } // Gets the number of successful tests in this test case. int successful_test_count() const; // Gets the number of failed tests in this test case. int failed_test_count() const; // Gets the number of disabled tests that will be reported in the XML report. int reportable_disabled_test_count() const; // Gets the number of disabled tests in this test case. int disabled_test_count() const; // Gets the number of tests to be printed in the XML report. int reportable_test_count() const; // Get the number of tests in this test case that should run. int test_to_run_count() const; // Gets the number of all tests in this test case. int total_test_count() const; // Returns true iff the test case passed. bool Passed() const { return !Failed(); } // Returns true iff the test case failed. bool Failed() const { return failed_test_count() > 0; } // Returns the elapsed time, in milliseconds. TimeInMillis elapsed_time() const { return elapsed_time_; } // Returns the i-th test among all the tests. i can range from 0 to // total_test_count() - 1. If i is not in that range, returns NULL. const TestInfo* GetTestInfo(int i) const; // Returns the TestResult that holds test properties recorded during // execution of SetUpTestCase and TearDownTestCase. const TestResult& ad_hoc_test_result() const { return ad_hoc_test_result_; } private: friend class Test; friend class internal::UnitTestImpl; // Gets the (mutable) vector of TestInfos in this TestCase. std::vector& test_info_list() { return test_info_list_; } // Gets the (immutable) vector of TestInfos in this TestCase. const std::vector& test_info_list() const { return test_info_list_; } // Returns the i-th test among all the tests. i can range from 0 to // total_test_count() - 1. If i is not in that range, returns NULL. TestInfo* GetMutableTestInfo(int i); // Sets the should_run member. void set_should_run(bool should) { should_run_ = should; } // Adds a TestInfo to this test case. Will delete the TestInfo upon // destruction of the TestCase object. void AddTestInfo(TestInfo * test_info); // Clears the results of all tests in this test case. void ClearResult(); // Clears the results of all tests in the given test case. static void ClearTestCaseResult(TestCase* test_case) { test_case->ClearResult(); } // Runs every test in this TestCase. void Run(); // Runs SetUpTestCase() for this TestCase. This wrapper is needed // for catching exceptions thrown from SetUpTestCase(). void RunSetUpTestCase() { (*set_up_tc_)(); } // Runs TearDownTestCase() for this TestCase. This wrapper is // needed for catching exceptions thrown from TearDownTestCase(). void RunTearDownTestCase() { (*tear_down_tc_)(); } // Returns true iff test passed. static bool TestPassed(const TestInfo* test_info) { return test_info->should_run() && test_info->result()->Passed(); } // Returns true iff test failed. static bool TestFailed(const TestInfo* test_info) { return test_info->should_run() && test_info->result()->Failed(); } // Returns true iff the test is disabled and will be reported in the XML // report. static bool TestReportableDisabled(const TestInfo* test_info) { return test_info->is_reportable() && test_info->is_disabled_; } // Returns true iff test is disabled. static bool TestDisabled(const TestInfo* test_info) { return test_info->is_disabled_; } // Returns true iff this test will appear in the XML report. static bool TestReportable(const TestInfo* test_info) { return test_info->is_reportable(); } // Returns true if the given test should run. static bool ShouldRunTest(const TestInfo* test_info) { return test_info->should_run(); } // Shuffles the tests in this test case. void ShuffleTests(internal::Random* random); // Restores the test order to before the first shuffle. void UnshuffleTests(); // Name of the test case. std::string name_; // Name of the parameter type, or NULL if this is not a typed or a // type-parameterized test. const internal::scoped_ptr type_param_; // The vector of TestInfos in their original order. It owns the // elements in the vector. std::vector test_info_list_; // Provides a level of indirection for the test list to allow easy // shuffling and restoring the test order. The i-th element in this // vector is the index of the i-th test in the shuffled test list. std::vector test_indices_; // Pointer to the function that sets up the test case. Test::SetUpTestCaseFunc set_up_tc_; // Pointer to the function that tears down the test case. Test::TearDownTestCaseFunc tear_down_tc_; // True iff any test in this test case should run. bool should_run_; // Elapsed time, in milliseconds. TimeInMillis elapsed_time_; // Holds test properties recorded during execution of SetUpTestCase and // TearDownTestCase. TestResult ad_hoc_test_result_; // We disallow copying TestCases. GTEST_DISALLOW_COPY_AND_ASSIGN_(TestCase); }; // An Environment object is capable of setting up and tearing down an // environment. The user should subclass this to define his own // environment(s). // // An Environment object does the set-up and tear-down in virtual // methods SetUp() and TearDown() instead of the constructor and the // destructor, as: // // 1. You cannot safely throw from a destructor. This is a problem // as in some cases Google Test is used where exceptions are enabled, and // we may want to implement ASSERT_* using exceptions where they are // available. // 2. You cannot use ASSERT_* directly in a constructor or // destructor. class Environment { public: // The d'tor is virtual as we need to subclass Environment. virtual ~Environment() {} // Override this to define how to set up the environment. virtual void SetUp() {} // Override this to define how to tear down the environment. virtual void TearDown() {} private: // If you see an error about overriding the following function or // about it being private, you have mis-spelled SetUp() as Setup(). struct Setup_should_be_spelled_SetUp {}; virtual Setup_should_be_spelled_SetUp* Setup() { return NULL; } }; // The interface for tracing execution of tests. The methods are organized in // the order the corresponding events are fired. class TestEventListener { public: virtual ~TestEventListener() {} // Fired before any test activity starts. virtual void OnTestProgramStart(const UnitTest& unit_test) = 0; // Fired before each iteration of tests starts. There may be more than // one iteration if GTEST_FLAG(repeat) is set. iteration is the iteration // index, starting from 0. virtual void OnTestIterationStart(const UnitTest& unit_test, int iteration) = 0; // Fired before environment set-up for each iteration of tests starts. virtual void OnEnvironmentsSetUpStart(const UnitTest& unit_test) = 0; // Fired after environment set-up for each iteration of tests ends. virtual void OnEnvironmentsSetUpEnd(const UnitTest& unit_test) = 0; // Fired before the test case starts. virtual void OnTestCaseStart(const TestCase& test_case) = 0; // Fired before the test starts. virtual void OnTestStart(const TestInfo& test_info) = 0; // Fired after a failed assertion or a SUCCEED() invocation. virtual void OnTestPartResult(const TestPartResult& test_part_result) = 0; // Fired after the test ends. virtual void OnTestEnd(const TestInfo& test_info) = 0; // Fired after the test case ends. virtual void OnTestCaseEnd(const TestCase& test_case) = 0; // Fired before environment tear-down for each iteration of tests starts. virtual void OnEnvironmentsTearDownStart(const UnitTest& unit_test) = 0; // Fired after environment tear-down for each iteration of tests ends. virtual void OnEnvironmentsTearDownEnd(const UnitTest& unit_test) = 0; // Fired after each iteration of tests finishes. virtual void OnTestIterationEnd(const UnitTest& unit_test, int iteration) = 0; // Fired after all test activities have ended. virtual void OnTestProgramEnd(const UnitTest& unit_test) = 0; }; // The convenience class for users who need to override just one or two // methods and are not concerned that a possible change to a signature of // the methods they override will not be caught during the build. For // comments about each method please see the definition of TestEventListener // above. class EmptyTestEventListener : public TestEventListener { public: virtual void OnTestProgramStart(const UnitTest& /*unit_test*/) {} virtual void OnTestIterationStart(const UnitTest& /*unit_test*/, int /*iteration*/) {} virtual void OnEnvironmentsSetUpStart(const UnitTest& /*unit_test*/) {} virtual void OnEnvironmentsSetUpEnd(const UnitTest& /*unit_test*/) {} virtual void OnTestCaseStart(const TestCase& /*test_case*/) {} virtual void OnTestStart(const TestInfo& /*test_info*/) {} virtual void OnTestPartResult(const TestPartResult& /*test_part_result*/) {} virtual void OnTestEnd(const TestInfo& /*test_info*/) {} virtual void OnTestCaseEnd(const TestCase& /*test_case*/) {} virtual void OnEnvironmentsTearDownStart(const UnitTest& /*unit_test*/) {} virtual void OnEnvironmentsTearDownEnd(const UnitTest& /*unit_test*/) {} virtual void OnTestIterationEnd(const UnitTest& /*unit_test*/, int /*iteration*/) {} virtual void OnTestProgramEnd(const UnitTest& /*unit_test*/) {} }; // TestEventListeners lets users add listeners to track events in Google Test. class GTEST_API_ TestEventListeners { public: TestEventListeners(); ~TestEventListeners(); // Appends an event listener to the end of the list. Google Test assumes // the ownership of the listener (i.e. it will delete the listener when // the test program finishes). void Append(TestEventListener* listener); // Removes the given event listener from the list and returns it. It then // becomes the caller's responsibility to delete the listener. Returns // NULL if the listener is not found in the list. TestEventListener* Release(TestEventListener* listener); // Returns the standard listener responsible for the default console // output. Can be removed from the listeners list to shut down default // console output. Note that removing this object from the listener list // with Release transfers its ownership to the caller and makes this // function return NULL the next time. TestEventListener* default_result_printer() const { return default_result_printer_; } // Returns the standard listener responsible for the default XML output // controlled by the --gtest_output=xml flag. Can be removed from the // listeners list by users who want to shut down the default XML output // controlled by this flag and substitute it with custom one. Note that // removing this object from the listener list with Release transfers its // ownership to the caller and makes this function return NULL the next // time. TestEventListener* default_xml_generator() const { return default_xml_generator_; } private: friend class TestCase; friend class TestInfo; friend class internal::DefaultGlobalTestPartResultReporter; friend class internal::NoExecDeathTest; friend class internal::TestEventListenersAccessor; friend class internal::UnitTestImpl; // Returns repeater that broadcasts the TestEventListener events to all // subscribers. TestEventListener* repeater(); // Sets the default_result_printer attribute to the provided listener. // The listener is also added to the listener list and previous // default_result_printer is removed from it and deleted. The listener can // also be NULL in which case it will not be added to the list. Does // nothing if the previous and the current listener objects are the same. void SetDefaultResultPrinter(TestEventListener* listener); // Sets the default_xml_generator attribute to the provided listener. The // listener is also added to the listener list and previous // default_xml_generator is removed from it and deleted. The listener can // also be NULL in which case it will not be added to the list. Does // nothing if the previous and the current listener objects are the same. void SetDefaultXmlGenerator(TestEventListener* listener); // Controls whether events will be forwarded by the repeater to the // listeners in the list. bool EventForwardingEnabled() const; void SuppressEventForwarding(); // The actual list of listeners. internal::TestEventRepeater* repeater_; // Listener responsible for the standard result output. TestEventListener* default_result_printer_; // Listener responsible for the creation of the XML output file. TestEventListener* default_xml_generator_; // We disallow copying TestEventListeners. GTEST_DISALLOW_COPY_AND_ASSIGN_(TestEventListeners); }; // A UnitTest consists of a vector of TestCases. // // This is a singleton class. The only instance of UnitTest is // created when UnitTest::GetInstance() is first called. This // instance is never deleted. // // UnitTest is not copyable. // // This class is thread-safe as long as the methods are called // according to their specification. class GTEST_API_ UnitTest { public: // Gets the singleton UnitTest object. The first time this method // is called, a UnitTest object is constructed and returned. // Consecutive calls will return the same object. static UnitTest* GetInstance(); // Runs all tests in this UnitTest object and prints the result. // Returns 0 if successful, or 1 otherwise. // // This method can only be called from the main thread. // // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. int Run() GTEST_MUST_USE_RESULT_; // Returns the working directory when the first TEST() or TEST_F() // was executed. The UnitTest object owns the string. const char* original_working_dir() const; // Returns the TestCase object for the test that's currently running, // or NULL if no test is running. const TestCase* current_test_case() const GTEST_LOCK_EXCLUDED_(mutex_); // Returns the TestInfo object for the test that's currently running, // or NULL if no test is running. const TestInfo* current_test_info() const GTEST_LOCK_EXCLUDED_(mutex_); // Returns the random seed used at the start of the current test run. int random_seed() const; #if GTEST_HAS_PARAM_TEST // Returns the ParameterizedTestCaseRegistry object used to keep track of // value-parameterized tests and instantiate and register them. // // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. internal::ParameterizedTestCaseRegistry& parameterized_test_registry() GTEST_LOCK_EXCLUDED_(mutex_); #endif // GTEST_HAS_PARAM_TEST // Gets the number of successful test cases. int successful_test_case_count() const; // Gets the number of failed test cases. int failed_test_case_count() const; // Gets the number of all test cases. int total_test_case_count() const; // Gets the number of all test cases that contain at least one test // that should run. int test_case_to_run_count() const; // Gets the number of successful tests. int successful_test_count() const; // Gets the number of failed tests. int failed_test_count() const; // Gets the number of disabled tests that will be reported in the XML report. int reportable_disabled_test_count() const; // Gets the number of disabled tests. int disabled_test_count() const; // Gets the number of tests to be printed in the XML report. int reportable_test_count() const; // Gets the number of all tests. int total_test_count() const; // Gets the number of tests that should run. int test_to_run_count() const; // Gets the time of the test program start, in ms from the start of the // UNIX epoch. TimeInMillis start_timestamp() const; // Gets the elapsed time, in milliseconds. TimeInMillis elapsed_time() const; // Returns true iff the unit test passed (i.e. all test cases passed). bool Passed() const; // Returns true iff the unit test failed (i.e. some test case failed // or something outside of all tests failed). bool Failed() const; // Gets the i-th test case among all the test cases. i can range from 0 to // total_test_case_count() - 1. If i is not in that range, returns NULL. const TestCase* GetTestCase(int i) const; // Returns the TestResult containing information on test failures and // properties logged outside of individual test cases. const TestResult& ad_hoc_test_result() const; // Returns the list of event listeners that can be used to track events // inside Google Test. TestEventListeners& listeners(); private: // Registers and returns a global test environment. When a test // program is run, all global test environments will be set-up in // the order they were registered. After all tests in the program // have finished, all global test environments will be torn-down in // the *reverse* order they were registered. // // The UnitTest object takes ownership of the given environment. // // This method can only be called from the main thread. Environment* AddEnvironment(Environment* env); // Adds a TestPartResult to the current TestResult object. All // Google Test assertion macros (e.g. ASSERT_TRUE, EXPECT_EQ, etc) // eventually call this to report their results. The user code // should use the assertion macros instead of calling this directly. void AddTestPartResult(TestPartResult::Type result_type, const char* file_name, int line_number, const std::string& message, const std::string& os_stack_trace) GTEST_LOCK_EXCLUDED_(mutex_); // Adds a TestProperty to the current TestResult object when invoked from // inside a test, to current TestCase's ad_hoc_test_result_ when invoked // from SetUpTestCase or TearDownTestCase, or to the global property set // when invoked elsewhere. If the result already contains a property with // the same key, the value will be updated. void RecordProperty(const std::string& key, const std::string& value); // Gets the i-th test case among all the test cases. i can range from 0 to // total_test_case_count() - 1. If i is not in that range, returns NULL. TestCase* GetMutableTestCase(int i); // Accessors for the implementation object. internal::UnitTestImpl* impl() { return impl_; } const internal::UnitTestImpl* impl() const { return impl_; } // These classes and funcions are friends as they need to access private // members of UnitTest. friend class Test; friend class internal::AssertHelper; friend class internal::ScopedTrace; friend class internal::StreamingListenerTest; friend class internal::UnitTestRecordPropertyTestHelper; friend Environment* AddGlobalTestEnvironment(Environment* env); friend internal::UnitTestImpl* internal::GetUnitTestImpl(); friend void internal::ReportFailureInUnknownLocation( TestPartResult::Type result_type, const std::string& message); // Creates an empty UnitTest. UnitTest(); // D'tor virtual ~UnitTest(); // Pushes a trace defined by SCOPED_TRACE() on to the per-thread // Google Test trace stack. void PushGTestTrace(const internal::TraceInfo& trace) GTEST_LOCK_EXCLUDED_(mutex_); // Pops a trace from the per-thread Google Test trace stack. void PopGTestTrace() GTEST_LOCK_EXCLUDED_(mutex_); // Protects mutable state in *impl_. This is mutable as some const // methods need to lock it too. mutable internal::Mutex mutex_; // Opaque implementation object. This field is never changed once // the object is constructed. We don't mark it as const here, as // doing so will cause a warning in the constructor of UnitTest. // Mutable state in *impl_ is protected by mutex_. internal::UnitTestImpl* impl_; // We disallow copying UnitTest. GTEST_DISALLOW_COPY_AND_ASSIGN_(UnitTest); }; // A convenient wrapper for adding an environment for the test // program. // // You should call this before RUN_ALL_TESTS() is called, probably in // main(). If you use gtest_main, you need to call this before main() // starts for it to take effect. For example, you can define a global // variable like this: // // testing::Environment* const foo_env = // testing::AddGlobalTestEnvironment(new FooEnvironment); // // However, we strongly recommend you to write your own main() and // call AddGlobalTestEnvironment() there, as relying on initialization // of global variables makes the code harder to read and may cause // problems when you register multiple environments from different // translation units and the environments have dependencies among them // (remember that the compiler doesn't guarantee the order in which // global variables from different translation units are initialized). inline Environment* AddGlobalTestEnvironment(Environment* env) { return UnitTest::GetInstance()->AddEnvironment(env); } // Initializes Google Test. This must be called before calling // RUN_ALL_TESTS(). In particular, it parses a command line for the // flags that Google Test recognizes. Whenever a Google Test flag is // seen, it is removed from argv, and *argc is decremented. // // No value is returned. Instead, the Google Test flag variables are // updated. // // Calling the function for the second time has no user-visible effect. GTEST_API_ void InitGoogleTest(int* argc, char** argv); // This overloaded version can be used in Windows programs compiled in // UNICODE mode. GTEST_API_ void InitGoogleTest(int* argc, wchar_t** argv); namespace internal { // FormatForComparison::Format(value) formats a // value of type ToPrint that is an operand of a comparison assertion // (e.g. ASSERT_EQ). OtherOperand is the type of the other operand in // the comparison, and is used to help determine the best way to // format the value. In particular, when the value is a C string // (char pointer) and the other operand is an STL string object, we // want to format the C string as a string, since we know it is // compared by value with the string object. If the value is a char // pointer but the other operand is not an STL string object, we don't // know whether the pointer is supposed to point to a NUL-terminated // string, and thus want to print it as a pointer to be safe. // // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. // The default case. template class FormatForComparison { public: static ::std::string Format(const ToPrint& value) { return ::testing::PrintToString(value); } }; // Array. template class FormatForComparison { public: static ::std::string Format(const ToPrint* value) { return FormatForComparison::Format(value); } }; // By default, print C string as pointers to be safe, as we don't know // whether they actually point to a NUL-terminated string. #define GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_(CharType) \ template \ class FormatForComparison { \ public: \ static ::std::string Format(CharType* value) { \ return ::testing::PrintToString(static_cast(value)); \ } \ } GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_(char); GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_(const char); GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_(wchar_t); GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_(const wchar_t); #undef GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_ // If a C string is compared with an STL string object, we know it's meant // to point to a NUL-terminated string, and thus can print it as a string. #define GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(CharType, OtherStringType) \ template <> \ class FormatForComparison { \ public: \ static ::std::string Format(CharType* value) { \ return ::testing::PrintToString(value); \ } \ } GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(char, ::std::string); GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(const char, ::std::string); #if GTEST_HAS_GLOBAL_STRING GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(char, ::string); GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(const char, ::string); #endif #if GTEST_HAS_GLOBAL_WSTRING GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(wchar_t, ::wstring); GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(const wchar_t, ::wstring); #endif #if GTEST_HAS_STD_WSTRING GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(wchar_t, ::std::wstring); GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(const wchar_t, ::std::wstring); #endif #undef GTEST_IMPL_FORMAT_C_STRING_AS_STRING_ // Formats a comparison assertion (e.g. ASSERT_EQ, EXPECT_LT, and etc) // operand to be used in a failure message. The type (but not value) // of the other operand may affect the format. This allows us to // print a char* as a raw pointer when it is compared against another // char* or void*, and print it as a C string when it is compared // against an std::string object, for example. // // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. template std::string FormatForComparisonFailureMessage( const T1& value, const T2& /* other_operand */) { return FormatForComparison::Format(value); } // The helper function for {ASSERT|EXPECT}_EQ. template AssertionResult CmpHelperEQ(const char* expected_expression, const char* actual_expression, const T1& expected, const T2& actual) { #ifdef _MSC_VER # pragma warning(push) // Saves the current warning state. # pragma warning(disable:4389) // Temporarily disables warning on // signed/unsigned mismatch. #endif if (expected == actual) { return AssertionSuccess(); } #ifdef _MSC_VER # pragma warning(pop) // Restores the warning state. #endif return EqFailure(expected_expression, actual_expression, FormatForComparisonFailureMessage(expected, actual), FormatForComparisonFailureMessage(actual, expected), false); } // With this overloaded version, we allow anonymous enums to be used // in {ASSERT|EXPECT}_EQ when compiled with gcc 4, as anonymous enums // can be implicitly cast to BiggestInt. GTEST_API_ AssertionResult CmpHelperEQ(const char* expected_expression, const char* actual_expression, BiggestInt expected, BiggestInt actual); // The helper class for {ASSERT|EXPECT}_EQ. The template argument // lhs_is_null_literal is true iff the first argument to ASSERT_EQ() // is a null pointer literal. The following default implementation is // for lhs_is_null_literal being false. template class EqHelper { public: // This templatized version is for the general case. template static AssertionResult Compare(const char* expected_expression, const char* actual_expression, const T1& expected, const T2& actual) { return CmpHelperEQ(expected_expression, actual_expression, expected, actual); } // With this overloaded version, we allow anonymous enums to be used // in {ASSERT|EXPECT}_EQ when compiled with gcc 4, as anonymous // enums can be implicitly cast to BiggestInt. // // Even though its body looks the same as the above version, we // cannot merge the two, as it will make anonymous enums unhappy. static AssertionResult Compare(const char* expected_expression, const char* actual_expression, BiggestInt expected, BiggestInt actual) { return CmpHelperEQ(expected_expression, actual_expression, expected, actual); } }; // This specialization is used when the first argument to ASSERT_EQ() // is a null pointer literal, like NULL, false, or 0. template <> class EqHelper { public: // We define two overloaded versions of Compare(). The first // version will be picked when the second argument to ASSERT_EQ() is // NOT a pointer, e.g. ASSERT_EQ(0, AnIntFunction()) or // EXPECT_EQ(false, a_bool). template static AssertionResult Compare( const char* expected_expression, const char* actual_expression, const T1& expected, const T2& actual, // The following line prevents this overload from being considered if T2 // is not a pointer type. We need this because ASSERT_EQ(NULL, my_ptr) // expands to Compare("", "", NULL, my_ptr), which requires a conversion // to match the Secret* in the other overload, which would otherwise make // this template match better. typename EnableIf::value>::type* = 0) { return CmpHelperEQ(expected_expression, actual_expression, expected, actual); } // This version will be picked when the second argument to ASSERT_EQ() is a // pointer, e.g. ASSERT_EQ(NULL, a_pointer). template static AssertionResult Compare( const char* expected_expression, const char* actual_expression, // We used to have a second template parameter instead of Secret*. That // template parameter would deduce to 'long', making this a better match // than the first overload even without the first overload's EnableIf. // Unfortunately, gcc with -Wconversion-null warns when "passing NULL to // non-pointer argument" (even a deduced integral argument), so the old // implementation caused warnings in user code. Secret* /* expected (NULL) */, T* actual) { // We already know that 'expected' is a null pointer. return CmpHelperEQ(expected_expression, actual_expression, static_cast(NULL), actual); } }; // A macro for implementing the helper functions needed to implement // ASSERT_?? and EXPECT_??. It is here just to avoid copy-and-paste // of similar code. // // For each templatized helper function, we also define an overloaded // version for BiggestInt in order to reduce code bloat and allow // anonymous enums to be used with {ASSERT|EXPECT}_?? when compiled // with gcc 4. // // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. #define GTEST_IMPL_CMP_HELPER_(op_name, op)\ template \ AssertionResult CmpHelper##op_name(const char* expr1, const char* expr2, \ const T1& val1, const T2& val2) { \ if (val1 op val2) { return AssertionSuccess(); \ }else { return AssertionFailure() \ << "Expected: (" << expr1 << ") " #op " (" << expr2\ << "), actual: " << FormatForComparisonFailureMessage(val1, val2)\ << " vs " << FormatForComparisonFailureMessage(val2, val1); \ }\ }\ GTEST_API_ AssertionResult CmpHelper##op_name(\ const char* expr1, const char* expr2, BiggestInt val1, BiggestInt val2) // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. // Implements the helper function for {ASSERT|EXPECT}_NE GTEST_IMPL_CMP_HELPER_(NE, != ); // Implements the helper function for {ASSERT|EXPECT}_LE GTEST_IMPL_CMP_HELPER_(LE, <= ); // Implements the helper function for {ASSERT|EXPECT}_LT GTEST_IMPL_CMP_HELPER_(LT, <); // Implements the helper function for {ASSERT|EXPECT}_GE GTEST_IMPL_CMP_HELPER_(GE, >= ); // Implements the helper function for {ASSERT|EXPECT}_GT GTEST_IMPL_CMP_HELPER_(GT, >); #undef GTEST_IMPL_CMP_HELPER_ // The helper function for {ASSERT|EXPECT}_STREQ. // // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. GTEST_API_ AssertionResult CmpHelperSTREQ(const char* expected_expression, const char* actual_expression, const char* expected, const char* actual); // The helper function for {ASSERT|EXPECT}_STRCASEEQ. // // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. GTEST_API_ AssertionResult CmpHelperSTRCASEEQ(const char* expected_expression, const char* actual_expression, const char* expected, const char* actual); // The helper function for {ASSERT|EXPECT}_STRNE. // // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. GTEST_API_ AssertionResult CmpHelperSTRNE(const char* s1_expression, const char* s2_expression, const char* s1, const char* s2); // The helper function for {ASSERT|EXPECT}_STRCASENE. // // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. GTEST_API_ AssertionResult CmpHelperSTRCASENE(const char* s1_expression, const char* s2_expression, const char* s1, const char* s2); // Helper function for *_STREQ on wide strings. // // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. GTEST_API_ AssertionResult CmpHelperSTREQ(const char* expected_expression, const char* actual_expression, const wchar_t* expected, const wchar_t* actual); // Helper function for *_STRNE on wide strings. // // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. GTEST_API_ AssertionResult CmpHelperSTRNE(const char* s1_expression, const char* s2_expression, const wchar_t* s1, const wchar_t* s2); } // namespace internal // IsSubstring() and IsNotSubstring() are intended to be used as the // first argument to {EXPECT,ASSERT}_PRED_FORMAT2(), not by // themselves. They check whether needle is a substring of haystack // (NULL is considered a substring of itself only), and return an // appropriate error message when they fail. // // The {needle,haystack}_expr arguments are the stringified // expressions that generated the two real arguments. GTEST_API_ AssertionResult IsSubstring( const char* needle_expr, const char* haystack_expr, const char* needle, const char* haystack); GTEST_API_ AssertionResult IsSubstring( const char* needle_expr, const char* haystack_expr, const wchar_t* needle, const wchar_t* haystack); GTEST_API_ AssertionResult IsNotSubstring( const char* needle_expr, const char* haystack_expr, const char* needle, const char* haystack); GTEST_API_ AssertionResult IsNotSubstring( const char* needle_expr, const char* haystack_expr, const wchar_t* needle, const wchar_t* haystack); GTEST_API_ AssertionResult IsSubstring( const char* needle_expr, const char* haystack_expr, const ::std::string& needle, const ::std::string& haystack); GTEST_API_ AssertionResult IsNotSubstring( const char* needle_expr, const char* haystack_expr, const ::std::string& needle, const ::std::string& haystack); #if GTEST_HAS_STD_WSTRING GTEST_API_ AssertionResult IsSubstring( const char* needle_expr, const char* haystack_expr, const ::std::wstring& needle, const ::std::wstring& haystack); GTEST_API_ AssertionResult IsNotSubstring( const char* needle_expr, const char* haystack_expr, const ::std::wstring& needle, const ::std::wstring& haystack); #endif // GTEST_HAS_STD_WSTRING namespace internal { // Helper template function for comparing floating-points. // // Template parameter: // // RawType: the raw floating-point type (either float or double) // // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. template AssertionResult CmpHelperFloatingPointEQ(const char* expected_expression, const char* actual_expression, RawType expected, RawType actual) { const FloatingPoint lhs(expected), rhs(actual); if (lhs.AlmostEquals(rhs)) { return AssertionSuccess(); } ::std::stringstream expected_ss; expected_ss << std::setprecision(std::numeric_limits::digits10 + 2) << expected; ::std::stringstream actual_ss; actual_ss << std::setprecision(std::numeric_limits::digits10 + 2) << actual; return EqFailure(expected_expression, actual_expression, StringStreamToString(&expected_ss), StringStreamToString(&actual_ss), false); } // Helper function for implementing ASSERT_NEAR. // // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. GTEST_API_ AssertionResult DoubleNearPredFormat(const char* expr1, const char* expr2, const char* abs_error_expr, double val1, double val2, double abs_error); // INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. // A class that enables one to stream messages to assertion macros class GTEST_API_ AssertHelper { public: // Constructor. AssertHelper(TestPartResult::Type type, const char* file, int line, const char* message); ~AssertHelper(); // Message assignment is a semantic trick to enable assertion // streaming; see the GTEST_MESSAGE_ macro below. void operator=(const Message& message) const; private: // We put our data in a struct so that the size of the AssertHelper class can // be as small as possible. This is important because gcc is incapable of // re-using stack space even for temporary variables, so every EXPECT_EQ // reserves stack space for another AssertHelper. struct AssertHelperData { AssertHelperData(TestPartResult::Type t, const char* srcfile, int line_num, const char* msg) : type(t), file(srcfile), line(line_num), message(msg) { } TestPartResult::Type const type; const char* const file; int const line; std::string const message; private: GTEST_DISALLOW_COPY_AND_ASSIGN_(AssertHelperData); }; AssertHelperData* const data_; GTEST_DISALLOW_COPY_AND_ASSIGN_(AssertHelper); }; } // namespace internal #if GTEST_HAS_PARAM_TEST // The pure interface class that all value-parameterized tests inherit from. // A value-parameterized class must inherit from both ::testing::Test and // ::testing::WithParamInterface. In most cases that just means inheriting // from ::testing::TestWithParam, but more complicated test hierarchies // may need to inherit from Test and WithParamInterface at different levels. // // This interface has support for accessing the test parameter value via // the GetParam() method. // // Use it with one of the parameter generator defining functions, like Range(), // Values(), ValuesIn(), Bool(), and Combine(). // // class FooTest : public ::testing::TestWithParam { // protected: // FooTest() { // // Can use GetParam() here. // } // virtual ~FooTest() { // // Can use GetParam() here. // } // virtual void SetUp() { // // Can use GetParam() here. // } // virtual void TearDown { // // Can use GetParam() here. // } // }; // TEST_P(FooTest, DoesBar) { // // Can use GetParam() method here. // Foo foo; // ASSERT_TRUE(foo.DoesBar(GetParam())); // } // INSTANTIATE_TEST_CASE_P(OneToTenRange, FooTest, ::testing::Range(1, 10)); template class WithParamInterface { public: typedef T ParamType; virtual ~WithParamInterface() {} // The current parameter value. Is also available in the test fixture's // constructor. This member function is non-static, even though it only // references static data, to reduce the opportunity for incorrect uses // like writing 'WithParamInterface::GetParam()' for a test that // uses a fixture whose parameter type is int. const ParamType& GetParam() const { GTEST_CHECK_(parameter_ != NULL) << "GetParam() can only be called inside a value-parameterized test " << "-- did you intend to write TEST_P instead of TEST_F?"; return *parameter_; } private: // Sets parameter value. The caller is responsible for making sure the value // remains alive and unchanged throughout the current test. static void SetParam(const ParamType* parameter) { parameter_ = parameter; } // Static value used for accessing parameter during a test lifetime. static const ParamType* parameter_; // TestClass must be a subclass of WithParamInterface and Test. template friend class internal::ParameterizedTestFactory; }; template const T* WithParamInterface::parameter_ = NULL; // Most value-parameterized classes can ignore the existence of // WithParamInterface, and can just inherit from ::testing::TestWithParam. template class TestWithParam : public Test, public WithParamInterface { }; #endif // GTEST_HAS_PARAM_TEST // Macros for indicating success/failure in test code. // ADD_FAILURE unconditionally adds a failure to the current test. // SUCCEED generates a success - it doesn't automatically make the // current test successful, as a test is only successful when it has // no failure. // // EXPECT_* verifies that a certain condition is satisfied. If not, // it behaves like ADD_FAILURE. In particular: // // EXPECT_TRUE verifies that a Boolean condition is true. // EXPECT_FALSE verifies that a Boolean condition is false. // // FAIL and ASSERT_* are similar to ADD_FAILURE and EXPECT_*, except // that they will also abort the current function on failure. People // usually want the fail-fast behavior of FAIL and ASSERT_*, but those // writing data-driven tests often find themselves using ADD_FAILURE // and EXPECT_* more. // Generates a nonfatal failure with a generic message. #define ADD_FAILURE() GTEST_NONFATAL_FAILURE_("Failed") // Generates a nonfatal failure at the given source file location with // a generic message. #define ADD_FAILURE_AT(file, line) \ GTEST_MESSAGE_AT_(file, line, "Failed", \ ::testing::TestPartResult::kNonFatalFailure) // Generates a fatal failure with a generic message. #define GTEST_FAIL() GTEST_FATAL_FAILURE_("Failed") // Define this macro to 1 to omit the definition of FAIL(), which is a // generic name and clashes with some other libraries. #if !GTEST_DONT_DEFINE_FAIL # define FAIL() GTEST_FAIL() #endif // Generates a success with a generic message. #define GTEST_SUCCEED() GTEST_SUCCESS_("Succeeded") // Define this macro to 1 to omit the definition of SUCCEED(), which // is a generic name and clashes with some other libraries. #if !GTEST_DONT_DEFINE_SUCCEED # define SUCCEED() GTEST_SUCCEED() #endif // Macros for testing exceptions. // // * {ASSERT|EXPECT}_THROW(statement, expected_exception): // Tests that the statement throws the expected exception. // * {ASSERT|EXPECT}_NO_THROW(statement): // Tests that the statement doesn't throw any exception. // * {ASSERT|EXPECT}_ANY_THROW(statement): // Tests that the statement throws an exception. #define EXPECT_THROW(statement, expected_exception) \ GTEST_TEST_THROW_(statement, expected_exception, GTEST_NONFATAL_FAILURE_) #define EXPECT_NO_THROW(statement) \ GTEST_TEST_NO_THROW_(statement, GTEST_NONFATAL_FAILURE_) #define EXPECT_ANY_THROW(statement) \ GTEST_TEST_ANY_THROW_(statement, GTEST_NONFATAL_FAILURE_) #define ASSERT_THROW(statement, expected_exception) \ GTEST_TEST_THROW_(statement, expected_exception, GTEST_FATAL_FAILURE_) #define ASSERT_NO_THROW(statement) \ GTEST_TEST_NO_THROW_(statement, GTEST_FATAL_FAILURE_) #define ASSERT_ANY_THROW(statement) \ GTEST_TEST_ANY_THROW_(statement, GTEST_FATAL_FAILURE_) // Boolean assertions. Condition can be either a Boolean expression or an // AssertionResult. For more information on how to use AssertionResult with // these macros see comments on that class. #define EXPECT_TRUE(condition) \ GTEST_TEST_BOOLEAN_(condition, #condition, false, true, \ GTEST_NONFATAL_FAILURE_) #define EXPECT_FALSE(condition) \ GTEST_TEST_BOOLEAN_(!(condition), #condition, true, false, \ GTEST_NONFATAL_FAILURE_) #define ASSERT_TRUE(condition) \ GTEST_TEST_BOOLEAN_(condition, #condition, false, true, \ GTEST_FATAL_FAILURE_) #define ASSERT_FALSE(condition) \ GTEST_TEST_BOOLEAN_(!(condition), #condition, true, false, \ GTEST_FATAL_FAILURE_) // Includes the auto-generated header that implements a family of // generic predicate assertion macros. // Copyright 2006, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // This file is AUTOMATICALLY GENERATED on 10/31/2011 by command // 'gen_gtest_pred_impl.py 5'. DO NOT EDIT BY HAND! // // Implements a family of generic predicate assertion macros. #ifndef GTEST_INCLUDE_GTEST_GTEST_PRED_IMPL_H_ #define GTEST_INCLUDE_GTEST_GTEST_PRED_IMPL_H_ // Makes sure this header is not included before gtest.h. #ifndef GTEST_INCLUDE_GTEST_GTEST_H_ # error Do not include gtest_pred_impl.h directly. Include gtest.h instead. #endif // GTEST_INCLUDE_GTEST_GTEST_H_ // This header implements a family of generic predicate assertion // macros: // // ASSERT_PRED_FORMAT1(pred_format, v1) // ASSERT_PRED_FORMAT2(pred_format, v1, v2) // ... // // where pred_format is a function or functor that takes n (in the // case of ASSERT_PRED_FORMATn) values and their source expression // text, and returns a testing::AssertionResult. See the definition // of ASSERT_EQ in gtest.h for an example. // // If you don't care about formatting, you can use the more // restrictive version: // // ASSERT_PRED1(pred, v1) // ASSERT_PRED2(pred, v1, v2) // ... // // where pred is an n-ary function or functor that returns bool, // and the values v1, v2, ..., must support the << operator for // streaming to std::ostream. // // We also define the EXPECT_* variations. // // For now we only support predicates whose arity is at most 5. // Please email googletestframework@googlegroups.com if you need // support for higher arities. // GTEST_ASSERT_ is the basic statement to which all of the assertions // in this file reduce. Don't use this in your code. #define GTEST_ASSERT_(expression, on_failure) \ GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ if (const ::testing::AssertionResult gtest_ar = (expression)) \ ; \ else \ on_failure(gtest_ar.failure_message()) // Helper function for implementing {EXPECT|ASSERT}_PRED1. Don't use // this in your code. template AssertionResult AssertPred1Helper(const char* pred_text, const char* e1, Pred pred, const T1& v1) { if (pred(v1)) return AssertionSuccess(); return AssertionFailure() << pred_text << "(" << e1 << ") evaluates to false, where" << "\n" << e1 << " evaluates to " << v1; } // Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT1. // Don't use this in your code. #define GTEST_PRED_FORMAT1_(pred_format, v1, on_failure)\ GTEST_ASSERT_(pred_format(#v1, v1), \ on_failure) // Internal macro for implementing {EXPECT|ASSERT}_PRED1. Don't use // this in your code. #define GTEST_PRED1_(pred, v1, on_failure)\ GTEST_ASSERT_(::testing::AssertPred1Helper(#pred, \ #v1, \ pred, \ v1), on_failure) // Unary predicate assertion macros. #define EXPECT_PRED_FORMAT1(pred_format, v1) \ GTEST_PRED_FORMAT1_(pred_format, v1, GTEST_NONFATAL_FAILURE_) #define EXPECT_PRED1(pred, v1) \ GTEST_PRED1_(pred, v1, GTEST_NONFATAL_FAILURE_) #define ASSERT_PRED_FORMAT1(pred_format, v1) \ GTEST_PRED_FORMAT1_(pred_format, v1, GTEST_FATAL_FAILURE_) #define ASSERT_PRED1(pred, v1) \ GTEST_PRED1_(pred, v1, GTEST_FATAL_FAILURE_) // Helper function for implementing {EXPECT|ASSERT}_PRED2. Don't use // this in your code. template AssertionResult AssertPred2Helper(const char* pred_text, const char* e1, const char* e2, Pred pred, const T1& v1, const T2& v2) { if (pred(v1, v2)) return AssertionSuccess(); return AssertionFailure() << pred_text << "(" << e1 << ", " << e2 << ") evaluates to false, where" << "\n" << e1 << " evaluates to " << v1 << "\n" << e2 << " evaluates to " << v2; } // Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT2. // Don't use this in your code. #define GTEST_PRED_FORMAT2_(pred_format, v1, v2, on_failure)\ GTEST_ASSERT_(pred_format(#v1, #v2, v1, v2), \ on_failure) // Internal macro for implementing {EXPECT|ASSERT}_PRED2. Don't use // this in your code. #define GTEST_PRED2_(pred, v1, v2, on_failure)\ GTEST_ASSERT_(::testing::AssertPred2Helper(#pred, \ #v1, \ #v2, \ pred, \ v1, \ v2), on_failure) // Binary predicate assertion macros. #define EXPECT_PRED_FORMAT2(pred_format, v1, v2) \ GTEST_PRED_FORMAT2_(pred_format, v1, v2, GTEST_NONFATAL_FAILURE_) #define EXPECT_PRED2(pred, v1, v2) \ GTEST_PRED2_(pred, v1, v2, GTEST_NONFATAL_FAILURE_) #define ASSERT_PRED_FORMAT2(pred_format, v1, v2) \ GTEST_PRED_FORMAT2_(pred_format, v1, v2, GTEST_FATAL_FAILURE_) #define ASSERT_PRED2(pred, v1, v2) \ GTEST_PRED2_(pred, v1, v2, GTEST_FATAL_FAILURE_) // Helper function for implementing {EXPECT|ASSERT}_PRED3. Don't use // this in your code. template AssertionResult AssertPred3Helper(const char* pred_text, const char* e1, const char* e2, const char* e3, Pred pred, const T1& v1, const T2& v2, const T3& v3) { if (pred(v1, v2, v3)) return AssertionSuccess(); return AssertionFailure() << pred_text << "(" << e1 << ", " << e2 << ", " << e3 << ") evaluates to false, where" << "\n" << e1 << " evaluates to " << v1 << "\n" << e2 << " evaluates to " << v2 << "\n" << e3 << " evaluates to " << v3; } // Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT3. // Don't use this in your code. #define GTEST_PRED_FORMAT3_(pred_format, v1, v2, v3, on_failure)\ GTEST_ASSERT_(pred_format(#v1, #v2, #v3, v1, v2, v3), \ on_failure) // Internal macro for implementing {EXPECT|ASSERT}_PRED3. Don't use // this in your code. #define GTEST_PRED3_(pred, v1, v2, v3, on_failure)\ GTEST_ASSERT_(::testing::AssertPred3Helper(#pred, \ #v1, \ #v2, \ #v3, \ pred, \ v1, \ v2, \ v3), on_failure) // Ternary predicate assertion macros. #define EXPECT_PRED_FORMAT3(pred_format, v1, v2, v3) \ GTEST_PRED_FORMAT3_(pred_format, v1, v2, v3, GTEST_NONFATAL_FAILURE_) #define EXPECT_PRED3(pred, v1, v2, v3) \ GTEST_PRED3_(pred, v1, v2, v3, GTEST_NONFATAL_FAILURE_) #define ASSERT_PRED_FORMAT3(pred_format, v1, v2, v3) \ GTEST_PRED_FORMAT3_(pred_format, v1, v2, v3, GTEST_FATAL_FAILURE_) #define ASSERT_PRED3(pred, v1, v2, v3) \ GTEST_PRED3_(pred, v1, v2, v3, GTEST_FATAL_FAILURE_) // Helper function for implementing {EXPECT|ASSERT}_PRED4. Don't use // this in your code. template AssertionResult AssertPred4Helper(const char* pred_text, const char* e1, const char* e2, const char* e3, const char* e4, Pred pred, const T1& v1, const T2& v2, const T3& v3, const T4& v4) { if (pred(v1, v2, v3, v4)) return AssertionSuccess(); return AssertionFailure() << pred_text << "(" << e1 << ", " << e2 << ", " << e3 << ", " << e4 << ") evaluates to false, where" << "\n" << e1 << " evaluates to " << v1 << "\n" << e2 << " evaluates to " << v2 << "\n" << e3 << " evaluates to " << v3 << "\n" << e4 << " evaluates to " << v4; } // Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT4. // Don't use this in your code. #define GTEST_PRED_FORMAT4_(pred_format, v1, v2, v3, v4, on_failure)\ GTEST_ASSERT_(pred_format(#v1, #v2, #v3, #v4, v1, v2, v3, v4), \ on_failure) // Internal macro for implementing {EXPECT|ASSERT}_PRED4. Don't use // this in your code. #define GTEST_PRED4_(pred, v1, v2, v3, v4, on_failure)\ GTEST_ASSERT_(::testing::AssertPred4Helper(#pred, \ #v1, \ #v2, \ #v3, \ #v4, \ pred, \ v1, \ v2, \ v3, \ v4), on_failure) // 4-ary predicate assertion macros. #define EXPECT_PRED_FORMAT4(pred_format, v1, v2, v3, v4) \ GTEST_PRED_FORMAT4_(pred_format, v1, v2, v3, v4, GTEST_NONFATAL_FAILURE_) #define EXPECT_PRED4(pred, v1, v2, v3, v4) \ GTEST_PRED4_(pred, v1, v2, v3, v4, GTEST_NONFATAL_FAILURE_) #define ASSERT_PRED_FORMAT4(pred_format, v1, v2, v3, v4) \ GTEST_PRED_FORMAT4_(pred_format, v1, v2, v3, v4, GTEST_FATAL_FAILURE_) #define ASSERT_PRED4(pred, v1, v2, v3, v4) \ GTEST_PRED4_(pred, v1, v2, v3, v4, GTEST_FATAL_FAILURE_) // Helper function for implementing {EXPECT|ASSERT}_PRED5. Don't use // this in your code. template AssertionResult AssertPred5Helper(const char* pred_text, const char* e1, const char* e2, const char* e3, const char* e4, const char* e5, Pred pred, const T1& v1, const T2& v2, const T3& v3, const T4& v4, const T5& v5) { if (pred(v1, v2, v3, v4, v5)) return AssertionSuccess(); return AssertionFailure() << pred_text << "(" << e1 << ", " << e2 << ", " << e3 << ", " << e4 << ", " << e5 << ") evaluates to false, where" << "\n" << e1 << " evaluates to " << v1 << "\n" << e2 << " evaluates to " << v2 << "\n" << e3 << " evaluates to " << v3 << "\n" << e4 << " evaluates to " << v4 << "\n" << e5 << " evaluates to " << v5; } // Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT5. // Don't use this in your code. #define GTEST_PRED_FORMAT5_(pred_format, v1, v2, v3, v4, v5, on_failure)\ GTEST_ASSERT_(pred_format(#v1, #v2, #v3, #v4, #v5, v1, v2, v3, v4, v5), \ on_failure) // Internal macro for implementing {EXPECT|ASSERT}_PRED5. Don't use // this in your code. #define GTEST_PRED5_(pred, v1, v2, v3, v4, v5, on_failure)\ GTEST_ASSERT_(::testing::AssertPred5Helper(#pred, \ #v1, \ #v2, \ #v3, \ #v4, \ #v5, \ pred, \ v1, \ v2, \ v3, \ v4, \ v5), on_failure) // 5-ary predicate assertion macros. #define EXPECT_PRED_FORMAT5(pred_format, v1, v2, v3, v4, v5) \ GTEST_PRED_FORMAT5_(pred_format, v1, v2, v3, v4, v5, GTEST_NONFATAL_FAILURE_) #define EXPECT_PRED5(pred, v1, v2, v3, v4, v5) \ GTEST_PRED5_(pred, v1, v2, v3, v4, v5, GTEST_NONFATAL_FAILURE_) #define ASSERT_PRED_FORMAT5(pred_format, v1, v2, v3, v4, v5) \ GTEST_PRED_FORMAT5_(pred_format, v1, v2, v3, v4, v5, GTEST_FATAL_FAILURE_) #define ASSERT_PRED5(pred, v1, v2, v3, v4, v5) \ GTEST_PRED5_(pred, v1, v2, v3, v4, v5, GTEST_FATAL_FAILURE_) #endif // GTEST_INCLUDE_GTEST_GTEST_PRED_IMPL_H_ // Macros for testing equalities and inequalities. // // * {ASSERT|EXPECT}_EQ(expected, actual): Tests that expected == actual // * {ASSERT|EXPECT}_NE(v1, v2): Tests that v1 != v2 // * {ASSERT|EXPECT}_LT(v1, v2): Tests that v1 < v2 // * {ASSERT|EXPECT}_LE(v1, v2): Tests that v1 <= v2 // * {ASSERT|EXPECT}_GT(v1, v2): Tests that v1 > v2 // * {ASSERT|EXPECT}_GE(v1, v2): Tests that v1 >= v2 // // When they are not, Google Test prints both the tested expressions and // their actual values. The values must be compatible built-in types, // or you will get a compiler error. By "compatible" we mean that the // values can be compared by the respective operator. // // Note: // // 1. It is possible to make a user-defined type work with // {ASSERT|EXPECT}_??(), but that requires overloading the // comparison operators and is thus discouraged by the Google C++ // Usage Guide. Therefore, you are advised to use the // {ASSERT|EXPECT}_TRUE() macro to assert that two objects are // equal. // // 2. The {ASSERT|EXPECT}_??() macros do pointer comparisons on // pointers (in particular, C strings). Therefore, if you use it // with two C strings, you are testing how their locations in memory // are related, not how their content is related. To compare two C // strings by content, use {ASSERT|EXPECT}_STR*(). // // 3. {ASSERT|EXPECT}_EQ(expected, actual) is preferred to // {ASSERT|EXPECT}_TRUE(expected == actual), as the former tells you // what the actual value is when it fails, and similarly for the // other comparisons. // // 4. Do not depend on the order in which {ASSERT|EXPECT}_??() // evaluate their arguments, which is undefined. // // 5. These macros evaluate their arguments exactly once. // // Examples: // // EXPECT_NE(5, Foo()); // EXPECT_EQ(NULL, a_pointer); // ASSERT_LT(i, array_size); // ASSERT_GT(records.size(), 0) << "There is no record left."; #define EXPECT_EQ(expected, actual) \ EXPECT_PRED_FORMAT2(::testing::internal:: \ EqHelper::Compare, \ expected, actual) #define EXPECT_NE(expected, actual) \ EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperNE, expected, actual) #define EXPECT_LE(val1, val2) \ EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperLE, val1, val2) #define EXPECT_LT(val1, val2) \ EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperLT, val1, val2) #define EXPECT_GE(val1, val2) \ EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperGE, val1, val2) #define EXPECT_GT(val1, val2) \ EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperGT, val1, val2) #define GTEST_ASSERT_EQ(expected, actual) \ ASSERT_PRED_FORMAT2(::testing::internal:: \ EqHelper::Compare, \ expected, actual) #define GTEST_ASSERT_NE(val1, val2) \ ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperNE, val1, val2) #define GTEST_ASSERT_LE(val1, val2) \ ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperLE, val1, val2) #define GTEST_ASSERT_LT(val1, val2) \ ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperLT, val1, val2) #define GTEST_ASSERT_GE(val1, val2) \ ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperGE, val1, val2) #define GTEST_ASSERT_GT(val1, val2) \ ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperGT, val1, val2) // Define macro GTEST_DONT_DEFINE_ASSERT_XY to 1 to omit the definition of // ASSERT_XY(), which clashes with some users' own code. #if !GTEST_DONT_DEFINE_ASSERT_EQ # define ASSERT_EQ(val1, val2) GTEST_ASSERT_EQ(val1, val2) #endif #if !GTEST_DONT_DEFINE_ASSERT_NE # define ASSERT_NE(val1, val2) GTEST_ASSERT_NE(val1, val2) #endif #if !GTEST_DONT_DEFINE_ASSERT_LE # define ASSERT_LE(val1, val2) GTEST_ASSERT_LE(val1, val2) #endif #if !GTEST_DONT_DEFINE_ASSERT_LT # define ASSERT_LT(val1, val2) GTEST_ASSERT_LT(val1, val2) #endif #if !GTEST_DONT_DEFINE_ASSERT_GE # define ASSERT_GE(val1, val2) GTEST_ASSERT_GE(val1, val2) #endif #if !GTEST_DONT_DEFINE_ASSERT_GT # define ASSERT_GT(val1, val2) GTEST_ASSERT_GT(val1, val2) #endif // C-string Comparisons. All tests treat NULL and any non-NULL string // as different. Two NULLs are equal. // // * {ASSERT|EXPECT}_STREQ(s1, s2): Tests that s1 == s2 // * {ASSERT|EXPECT}_STRNE(s1, s2): Tests that s1 != s2 // * {ASSERT|EXPECT}_STRCASEEQ(s1, s2): Tests that s1 == s2, ignoring case // * {ASSERT|EXPECT}_STRCASENE(s1, s2): Tests that s1 != s2, ignoring case // // For wide or narrow string objects, you can use the // {ASSERT|EXPECT}_??() macros. // // Don't depend on the order in which the arguments are evaluated, // which is undefined. // // These macros evaluate their arguments exactly once. #define EXPECT_STREQ(expected, actual) \ EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperSTREQ, expected, actual) #define EXPECT_STRNE(s1, s2) \ EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperSTRNE, s1, s2) #define EXPECT_STRCASEEQ(expected, actual) \ EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperSTRCASEEQ, expected, actual) #define EXPECT_STRCASENE(s1, s2)\ EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperSTRCASENE, s1, s2) #define ASSERT_STREQ(expected, actual) \ ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperSTREQ, expected, actual) #define ASSERT_STRNE(s1, s2) \ ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperSTRNE, s1, s2) #define ASSERT_STRCASEEQ(expected, actual) \ ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperSTRCASEEQ, expected, actual) #define ASSERT_STRCASENE(s1, s2)\ ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperSTRCASENE, s1, s2) // Macros for comparing floating-point numbers. // // * {ASSERT|EXPECT}_FLOAT_EQ(expected, actual): // Tests that two float values are almost equal. // * {ASSERT|EXPECT}_DOUBLE_EQ(expected, actual): // Tests that two double values are almost equal. // * {ASSERT|EXPECT}_NEAR(v1, v2, abs_error): // Tests that v1 and v2 are within the given distance to each other. // // Google Test uses ULP-based comparison to automatically pick a default // error bound that is appropriate for the operands. See the // FloatingPoint template class in gtest-internal.h if you are // interested in the implementation details. #define EXPECT_FLOAT_EQ(expected, actual)\ EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperFloatingPointEQ, \ expected, actual) #define EXPECT_DOUBLE_EQ(expected, actual)\ EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperFloatingPointEQ, \ expected, actual) #define ASSERT_FLOAT_EQ(expected, actual)\ ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperFloatingPointEQ, \ expected, actual) #define ASSERT_DOUBLE_EQ(expected, actual)\ ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperFloatingPointEQ, \ expected, actual) #define EXPECT_NEAR(val1, val2, abs_error)\ EXPECT_PRED_FORMAT3(::testing::internal::DoubleNearPredFormat, \ val1, val2, abs_error) #define ASSERT_NEAR(val1, val2, abs_error)\ ASSERT_PRED_FORMAT3(::testing::internal::DoubleNearPredFormat, \ val1, val2, abs_error) // These predicate format functions work on floating-point values, and // can be used in {ASSERT|EXPECT}_PRED_FORMAT2*(), e.g. // // EXPECT_PRED_FORMAT2(testing::DoubleLE, Foo(), 5.0); // Asserts that val1 is less than, or almost equal to, val2. Fails // otherwise. In particular, it fails if either val1 or val2 is NaN. GTEST_API_ AssertionResult FloatLE(const char* expr1, const char* expr2, float val1, float val2); GTEST_API_ AssertionResult DoubleLE(const char* expr1, const char* expr2, double val1, double val2); #if GTEST_OS_WINDOWS // Macros that test for HRESULT failure and success, these are only useful // on Windows, and rely on Windows SDK macros and APIs to compile. // // * {ASSERT|EXPECT}_HRESULT_{SUCCEEDED|FAILED}(expr) // // When expr unexpectedly fails or succeeds, Google Test prints the // expected result and the actual result with both a human-readable // string representation of the error, if available, as well as the // hex result code. # define EXPECT_HRESULT_SUCCEEDED(expr) \ EXPECT_PRED_FORMAT1(::testing::internal::IsHRESULTSuccess, (expr)) # define ASSERT_HRESULT_SUCCEEDED(expr) \ ASSERT_PRED_FORMAT1(::testing::internal::IsHRESULTSuccess, (expr)) # define EXPECT_HRESULT_FAILED(expr) \ EXPECT_PRED_FORMAT1(::testing::internal::IsHRESULTFailure, (expr)) # define ASSERT_HRESULT_FAILED(expr) \ ASSERT_PRED_FORMAT1(::testing::internal::IsHRESULTFailure, (expr)) #endif // GTEST_OS_WINDOWS // Macros that execute statement and check that it doesn't generate new fatal // failures in the current thread. // // * {ASSERT|EXPECT}_NO_FATAL_FAILURE(statement); // // Examples: // // EXPECT_NO_FATAL_FAILURE(Process()); // ASSERT_NO_FATAL_FAILURE(Process()) << "Process() failed"; // #define ASSERT_NO_FATAL_FAILURE(statement) \ GTEST_TEST_NO_FATAL_FAILURE_(statement, GTEST_FATAL_FAILURE_) #define EXPECT_NO_FATAL_FAILURE(statement) \ GTEST_TEST_NO_FATAL_FAILURE_(statement, GTEST_NONFATAL_FAILURE_) // Causes a trace (including the source file path, the current line // number, and the given message) to be included in every test failure // message generated by code in the current scope. The effect is // undone when the control leaves the current scope. // // The message argument can be anything streamable to std::ostream. // // In the implementation, we include the current line number as part // of the dummy variable name, thus allowing multiple SCOPED_TRACE()s // to appear in the same block - as long as they are on different // lines. #define SCOPED_TRACE(message) \ ::testing::internal::ScopedTrace GTEST_CONCAT_TOKEN_(gtest_trace_, __LINE__)(\ __FILE__, __LINE__, ::testing::Message() << (message)) // Compile-time assertion for type equality. // StaticAssertTypeEq() compiles iff type1 and type2 are // the same type. The value it returns is not interesting. // // Instead of making StaticAssertTypeEq a class template, we make it a // function template that invokes a helper class template. This // prevents a user from misusing StaticAssertTypeEq by // defining objects of that type. // // CAVEAT: // // When used inside a method of a class template, // StaticAssertTypeEq() is effective ONLY IF the method is // instantiated. For example, given: // // template class Foo { // public: // void Bar() { testing::StaticAssertTypeEq(); } // }; // // the code: // // void Test1() { Foo foo; } // // will NOT generate a compiler error, as Foo::Bar() is never // actually instantiated. Instead, you need: // // void Test2() { Foo foo; foo.Bar(); } // // to cause a compiler error. template bool StaticAssertTypeEq() { (void)internal::StaticAssertTypeEqHelper(); return true; } // Defines a test. // // The first parameter is the name of the test case, and the second // parameter is the name of the test within the test case. // // The convention is to end the test case name with "Test". For // example, a test case for the Foo class can be named FooTest. // // The user should put his test code between braces after using this // macro. Example: // // TEST(FooTest, InitializesCorrectly) { // Foo foo; // EXPECT_TRUE(foo.StatusIsOK()); // } // Note that we call GetTestTypeId() instead of GetTypeId< // ::testing::Test>() here to get the type ID of testing::Test. This // is to work around a suspected linker bug when using Google Test as // a framework on Mac OS X. The bug causes GetTypeId< // ::testing::Test>() to return different values depending on whether // the call is from the Google Test framework itself or from user test // code. GetTestTypeId() is guaranteed to always return the same // value, as it always calls GetTypeId<>() from the Google Test // framework. #define GTEST_TEST(test_case_name, test_name)\ GTEST_TEST_(test_case_name, test_name, \ ::testing::Test, ::testing::internal::GetTestTypeId()) // Define this macro to 1 to omit the definition of TEST(), which // is a generic name and clashes with some other libraries. #if !GTEST_DONT_DEFINE_TEST # define TEST(test_case_name, test_name) GTEST_TEST(test_case_name, test_name) #endif // Defines a test that uses a test fixture. // // The first parameter is the name of the test fixture class, which // also doubles as the test case name. The second parameter is the // name of the test within the test case. // // A test fixture class must be declared earlier. The user should put // his test code between braces after using this macro. Example: // // class FooTest : public testing::Test { // protected: // virtual void SetUp() { b_.AddElement(3); } // // Foo a_; // Foo b_; // }; // // TEST_F(FooTest, InitializesCorrectly) { // EXPECT_TRUE(a_.StatusIsOK()); // } // // TEST_F(FooTest, ReturnsElementCountCorrectly) { // EXPECT_EQ(0, a_.size()); // EXPECT_EQ(1, b_.size()); // } #define TEST_F(test_fixture, test_name)\ GTEST_TEST_(test_fixture, test_name, test_fixture, \ ::testing::internal::GetTypeId()) } // namespace testing // Use this function in main() to run all tests. It returns 0 if all // tests are successful, or 1 otherwise. // // RUN_ALL_TESTS() should be invoked after the command line has been // parsed by InitGoogleTest(). // // This function was formerly a macro; thus, it is in the global // namespace and has an all-caps name. int RUN_ALL_TESTS() GTEST_MUST_USE_RESULT_; inline int RUN_ALL_TESTS() { return ::testing::UnitTest::GetInstance()->Run(); } #endif // GTEST_INCLUDE_GTEST_GTEST_H_ gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/ULT/googletest/src/000077500000000000000000000000001466655022700234625ustar00rootroot00000000000000gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/ULT/googletest/src/gtest-all.cc000066400000000000000000012644421466655022700257020ustar00rootroot00000000000000// Copyright 2008, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // Author: mheule@google.com (Markus Heule) // // Google C++ Testing Framework (Google Test) // // Sometimes it's desirable to build Google Test by compiling a single file. // This file serves this purpose. // This line ensures that gtest.h can be compiled on its own, even // when it's fused. /*#include "../../stdafx.h" #include "gtest/gtest.h" // The following lines pull in the real gtest *.cc files. #include "src/gtest.cc" #include "src/gtest-death-test.cc" #include "src/gtest-filepath.cc" #include "src/gtest-port.cc" #include "src/gtest-printers.cc" #include "src/gtest-test-part.cc" #include "src/gtest-typed-test.cc" */ // Copyright 2008, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // Author: mheule@google.com (Markus Heule) // // Google C++ Testing Framework (Google Test) // // Sometimes it's desirable to build Google Test by compiling a single file. // This file serves this purpose. // This line ensures that gtest.h can be compiled on its own, even // when it's fused. #include "gtest/gtest.h" // The following lines pull in the real gtest *.cc files. // Copyright 2005, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // Author: wan@google.com (Zhanyong Wan) // // The Google C++ Testing Framework (Google Test) // Copyright 2007, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // Author: wan@google.com (Zhanyong Wan) // // Utilities for testing Google Test itself and code that uses Google Test // (e.g. frameworks built on top of Google Test). #ifndef GTEST_INCLUDE_GTEST_GTEST_SPI_H_ #define GTEST_INCLUDE_GTEST_GTEST_SPI_H_ namespace testing { // This helper class can be used to mock out Google Test failure reporting // so that we can test Google Test or code that builds on Google Test. // // An object of this class appends a TestPartResult object to the // TestPartResultArray object given in the constructor whenever a Google Test // failure is reported. It can either intercept only failures that are // generated in the same thread that created this object or it can intercept // all generated failures. The scope of this mock object can be controlled with // the second argument to the two arguments constructor. class GTEST_API_ ScopedFakeTestPartResultReporter : public TestPartResultReporterInterface { public: // The two possible mocking modes of this object. enum InterceptMode { INTERCEPT_ONLY_CURRENT_THREAD, // Intercepts only thread local failures. INTERCEPT_ALL_THREADS // Intercepts all failures. }; // The c'tor sets this object as the test part result reporter used // by Google Test. The 'result' parameter specifies where to report the // results. This reporter will only catch failures generated in the current // thread. DEPRECATED explicit ScopedFakeTestPartResultReporter(TestPartResultArray* result); // Same as above, but you can choose the interception scope of this object. ScopedFakeTestPartResultReporter(InterceptMode intercept_mode, TestPartResultArray* result); // The d'tor restores the previous test part result reporter. virtual ~ScopedFakeTestPartResultReporter(); // Appends the TestPartResult object to the TestPartResultArray // received in the constructor. // // This method is from the TestPartResultReporterInterface // interface. virtual void ReportTestPartResult(const TestPartResult& result); private: void Init(); const InterceptMode intercept_mode_; TestPartResultReporterInterface* old_reporter_; TestPartResultArray* const result_; GTEST_DISALLOW_COPY_AND_ASSIGN_(ScopedFakeTestPartResultReporter); }; namespace internal { // A helper class for implementing EXPECT_FATAL_FAILURE() and // EXPECT_NONFATAL_FAILURE(). Its destructor verifies that the given // TestPartResultArray contains exactly one failure that has the given // type and contains the given substring. If that's not the case, a // non-fatal failure will be generated. class GTEST_API_ SingleFailureChecker { public: // The constructor remembers the arguments. SingleFailureChecker(const TestPartResultArray* results, TestPartResult::Type type, const string& substr); ~SingleFailureChecker(); private: const TestPartResultArray* const results_; const TestPartResult::Type type_; const string substr_; GTEST_DISALLOW_COPY_AND_ASSIGN_(SingleFailureChecker); }; } // namespace internal } // namespace testing // A set of macros for testing Google Test assertions or code that's expected // to generate Google Test fatal failures. It verifies that the given // statement will cause exactly one fatal Google Test failure with 'substr' // being part of the failure message. // // There are two different versions of this macro. EXPECT_FATAL_FAILURE only // affects and considers failures generated in the current thread and // EXPECT_FATAL_FAILURE_ON_ALL_THREADS does the same but for all threads. // // The verification of the assertion is done correctly even when the statement // throws an exception or aborts the current function. // // Known restrictions: // - 'statement' cannot reference local non-static variables or // non-static members of the current object. // - 'statement' cannot return a value. // - You cannot stream a failure message to this macro. // // Note that even though the implementations of the following two // macros are much alike, we cannot refactor them to use a common // helper macro, due to some peculiarity in how the preprocessor // works. The AcceptsMacroThatExpandsToUnprotectedComma test in // gtest_unittest.cc will fail to compile if we do that. #define EXPECT_FATAL_FAILURE(statement, substr) \ do { \ class GTestExpectFatalFailureHelper {\ public:\ static void Execute() { statement; }\ };\ ::testing::TestPartResultArray gtest_failures;\ ::testing::internal::SingleFailureChecker gtest_checker(\ >est_failures, ::testing::TestPartResult::kFatalFailure, (substr));\ {\ ::testing::ScopedFakeTestPartResultReporter gtest_reporter(\ ::testing::ScopedFakeTestPartResultReporter:: \ INTERCEPT_ONLY_CURRENT_THREAD, >est_failures);\ GTestExpectFatalFailureHelper::Execute();\ }\ } while (::testing::internal::AlwaysFalse()) #define EXPECT_FATAL_FAILURE_ON_ALL_THREADS(statement, substr) \ do { \ class GTestExpectFatalFailureHelper {\ public:\ static void Execute() { statement; }\ };\ ::testing::TestPartResultArray gtest_failures;\ ::testing::internal::SingleFailureChecker gtest_checker(\ >est_failures, ::testing::TestPartResult::kFatalFailure, (substr));\ {\ ::testing::ScopedFakeTestPartResultReporter gtest_reporter(\ ::testing::ScopedFakeTestPartResultReporter:: \ INTERCEPT_ALL_THREADS, >est_failures);\ GTestExpectFatalFailureHelper::Execute();\ }\ } while (::testing::internal::AlwaysFalse()) // A macro for testing Google Test assertions or code that's expected to // generate Google Test non-fatal failures. It asserts that the given // statement will cause exactly one non-fatal Google Test failure with 'substr' // being part of the failure message. // // There are two different versions of this macro. EXPECT_NONFATAL_FAILURE only // affects and considers failures generated in the current thread and // EXPECT_NONFATAL_FAILURE_ON_ALL_THREADS does the same but for all threads. // // 'statement' is allowed to reference local variables and members of // the current object. // // The verification of the assertion is done correctly even when the statement // throws an exception or aborts the current function. // // Known restrictions: // - You cannot stream a failure message to this macro. // // Note that even though the implementations of the following two // macros are much alike, we cannot refactor them to use a common // helper macro, due to some peculiarity in how the preprocessor // works. If we do that, the code won't compile when the user gives // EXPECT_NONFATAL_FAILURE() a statement that contains a macro that // expands to code containing an unprotected comma. The // AcceptsMacroThatExpandsToUnprotectedComma test in gtest_unittest.cc // catches that. // // For the same reason, we have to write // if (::testing::internal::AlwaysTrue()) { statement; } // instead of // GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement) // to avoid an MSVC warning on unreachable code. #define EXPECT_NONFATAL_FAILURE(statement, substr) \ do {\ ::testing::TestPartResultArray gtest_failures;\ ::testing::internal::SingleFailureChecker gtest_checker(\ >est_failures, ::testing::TestPartResult::kNonFatalFailure, \ (substr));\ {\ ::testing::ScopedFakeTestPartResultReporter gtest_reporter(\ ::testing::ScopedFakeTestPartResultReporter:: \ INTERCEPT_ONLY_CURRENT_THREAD, >est_failures);\ if (::testing::internal::AlwaysTrue()) { statement; }\ }\ } while (::testing::internal::AlwaysFalse()) #define EXPECT_NONFATAL_FAILURE_ON_ALL_THREADS(statement, substr) \ do {\ ::testing::TestPartResultArray gtest_failures;\ ::testing::internal::SingleFailureChecker gtest_checker(\ >est_failures, ::testing::TestPartResult::kNonFatalFailure, \ (substr));\ {\ ::testing::ScopedFakeTestPartResultReporter gtest_reporter(\ ::testing::ScopedFakeTestPartResultReporter::INTERCEPT_ALL_THREADS, \ >est_failures);\ if (::testing::internal::AlwaysTrue()) { statement; }\ }\ } while (::testing::internal::AlwaysFalse()) #endif // GTEST_INCLUDE_GTEST_GTEST_SPI_H_ #include #include #include #include #include #include #include #include #include #include #include #include // NOLINT #include #include #if GTEST_OS_LINUX // TODO(kenton@google.com): Use autoconf to detect availability of // gettimeofday(). # define GTEST_HAS_GETTIMEOFDAY_ 1 # include // NOLINT # include // NOLINT # include // NOLINT // Declares vsnprintf(). This header is not available on Windows. # include // NOLINT # include // NOLINT # include // NOLINT # include // NOLINT # include #elif GTEST_OS_SYMBIAN # define GTEST_HAS_GETTIMEOFDAY_ 1 # include // NOLINT #elif GTEST_OS_ZOS # define GTEST_HAS_GETTIMEOFDAY_ 1 # include // NOLINT // On z/OS we additionally need strings.h for strcasecmp. # include // NOLINT #elif GTEST_OS_WINDOWS_MOBILE // We are on Windows CE. # include // NOLINT #elif GTEST_OS_WINDOWS // We are on Windows proper. # include // NOLINT # include // NOLINT # include // NOLINT # include // NOLINT # if GTEST_OS_WINDOWS_MINGW // MinGW has gettimeofday() but not _ftime64(). // TODO(kenton@google.com): Use autoconf to detect availability of // gettimeofday(). // TODO(kenton@google.com): There are other ways to get the time on // Windows, like GetTickCount() or GetSystemTimeAsFileTime(). MinGW // supports these. consider using them instead. # define GTEST_HAS_GETTIMEOFDAY_ 1 # include // NOLINT # endif // GTEST_OS_WINDOWS_MINGW // cpplint thinks that the header is already included, so we want to // silence it. # include // NOLINT #else // Assume other platforms have gettimeofday(). // TODO(kenton@google.com): Use autoconf to detect availability of // gettimeofday(). # define GTEST_HAS_GETTIMEOFDAY_ 1 // cpplint thinks that the header is already included, so we want to // silence it. # include // NOLINT # include // NOLINT #endif // GTEST_OS_LINUX #if GTEST_HAS_EXCEPTIONS # include #endif #if GTEST_CAN_STREAM_RESULTS_ # include // NOLINT # include // NOLINT #endif // Indicates that this translation unit is part of Google Test's // implementation. It must come before gtest-internal-inl.h is // included, or there will be a compiler error. This trick is to // prevent a user from accidentally including gtest-internal-inl.h in // his code. #define GTEST_IMPLEMENTATION_ 1 // Copyright 2005, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // Utility functions and classes used by the Google C++ testing framework. // // Author: wan@google.com (Zhanyong Wan) // // This file contains purely Google Test's internal implementation. Please // DO NOT #INCLUDE IT IN A USER PROGRAM. #ifndef GTEST_SRC_GTEST_INTERNAL_INL_H_ #define GTEST_SRC_GTEST_INTERNAL_INL_H_ // GTEST_IMPLEMENTATION_ is defined to 1 iff the current translation unit is // part of Google Test's implementation; otherwise it's undefined. #if !GTEST_IMPLEMENTATION_ // A user is trying to include this from his code - just say no. # error "gtest-internal-inl.h is part of Google Test's internal implementation." # error "It must not be included except by Google Test itself." #endif // GTEST_IMPLEMENTATION_ #ifndef _WIN32_WCE # include #endif // !_WIN32_WCE #include #include // For strtoll/_strtoul64/malloc/free. #include // For memmove. #include #include #include #if GTEST_CAN_STREAM_RESULTS_ # include // NOLINT # include // NOLINT #endif #if GTEST_OS_WINDOWS # include // NOLINT #endif // GTEST_OS_WINDOWS namespace testing { // Declares the flags. // // We don't want the users to modify this flag in the code, but want // Google Test's own unit tests to be able to access it. Therefore we // declare it here as opposed to in gtest.h. GTEST_DECLARE_bool_(death_test_use_fork); namespace internal { // The value of GetTestTypeId() as seen from within the Google Test // library. This is solely for testing GetTestTypeId(). GTEST_API_ extern const TypeId kTestTypeIdInGoogleTest; // Names of the flags (needed for parsing Google Test flags). const char kAlsoRunDisabledTestsFlag[] = "also_run_disabled_tests"; const char kBreakOnFailureFlag[] = "break_on_failure"; const char kCatchExceptionsFlag[] = "catch_exceptions"; const char kColorFlag[] = "color"; const char kFilterFlag[] = "filter"; const char kListTestsFlag[] = "list_tests"; const char kOutputFlag[] = "output"; const char kPrintTimeFlag[] = "print_time"; const char kRandomSeedFlag[] = "random_seed"; const char kRepeatFlag[] = "repeat"; const char kShuffleFlag[] = "shuffle"; const char kStackTraceDepthFlag[] = "stack_trace_depth"; const char kStreamResultToFlag[] = "stream_result_to"; const char kThrowOnFailureFlag[] = "throw_on_failure"; // A valid random seed must be in [1, kMaxRandomSeed]. const int kMaxRandomSeed = 99999; // g_help_flag is true iff the --help flag or an equivalent form is // specified on the command line. GTEST_API_ extern bool g_help_flag; // Returns the current time in milliseconds. GTEST_API_ TimeInMillis GetTimeInMillis(); // Returns true iff Google Test should use colors in the output. GTEST_API_ bool ShouldUseColor(bool stdout_is_tty); // Formats the given time in milliseconds as seconds. GTEST_API_ std::string FormatTimeInMillisAsSeconds(TimeInMillis ms); // Converts the given time in milliseconds to a date string in the ISO 8601 // format, without the timezone information. N.B.: due to the use the // non-reentrant localtime() function, this function is not thread safe. Do // not use it in any code that can be called from multiple threads. GTEST_API_ std::string FormatEpochTimeInMillisAsIso8601(TimeInMillis ms); // Parses a string for an Int32 flag, in the form of "--flag=value". // // On success, stores the value of the flag in *value, and returns // true. On failure, returns false without changing *value. GTEST_API_ bool ParseInt32Flag( const char* str, const char* flag, Int32* value); // Returns a random seed in range [1, kMaxRandomSeed] based on the // given --gtest_random_seed flag value. inline int GetRandomSeedFromFlag(Int32 random_seed_flag) { const unsigned int raw_seed = (random_seed_flag == 0) ? static_cast(GetTimeInMillis()) : static_cast(random_seed_flag); // Normalizes the actual seed to range [1, kMaxRandomSeed] such that // it's easy to type. const int normalized_seed = static_cast((raw_seed - 1U) % static_cast(kMaxRandomSeed)) + 1; return normalized_seed; } // Returns the first valid random seed after 'seed'. The behavior is // undefined if 'seed' is invalid. The seed after kMaxRandomSeed is // considered to be 1. inline int GetNextRandomSeed(int seed) { GTEST_CHECK_(1 <= seed && seed <= kMaxRandomSeed) << "Invalid random seed " << seed << " - must be in [1, " << kMaxRandomSeed << "]."; const int next_seed = seed + 1; return (next_seed > kMaxRandomSeed) ? 1 : next_seed; } // This class saves the values of all Google Test flags in its c'tor, and // restores them in its d'tor. class GTestFlagSaver { public: // The c'tor. GTestFlagSaver() { also_run_disabled_tests_ = GTEST_FLAG(also_run_disabled_tests); break_on_failure_ = GTEST_FLAG(break_on_failure); catch_exceptions_ = GTEST_FLAG(catch_exceptions); color_ = GTEST_FLAG(color); death_test_style_ = GTEST_FLAG(death_test_style); death_test_use_fork_ = GTEST_FLAG(death_test_use_fork); filter_ = GTEST_FLAG(filter); internal_run_death_test_ = GTEST_FLAG(internal_run_death_test); list_tests_ = GTEST_FLAG(list_tests); output_ = GTEST_FLAG(output); print_time_ = GTEST_FLAG(print_time); random_seed_ = GTEST_FLAG(random_seed); repeat_ = GTEST_FLAG(repeat); shuffle_ = GTEST_FLAG(shuffle); stack_trace_depth_ = GTEST_FLAG(stack_trace_depth); stream_result_to_ = GTEST_FLAG(stream_result_to); throw_on_failure_ = GTEST_FLAG(throw_on_failure); } // The d'tor is not virtual. DO NOT INHERIT FROM THIS CLASS. ~GTestFlagSaver() { GTEST_FLAG(also_run_disabled_tests) = also_run_disabled_tests_; GTEST_FLAG(break_on_failure) = break_on_failure_; GTEST_FLAG(catch_exceptions) = catch_exceptions_; GTEST_FLAG(color) = color_; GTEST_FLAG(death_test_style) = death_test_style_; GTEST_FLAG(death_test_use_fork) = death_test_use_fork_; GTEST_FLAG(filter) = filter_; GTEST_FLAG(internal_run_death_test) = internal_run_death_test_; GTEST_FLAG(list_tests) = list_tests_; GTEST_FLAG(output) = output_; GTEST_FLAG(print_time) = print_time_; GTEST_FLAG(random_seed) = random_seed_; GTEST_FLAG(repeat) = repeat_; GTEST_FLAG(shuffle) = shuffle_; GTEST_FLAG(stack_trace_depth) = stack_trace_depth_; GTEST_FLAG(stream_result_to) = stream_result_to_; GTEST_FLAG(throw_on_failure) = throw_on_failure_; } private: // Fields for saving the original values of flags. bool also_run_disabled_tests_; bool break_on_failure_; bool catch_exceptions_; std::string color_; std::string death_test_style_; bool death_test_use_fork_; std::string filter_; std::string internal_run_death_test_; bool list_tests_; std::string output_; bool print_time_; internal::Int32 random_seed_; internal::Int32 repeat_; bool shuffle_; internal::Int32 stack_trace_depth_; std::string stream_result_to_; bool throw_on_failure_; } GTEST_ATTRIBUTE_UNUSED_; // Converts a Unicode code point to a narrow string in UTF-8 encoding. // code_point parameter is of type UInt32 because wchar_t may not be // wide enough to contain a code point. // If the code_point is not a valid Unicode code point // (i.e. outside of Unicode range U+0 to U+10FFFF) it will be converted // to "(Invalid Unicode 0xXXXXXXXX)". GTEST_API_ std::string CodePointToUtf8(UInt32 code_point); // Converts a wide string to a narrow string in UTF-8 encoding. // The wide string is assumed to have the following encoding: // UTF-16 if sizeof(wchar_t) == 2 (on Windows, Cygwin, Symbian OS) // UTF-32 if sizeof(wchar_t) == 4 (on Linux) // Parameter str points to a null-terminated wide string. // Parameter num_chars may additionally limit the number // of wchar_t characters processed. -1 is used when the entire string // should be processed. // If the string contains code points that are not valid Unicode code points // (i.e. outside of Unicode range U+0 to U+10FFFF) they will be output // as '(Invalid Unicode 0xXXXXXXXX)'. If the string is in UTF16 encoding // and contains invalid UTF-16 surrogate pairs, values in those pairs // will be encoded as individual Unicode characters from Basic Normal Plane. GTEST_API_ std::string WideStringToUtf8(const wchar_t* str, int num_chars); // Reads the GTEST_SHARD_STATUS_FILE environment variable, and creates the file // if the variable is present. If a file already exists at this location, this // function will write over it. If the variable is present, but the file cannot // be created, prints an error and exits. void WriteToShardStatusFileIfNeeded(); // Checks whether sharding is enabled by examining the relevant // environment variable values. If the variables are present, // but inconsistent (e.g., shard_index >= total_shards), prints // an error and exits. If in_subprocess_for_death_test, sharding is // disabled because it must only be applied to the original test // process. Otherwise, we could filter out death tests we intended to execute. GTEST_API_ bool ShouldShard(const char* total_shards_str, const char* shard_index_str, bool in_subprocess_for_death_test); // Parses the environment variable var as an Int32. If it is unset, // returns default_val. If it is not an Int32, prints an error and // and aborts. GTEST_API_ Int32 Int32FromEnvOrDie(const char* env_var, Int32 default_val); // Given the total number of shards, the shard index, and the test id, // returns true iff the test should be run on this shard. The test id is // some arbitrary but unique non-negative integer assigned to each test // method. Assumes that 0 <= shard_index < total_shards. GTEST_API_ bool ShouldRunTestOnShard( int total_shards, int shard_index, int test_id); // STL container utilities. // Returns the number of elements in the given container that satisfy // the given predicate. template inline int CountIf(const Container& c, Predicate predicate) { // Implemented as an explicit loop since std::count_if() in libCstd on // Solaris has a non-standard signature. int count = 0; for (typename Container::const_iterator it = c.begin(); it != c.end(); ++it) { if (predicate(*it)) ++count; } return count; } // Applies a function/functor to each element in the container. template void ForEach(const Container& c, Functor functor) { std::for_each(c.begin(), c.end(), functor); } // Returns the i-th element of the vector, or default_value if i is not // in range [0, v.size()). template inline E GetElementOr(const std::vector& v, int i, E default_value) { return (i < 0 || i >= static_cast(v.size())) ? default_value : v[i]; } // Performs an in-place shuffle of a range of the vector's elements. // 'begin' and 'end' are element indices as an STL-style range; // i.e. [begin, end) are shuffled, where 'end' == size() means to // shuffle to the end of the vector. template void ShuffleRange(internal::Random* random, int begin, int end, std::vector* v) { const int size = static_cast(v->size()); GTEST_CHECK_(0 <= begin && begin <= size) << "Invalid shuffle range start " << begin << ": must be in range [0, " << size << "]."; GTEST_CHECK_(begin <= end && end <= size) << "Invalid shuffle range finish " << end << ": must be in range [" << begin << ", " << size << "]."; // Fisher-Yates shuffle, from // http://en.wikipedia.org/wiki/Fisher-Yates_shuffle for (int range_width = end - begin; range_width >= 2; range_width--) { const int last_in_range = begin + range_width - 1; const int selected = begin + random->Generate(range_width); std::swap((*v)[selected], (*v)[last_in_range]); } } // Performs an in-place shuffle of the vector's elements. template inline void Shuffle(internal::Random* random, std::vector* v) { ShuffleRange(random, 0, static_cast(v->size()), v); } // A function for deleting an object. Handy for being used as a // functor. template static void Delete(T* x) { delete x; } // A predicate that checks the key of a TestProperty against a known key. // // TestPropertyKeyIs is copyable. class TestPropertyKeyIs { public: // Constructor. // // TestPropertyKeyIs has NO default constructor. explicit TestPropertyKeyIs(const std::string& key) : key_(key) {} // Returns true iff the test name of test property matches on key_. bool operator()(const TestProperty& test_property) const { return test_property.key() == key_; } private: std::string key_; }; // Class UnitTestOptions. // // This class contains functions for processing options the user // specifies when running the tests. It has only static members. // // In most cases, the user can specify an option using either an // environment variable or a command line flag. E.g. you can set the // test filter using either GTEST_FILTER or --gtest_filter. If both // the variable and the flag are present, the latter overrides the // former. class GTEST_API_ UnitTestOptions { public: // Functions for processing the gtest_output flag. // Returns the output format, or "" for normal printed output. static std::string GetOutputFormat(); // Returns the absolute path of the requested output file, or the // default (test_detail.xml in the original working directory) if // none was explicitly specified. static std::string GetAbsolutePathToOutputFile(); // Functions for processing the gtest_filter flag. // Returns true iff the wildcard pattern matches the string. The // first ':' or '\0' character in pattern marks the end of it. // // This recursive algorithm isn't very efficient, but is clear and // works well enough for matching test names, which are short. static bool PatternMatchesString(const char *pattern, const char *str); // Returns true iff the user-specified filter matches the test case // name and the test name. static bool FilterMatchesTest(const std::string &test_case_name, const std::string &test_name); #if GTEST_OS_WINDOWS // Function for supporting the gtest_catch_exception flag. // Returns EXCEPTION_EXECUTE_HANDLER if Google Test should handle the // given SEH exception, or EXCEPTION_CONTINUE_SEARCH otherwise. // This function is useful as an __except condition. static int GTestShouldProcessSEH(DWORD exception_code); #endif // GTEST_OS_WINDOWS // Returns true if "name" matches the ':' separated list of glob-style // filters in "filter". static bool MatchesFilter(const std::string& name, const char* filter); }; // Returns the current application's name, removing directory path if that // is present. Used by UnitTestOptions::GetOutputFile. GTEST_API_ FilePath GetCurrentExecutableName(); // The role interface for getting the OS stack trace as a string. class OsStackTraceGetterInterface { public: OsStackTraceGetterInterface() {} virtual ~OsStackTraceGetterInterface() {} // Returns the current OS stack trace as an std::string. Parameters: // // max_depth - the maximum number of stack frames to be included // in the trace. // skip_count - the number of top frames to be skipped; doesn't count // against max_depth. virtual string CurrentStackTrace(int max_depth, int skip_count) = 0; // UponLeavingGTest() should be called immediately before Google Test calls // user code. It saves some information about the current stack that // CurrentStackTrace() will use to find and hide Google Test stack frames. virtual void UponLeavingGTest() = 0; private: GTEST_DISALLOW_COPY_AND_ASSIGN_(OsStackTraceGetterInterface); }; // A working implementation of the OsStackTraceGetterInterface interface. class OsStackTraceGetter : public OsStackTraceGetterInterface { public: OsStackTraceGetter() : caller_frame_(NULL) {} virtual string CurrentStackTrace(int max_depth, int skip_count) GTEST_LOCK_EXCLUDED_(mutex_); virtual void UponLeavingGTest() GTEST_LOCK_EXCLUDED_(mutex_); // This string is inserted in place of stack frames that are part of // Google Test's implementation. static const char* const kElidedFramesMarker; private: Mutex mutex_; // protects all internal state // We save the stack frame below the frame that calls user code. // We do this because the address of the frame immediately below // the user code changes between the call to UponLeavingGTest() // and any calls to CurrentStackTrace() from within the user code. void* caller_frame_; GTEST_DISALLOW_COPY_AND_ASSIGN_(OsStackTraceGetter); }; // Information about a Google Test trace point. struct TraceInfo { const char* file; int line; std::string message; }; // This is the default global test part result reporter used in UnitTestImpl. // This class should only be used by UnitTestImpl. class DefaultGlobalTestPartResultReporter : public TestPartResultReporterInterface { public: explicit DefaultGlobalTestPartResultReporter(UnitTestImpl* unit_test); // Implements the TestPartResultReporterInterface. Reports the test part // result in the current test. virtual void ReportTestPartResult(const TestPartResult& result); private: UnitTestImpl* const unit_test_; GTEST_DISALLOW_COPY_AND_ASSIGN_(DefaultGlobalTestPartResultReporter); }; // This is the default per thread test part result reporter used in // UnitTestImpl. This class should only be used by UnitTestImpl. class DefaultPerThreadTestPartResultReporter : public TestPartResultReporterInterface { public: explicit DefaultPerThreadTestPartResultReporter(UnitTestImpl* unit_test); // Implements the TestPartResultReporterInterface. The implementation just // delegates to the current global test part result reporter of *unit_test_. virtual void ReportTestPartResult(const TestPartResult& result); private: UnitTestImpl* const unit_test_; GTEST_DISALLOW_COPY_AND_ASSIGN_(DefaultPerThreadTestPartResultReporter); }; // The private implementation of the UnitTest class. We don't protect // the methods under a mutex, as this class is not accessible by a // user and the UnitTest class that delegates work to this class does // proper locking. class GTEST_API_ UnitTestImpl { public: explicit UnitTestImpl(UnitTest* parent); virtual ~UnitTestImpl(); // There are two different ways to register your own TestPartResultReporter. // You can register your own repoter to listen either only for test results // from the current thread or for results from all threads. // By default, each per-thread test result repoter just passes a new // TestPartResult to the global test result reporter, which registers the // test part result for the currently running test. // Returns the global test part result reporter. TestPartResultReporterInterface* GetGlobalTestPartResultReporter(); // Sets the global test part result reporter. void SetGlobalTestPartResultReporter( TestPartResultReporterInterface* reporter); // Returns the test part result reporter for the current thread. TestPartResultReporterInterface* GetTestPartResultReporterForCurrentThread(); // Sets the test part result reporter for the current thread. void SetTestPartResultReporterForCurrentThread( TestPartResultReporterInterface* reporter); // Gets the number of successful test cases. int successful_test_case_count() const; // Gets the number of failed test cases. int failed_test_case_count() const; // Gets the number of all test cases. int total_test_case_count() const; // Gets the number of all test cases that contain at least one test // that should run. int test_case_to_run_count() const; // Gets the number of successful tests. int successful_test_count() const; // Gets the number of failed tests. int failed_test_count() const; // Gets the number of disabled tests that will be reported in the XML report. int reportable_disabled_test_count() const; // Gets the number of disabled tests. int disabled_test_count() const; // Gets the number of tests to be printed in the XML report. int reportable_test_count() const; // Gets the number of all tests. int total_test_count() const; // Gets the number of tests that should run. int test_to_run_count() const; // Gets the time of the test program start, in ms from the start of the // UNIX epoch. TimeInMillis start_timestamp() const { return start_timestamp_; } // Gets the elapsed time, in milliseconds. TimeInMillis elapsed_time() const { return elapsed_time_; } // Returns true iff the unit test passed (i.e. all test cases passed). bool Passed() const { return !Failed(); } // Returns true iff the unit test failed (i.e. some test case failed // or something outside of all tests failed). bool Failed() const { return failed_test_case_count() > 0 || ad_hoc_test_result()->Failed(); } // Gets the i-th test case among all the test cases. i can range from 0 to // total_test_case_count() - 1. If i is not in that range, returns NULL. const TestCase* GetTestCase(int i) const { const int index = GetElementOr(test_case_indices_, i, -1); return index < 0 ? NULL : test_cases_[i]; } // Gets the i-th test case among all the test cases. i can range from 0 to // total_test_case_count() - 1. If i is not in that range, returns NULL. TestCase* GetMutableTestCase(int i) { const int index = GetElementOr(test_case_indices_, i, -1); return index < 0 ? NULL : test_cases_[index]; } // Provides access to the event listener list. TestEventListeners* listeners() { return &listeners_; } // Returns the TestResult for the test that's currently running, or // the TestResult for the ad hoc test if no test is running. TestResult* current_test_result(); // Returns the TestResult for the ad hoc test. const TestResult* ad_hoc_test_result() const { return &ad_hoc_test_result_; } // Sets the OS stack trace getter. // // Does nothing if the input and the current OS stack trace getter // are the same; otherwise, deletes the old getter and makes the // input the current getter. void set_os_stack_trace_getter(OsStackTraceGetterInterface* getter); // Returns the current OS stack trace getter if it is not NULL; // otherwise, creates an OsStackTraceGetter, makes it the current // getter, and returns it. OsStackTraceGetterInterface* os_stack_trace_getter(); // Returns the current OS stack trace as an std::string. // // The maximum number of stack frames to be included is specified by // the gtest_stack_trace_depth flag. The skip_count parameter // specifies the number of top frames to be skipped, which doesn't // count against the number of frames to be included. // // For example, if Foo() calls Bar(), which in turn calls // CurrentOsStackTraceExceptTop(1), Foo() will be included in the // trace but Bar() and CurrentOsStackTraceExceptTop() won't. std::string CurrentOsStackTraceExceptTop(int skip_count) GTEST_NO_INLINE_; // Finds and returns a TestCase with the given name. If one doesn't // exist, creates one and returns it. // // Arguments: // // test_case_name: name of the test case // type_param: the name of the test's type parameter, or NULL if // this is not a typed or a type-parameterized test. // set_up_tc: pointer to the function that sets up the test case // tear_down_tc: pointer to the function that tears down the test case TestCase* GetTestCase(const char* test_case_name, const char* type_param, Test::SetUpTestCaseFunc set_up_tc, Test::TearDownTestCaseFunc tear_down_tc); // Adds a TestInfo to the unit test. // // Arguments: // // set_up_tc: pointer to the function that sets up the test case // tear_down_tc: pointer to the function that tears down the test case // test_info: the TestInfo object void AddTestInfo(Test::SetUpTestCaseFunc set_up_tc, Test::TearDownTestCaseFunc tear_down_tc, TestInfo* test_info) { // In order to support thread-safe death tests, we need to // remember the original working directory when the test program // was first invoked. We cannot do this in RUN_ALL_TESTS(), as // the user may have changed the current directory before calling // RUN_ALL_TESTS(). Therefore we capture the current directory in // AddTestInfo(), which is called to register a TEST or TEST_F // before main() is reached. if (original_working_dir_.IsEmpty()) { original_working_dir_.Set(FilePath::GetCurrentDir()); GTEST_CHECK_(!original_working_dir_.IsEmpty()) << "Failed to get the current working directory."; } GetTestCase(test_info->test_case_name(), test_info->type_param(), set_up_tc, tear_down_tc)->AddTestInfo(test_info); } #if GTEST_HAS_PARAM_TEST // Returns ParameterizedTestCaseRegistry object used to keep track of // value-parameterized tests and instantiate and register them. internal::ParameterizedTestCaseRegistry& parameterized_test_registry() { return parameterized_test_registry_; } #endif // GTEST_HAS_PARAM_TEST // Sets the TestCase object for the test that's currently running. void set_current_test_case(TestCase* a_current_test_case) { current_test_case_ = a_current_test_case; } // Sets the TestInfo object for the test that's currently running. If // current_test_info is NULL, the assertion results will be stored in // ad_hoc_test_result_. void set_current_test_info(TestInfo* a_current_test_info) { current_test_info_ = a_current_test_info; } // Registers all parameterized tests defined using TEST_P and // INSTANTIATE_TEST_CASE_P, creating regular tests for each test/parameter // combination. This method can be called more then once; it has guards // protecting from registering the tests more then once. If // value-parameterized tests are disabled, RegisterParameterizedTests is // present but does nothing. void RegisterParameterizedTests(); // Runs all tests in this UnitTest object, prints the result, and // returns true if all tests are successful. If any exception is // thrown during a test, this test is considered to be failed, but // the rest of the tests will still be run. bool RunAllTests(); // Clears the results of all tests, except the ad hoc tests. void ClearNonAdHocTestResult() { ForEach(test_cases_, TestCase::ClearTestCaseResult); } // Clears the results of ad-hoc test assertions. void ClearAdHocTestResult() { ad_hoc_test_result_.Clear(); } // Adds a TestProperty to the current TestResult object when invoked in a // context of a test or a test case, or to the global property set. If the // result already contains a property with the same key, the value will be // updated. void RecordProperty(const TestProperty& test_property); enum ReactionToSharding { HONOR_SHARDING_PROTOCOL, IGNORE_SHARDING_PROTOCOL }; // Matches the full name of each test against the user-specified // filter to decide whether the test should run, then records the // result in each TestCase and TestInfo object. // If shard_tests == HONOR_SHARDING_PROTOCOL, further filters tests // based on sharding variables in the environment. // Returns the number of tests that should run. int FilterTests(ReactionToSharding shard_tests); // Prints the names of the tests matching the user-specified filter flag. void ListTestsMatchingFilter(); const TestCase* current_test_case() const { return current_test_case_; } TestInfo* current_test_info() { return current_test_info_; } const TestInfo* current_test_info() const { return current_test_info_; } // Returns the vector of environments that need to be set-up/torn-down // before/after the tests are run. std::vector& environments() { return environments_; } // Getters for the per-thread Google Test trace stack. std::vector& gtest_trace_stack() { return *(gtest_trace_stack_.pointer()); } const std::vector& gtest_trace_stack() const { return gtest_trace_stack_.get(); } #if GTEST_HAS_DEATH_TEST void InitDeathTestSubprocessControlInfo() { internal_run_death_test_flag_.reset(ParseInternalRunDeathTestFlag()); } // Returns a pointer to the parsed --gtest_internal_run_death_test // flag, or NULL if that flag was not specified. // This information is useful only in a death test child process. // Must not be called before a call to InitGoogleTest. const InternalRunDeathTestFlag* internal_run_death_test_flag() const { return internal_run_death_test_flag_.get(); } // Returns a pointer to the current death test factory. internal::DeathTestFactory* death_test_factory() { return death_test_factory_.get(); } void SuppressTestEventsIfInSubprocess(); friend class ReplaceDeathTestFactory; #endif // GTEST_HAS_DEATH_TEST // Initializes the event listener performing XML output as specified by // UnitTestOptions. Must not be called before InitGoogleTest. void ConfigureXmlOutput(); #if GTEST_CAN_STREAM_RESULTS_ // Initializes the event listener for streaming test results to a socket. // Must not be called before InitGoogleTest. void ConfigureStreamingOutput(); #endif // Performs initialization dependent upon flag values obtained in // ParseGoogleTestFlagsOnly. Is called from InitGoogleTest after the call to // ParseGoogleTestFlagsOnly. In case a user neglects to call InitGoogleTest // this function is also called from RunAllTests. Since this function can be // called more than once, it has to be idempotent. void PostFlagParsingInit(); // Gets the random seed used at the start of the current test iteration. int random_seed() const { return random_seed_; } // Gets the random number generator. internal::Random* random() { return &random_; } // Shuffles all test cases, and the tests within each test case, // making sure that death tests are still run first. void ShuffleTests(); // Restores the test cases and tests to their order before the first shuffle. void UnshuffleTests(); // Returns the value of GTEST_FLAG(catch_exceptions) at the moment // UnitTest::Run() starts. bool catch_exceptions() const { return catch_exceptions_; } private: friend class ::testing::UnitTest; // Used by UnitTest::Run() to capture the state of // GTEST_FLAG(catch_exceptions) at the moment it starts. void set_catch_exceptions(bool value) { catch_exceptions_ = value; } // The UnitTest object that owns this implementation object. UnitTest* const parent_; // The working directory when the first TEST() or TEST_F() was // executed. internal::FilePath original_working_dir_; // The default test part result reporters. DefaultGlobalTestPartResultReporter default_global_test_part_result_reporter_; DefaultPerThreadTestPartResultReporter default_per_thread_test_part_result_reporter_; // Points to (but doesn't own) the global test part result reporter. TestPartResultReporterInterface* global_test_part_result_repoter_; // Protects read and write access to global_test_part_result_reporter_. internal::Mutex global_test_part_result_reporter_mutex_; // Points to (but doesn't own) the per-thread test part result reporter. internal::ThreadLocal per_thread_test_part_result_reporter_; // The vector of environments that need to be set-up/torn-down // before/after the tests are run. std::vector environments_; // The vector of TestCases in their original order. It owns the // elements in the vector. std::vector test_cases_; // Provides a level of indirection for the test case list to allow // easy shuffling and restoring the test case order. The i-th // element of this vector is the index of the i-th test case in the // shuffled order. std::vector test_case_indices_; #if GTEST_HAS_PARAM_TEST // ParameterizedTestRegistry object used to register value-parameterized // tests. internal::ParameterizedTestCaseRegistry parameterized_test_registry_; // Indicates whether RegisterParameterizedTests() has been called already. bool parameterized_tests_registered_; #endif // GTEST_HAS_PARAM_TEST // Index of the last death test case registered. Initially -1. int last_death_test_case_; // This points to the TestCase for the currently running test. It // changes as Google Test goes through one test case after another. // When no test is running, this is set to NULL and Google Test // stores assertion results in ad_hoc_test_result_. Initially NULL. TestCase* current_test_case_; // This points to the TestInfo for the currently running test. It // changes as Google Test goes through one test after another. When // no test is running, this is set to NULL and Google Test stores // assertion results in ad_hoc_test_result_. Initially NULL. TestInfo* current_test_info_; // Normally, a user only writes assertions inside a TEST or TEST_F, // or inside a function called by a TEST or TEST_F. Since Google // Test keeps track of which test is current running, it can // associate such an assertion with the test it belongs to. // // If an assertion is encountered when no TEST or TEST_F is running, // Google Test attributes the assertion result to an imaginary "ad hoc" // test, and records the result in ad_hoc_test_result_. TestResult ad_hoc_test_result_; // The list of event listeners that can be used to track events inside // Google Test. TestEventListeners listeners_; // The OS stack trace getter. Will be deleted when the UnitTest // object is destructed. By default, an OsStackTraceGetter is used, // but the user can set this field to use a custom getter if that is // desired. OsStackTraceGetterInterface* os_stack_trace_getter_; // True iff PostFlagParsingInit() has been called. bool post_flag_parse_init_performed_; // The random number seed used at the beginning of the test run. int random_seed_; // Our random number generator. internal::Random random_; // The time of the test program start, in ms from the start of the // UNIX epoch. TimeInMillis start_timestamp_; // How long the test took to run, in milliseconds. TimeInMillis elapsed_time_; #if GTEST_HAS_DEATH_TEST // The decomposed components of the gtest_internal_run_death_test flag, // parsed when RUN_ALL_TESTS is called. internal::scoped_ptr internal_run_death_test_flag_; internal::scoped_ptr death_test_factory_; #endif // GTEST_HAS_DEATH_TEST // A per-thread stack of traces created by the SCOPED_TRACE() macro. internal::ThreadLocal > gtest_trace_stack_; // The value of GTEST_FLAG(catch_exceptions) at the moment RunAllTests() // starts. bool catch_exceptions_; GTEST_DISALLOW_COPY_AND_ASSIGN_(UnitTestImpl); }; // class UnitTestImpl // Convenience function for accessing the global UnitTest // implementation object. inline UnitTestImpl* GetUnitTestImpl() { return UnitTest::GetInstance()->impl(); } #if GTEST_USES_SIMPLE_RE // Internal helper functions for implementing the simple regular // expression matcher. GTEST_API_ bool IsInSet(char ch, const char* str); GTEST_API_ bool IsAsciiDigit(char ch); GTEST_API_ bool IsAsciiPunct(char ch); GTEST_API_ bool IsRepeat(char ch); GTEST_API_ bool IsAsciiWhiteSpace(char ch); GTEST_API_ bool IsAsciiWordChar(char ch); GTEST_API_ bool IsValidEscape(char ch); GTEST_API_ bool AtomMatchesChar(bool escaped, char pattern, char ch); GTEST_API_ bool ValidateRegex(const char* regex); GTEST_API_ bool MatchRegexAtHead(const char* regex, const char* str); GTEST_API_ bool MatchRepetitionAndRegexAtHead( bool escaped, char ch, char repeat, const char* regex, const char* str); GTEST_API_ bool MatchRegexAnywhere(const char* regex, const char* str); #endif // GTEST_USES_SIMPLE_RE // Parses the command line for Google Test flags, without initializing // other parts of Google Test. GTEST_API_ void ParseGoogleTestFlagsOnly(int* argc, char** argv); GTEST_API_ void ParseGoogleTestFlagsOnly(int* argc, wchar_t** argv); #if GTEST_HAS_DEATH_TEST // Returns the message describing the last system error, regardless of the // platform. GTEST_API_ std::string GetLastErrnoDescription(); # if GTEST_OS_WINDOWS // Provides leak-safe Windows kernel handle ownership. class AutoHandle { public: AutoHandle() : handle_(INVALID_HANDLE_VALUE) {} explicit AutoHandle(HANDLE handle) : handle_(handle) {} ~AutoHandle() { Reset(); } HANDLE Get() const { return handle_; } void Reset() { Reset(INVALID_HANDLE_VALUE); } void Reset(HANDLE handle) { if (handle != handle_) { if (handle_ != INVALID_HANDLE_VALUE) ::CloseHandle(handle_); handle_ = handle; } } private: HANDLE handle_; GTEST_DISALLOW_COPY_AND_ASSIGN_(AutoHandle); }; # endif // GTEST_OS_WINDOWS // Attempts to parse a string into a positive integer pointed to by the // number parameter. Returns true if that is possible. // GTEST_HAS_DEATH_TEST implies that we have ::std::string, so we can use // it here. template bool ParseNaturalNumber(const ::std::string& str, Integer* number) { // Fail fast if the given string does not begin with a digit; // this bypasses strtoXXX's "optional leading whitespace and plus // or minus sign" semantics, which are undesirable here. if (str.empty() || !IsDigit(str[0])) { return false; } errno = 0; char* end; // BiggestConvertible is the largest integer type that system-provided // string-to-number conversion routines can return. # if GTEST_OS_WINDOWS && !defined(__GNUC__) // MSVC and C++ Builder define __int64 instead of the standard long long. typedef unsigned __int64 BiggestConvertible; const BiggestConvertible parsed = _strtoui64(str.c_str(), &end, 10); # else typedef unsigned long long BiggestConvertible; // NOLINT const BiggestConvertible parsed = strtoull(str.c_str(), &end, 10); # endif // GTEST_OS_WINDOWS && !defined(__GNUC__) const bool parse_success = *end == '\0' && errno == 0; // TODO(vladl@google.com): Convert this to compile time assertion when it is // available. GTEST_CHECK_(sizeof(Integer) <= sizeof(parsed)); const Integer result = static_cast(parsed); if (parse_success && static_cast(result) == parsed) { *number = result; return true; } return false; } #endif // GTEST_HAS_DEATH_TEST // TestResult contains some private methods that should be hidden from // Google Test user but are required for testing. This class allow our tests // to access them. // // This class is supplied only for the purpose of testing Google Test's own // constructs. Do not use it in user tests, either directly or indirectly. class TestResultAccessor { public: static void RecordProperty(TestResult* test_result, const std::string& xml_element, const TestProperty& property) { test_result->RecordProperty(xml_element, property); } static void ClearTestPartResults(TestResult* test_result) { test_result->ClearTestPartResults(); } static const std::vector& test_part_results( const TestResult& test_result) { return test_result.test_part_results(); } }; #if GTEST_CAN_STREAM_RESULTS_ // Streams test results to the given port on the given host machine. class StreamingListener : public EmptyTestEventListener { public: // Abstract base class for writing strings to a socket. class AbstractSocketWriter { public: virtual ~AbstractSocketWriter() {} // Sends a string to the socket. virtual void Send(const string& message) = 0; // Closes the socket. virtual void CloseConnection() {} // Sends a string and a newline to the socket. void SendLn(const string& message) { Send(message + "\n"); } }; // Concrete class for actually writing strings to a socket. class SocketWriter : public AbstractSocketWriter { public: SocketWriter(const string& host, const string& port) : sockfd_(-1), host_name_(host), port_num_(port) { MakeConnection(); } virtual ~SocketWriter() { if (sockfd_ != -1) CloseConnection(); } // Sends a string to the socket. virtual void Send(const string& message) { GTEST_CHECK_(sockfd_ != -1) << "Send() can be called only when there is a connection."; const int len = static_cast(message.length()); if (write(sockfd_, message.c_str(), len) != len) { GTEST_LOG_(WARNING) << "stream_result_to: failed to stream to " << host_name_ << ":" << port_num_; } } private: // Creates a client socket and connects to the server. void MakeConnection(); // Closes the socket. void CloseConnection() { GTEST_CHECK_(sockfd_ != -1) << "CloseConnection() can be called only when there is a connection."; close(sockfd_); sockfd_ = -1; } int sockfd_; // socket file descriptor const string host_name_; const string port_num_; GTEST_DISALLOW_COPY_AND_ASSIGN_(SocketWriter); }; // class SocketWriter // Escapes '=', '&', '%', and '\n' characters in str as "%xx". static string UrlEncode(const char* str); StreamingListener(const string& host, const string& port) : socket_writer_(new SocketWriter(host, port)) { Start(); } explicit StreamingListener(AbstractSocketWriter* socket_writer) : socket_writer_(socket_writer) { Start(); } void OnTestProgramStart(const UnitTest& /* unit_test */) { SendLn("event=TestProgramStart"); } void OnTestProgramEnd(const UnitTest& unit_test) { // Note that Google Test current only report elapsed time for each // test iteration, not for the entire test program. SendLn("event=TestProgramEnd&passed=" + FormatBool(unit_test.Passed())); // Notify the streaming server to stop. socket_writer_->CloseConnection(); } void OnTestIterationStart(const UnitTest& /* unit_test */, int iteration) { SendLn("event=TestIterationStart&iteration=" + StreamableToString(iteration)); } void OnTestIterationEnd(const UnitTest& unit_test, int /* iteration */) { SendLn("event=TestIterationEnd&passed=" + FormatBool(unit_test.Passed()) + "&elapsed_time=" + StreamableToString(unit_test.elapsed_time()) + "ms"); } void OnTestCaseStart(const TestCase& test_case) { SendLn(std::string("event=TestCaseStart&name=") + test_case.name()); } void OnTestCaseEnd(const TestCase& test_case) { SendLn("event=TestCaseEnd&passed=" + FormatBool(test_case.Passed()) + "&elapsed_time=" + StreamableToString(test_case.elapsed_time()) + "ms"); } void OnTestStart(const TestInfo& test_info) { SendLn(std::string("event=TestStart&name=") + test_info.name()); } void OnTestEnd(const TestInfo& test_info) { SendLn("event=TestEnd&passed=" + FormatBool((test_info.result())->Passed()) + "&elapsed_time=" + StreamableToString((test_info.result())->elapsed_time()) + "ms"); } void OnTestPartResult(const TestPartResult& test_part_result) { const char* file_name = test_part_result.file_name(); if (file_name == NULL) file_name = ""; SendLn("event=TestPartResult&file=" + UrlEncode(file_name) + "&line=" + StreamableToString(test_part_result.line_number()) + "&message=" + UrlEncode(test_part_result.message())); } private: // Sends the given message and a newline to the socket. void SendLn(const string& message) { socket_writer_->SendLn(message); } // Called at the start of streaming to notify the receiver what // protocol we are using. void Start() { SendLn("gtest_streaming_protocol_version=1.0"); } string FormatBool(bool value) { return value ? "1" : "0"; } const scoped_ptr socket_writer_; GTEST_DISALLOW_COPY_AND_ASSIGN_(StreamingListener); }; // class StreamingListener #endif // GTEST_CAN_STREAM_RESULTS_ } // namespace internal } // namespace testing #endif // GTEST_SRC_GTEST_INTERNAL_INL_H_ #undef GTEST_IMPLEMENTATION_ #if GTEST_OS_WINDOWS # define vsnprintf _vsnprintf #endif // GTEST_OS_WINDOWS namespace testing { using internal::CountIf; using internal::ForEach; using internal::GetElementOr; using internal::Shuffle; // Constants. // A test whose test case name or test name matches this filter is // disabled and not run. static const char kDisableTestFilter[] = "DISABLED_*:*/DISABLED_*"; // A test case whose name matches this filter is considered a death // test case and will be run before test cases whose name doesn't // match this filter. static const char kDeathTestCaseFilter[] = "*DeathTest:*DeathTest/*"; // A test filter that matches everything. static const char kUniversalFilter[] = "*"; // The default output file for XML output. static const char kDefaultOutputFile[] = "test_detail.xml"; // The environment variable name for the test shard index. static const char kTestShardIndex[] = "GTEST_SHARD_INDEX"; // The environment variable name for the total number of test shards. static const char kTestTotalShards[] = "GTEST_TOTAL_SHARDS"; // The environment variable name for the test shard status file. static const char kTestShardStatusFile[] = "GTEST_SHARD_STATUS_FILE"; namespace internal { // The text used in failure messages to indicate the start of the // stack trace. const char kStackTraceMarker[] = "\nStack trace:\n"; // g_help_flag is true iff the --help flag or an equivalent form is // specified on the command line. bool g_help_flag = false; } // namespace internal static const char* GetDefaultFilter() { return kUniversalFilter; } GTEST_DEFINE_bool_( also_run_disabled_tests, internal::BoolFromGTestEnv("also_run_disabled_tests", false), "Run disabled tests too, in addition to the tests normally being run."); GTEST_DEFINE_bool_( break_on_failure, internal::BoolFromGTestEnv("break_on_failure", false), "True iff a failed assertion should be a debugger break-point."); GTEST_DEFINE_bool_( catch_exceptions, internal::BoolFromGTestEnv("catch_exceptions", true), "True iff " GTEST_NAME_ " should catch exceptions and treat them as test failures."); GTEST_DEFINE_string_( color, internal::StringFromGTestEnv("color", "auto"), "Whether to use colors in the output. Valid values: yes, no, " "and auto. 'auto' means to use colors if the output is " "being sent to a terminal and the TERM environment variable " "is set to a terminal type that supports colors."); GTEST_DEFINE_string_( filter, internal::StringFromGTestEnv("filter", GetDefaultFilter()), "A colon-separated list of glob (not regex) patterns " "for filtering the tests to run, optionally followed by a " "'-' and a : separated list of negative patterns (tests to " "exclude). A test is run if it matches one of the positive " "patterns and does not match any of the negative patterns."); GTEST_DEFINE_bool_(list_tests, false, "List all tests without running them."); GTEST_DEFINE_string_( output, internal::StringFromGTestEnv("output", ""), "A format (currently must be \"xml\"), optionally followed " "by a colon and an output file name or directory. A directory " "is indicated by a trailing pathname separator. " "Examples: \"xml:filename.xml\", \"xml::directoryname/\". " "If a directory is specified, output files will be created " "within that directory, with file-names based on the test " "executable's name and, if necessary, made unique by adding " "digits."); GTEST_DEFINE_bool_( print_time, internal::BoolFromGTestEnv("print_time", true), "True iff " GTEST_NAME_ " should display elapsed time in text output."); GTEST_DEFINE_int32_( random_seed, internal::Int32FromGTestEnv("random_seed", 0), "Random number seed to use when shuffling test orders. Must be in range " "[1, 99999], or 0 to use a seed based on the current time."); GTEST_DEFINE_int32_( repeat, internal::Int32FromGTestEnv("repeat", 1), "How many times to repeat each test. Specify a negative number " "for repeating forever. Useful for shaking out flaky tests."); GTEST_DEFINE_bool_( show_internal_stack_frames, false, "True iff " GTEST_NAME_ " should include internal stack frames when " "printing test failure stack traces."); GTEST_DEFINE_bool_( shuffle, internal::BoolFromGTestEnv("shuffle", false), "True iff " GTEST_NAME_ " should randomize tests' order on every run."); GTEST_DEFINE_int32_( stack_trace_depth, internal::Int32FromGTestEnv("stack_trace_depth", kMaxStackTraceDepth), "The maximum number of stack frames to print when an " "assertion fails. The valid range is 0 through 100, inclusive."); GTEST_DEFINE_string_( stream_result_to, internal::StringFromGTestEnv("stream_result_to", ""), "This flag specifies the host name and the port number on which to stream " "test results. Example: \"localhost:555\". The flag is effective only on " "Linux."); GTEST_DEFINE_bool_( throw_on_failure, internal::BoolFromGTestEnv("throw_on_failure", false), "When this flag is specified, a failed assertion will throw an exception " "if exceptions are enabled or exit the program with a non-zero code " "otherwise."); namespace internal { // Generates a random number from [0, range), using a Linear // Congruential Generator (LCG). Crashes if 'range' is 0 or greater // than kMaxRange. UInt32 Random::Generate(UInt32 range) { // These constants are the same as are used in glibc's rand(3). state_ = (1103515245U * state_ + 12345U) % kMaxRange; GTEST_CHECK_(range > 0) << "Cannot generate a number in the range [0, 0)."; GTEST_CHECK_(range <= kMaxRange) << "Generation of a number in [0, " << range << ") was requested, " << "but this can only generate numbers in [0, " << kMaxRange << ")."; // Converting via modulus introduces a bit of downward bias, but // it's simple, and a linear congruential generator isn't too good // to begin with. return state_ % range; } // GTestIsInitialized() returns true iff the user has initialized // Google Test. Useful for catching the user mistake of not initializing // Google Test before calling RUN_ALL_TESTS(). // // A user must call testing::InitGoogleTest() to initialize Google // Test. g_init_gtest_count is set to the number of times // InitGoogleTest() has been called. We don't protect this variable // under a mutex as it is only accessed in the main thread. GTEST_API_ int g_init_gtest_count = 0; static bool GTestIsInitialized() { return g_init_gtest_count != 0; } // Iterates over a vector of TestCases, keeping a running sum of the // results of calling a given int-returning method on each. // Returns the sum. static int SumOverTestCaseList(const std::vector& case_list, int (TestCase::*method)() const) { int sum = 0; for (size_t i = 0; i < case_list.size(); i++) { sum += (case_list[i]->*method)(); } return sum; } // Returns true iff the test case passed. static bool TestCasePassed(const TestCase* test_case) { return test_case->should_run() && test_case->Passed(); } // Returns true iff the test case failed. static bool TestCaseFailed(const TestCase* test_case) { return test_case->should_run() && test_case->Failed(); } // Returns true iff test_case contains at least one test that should // run. static bool ShouldRunTestCase(const TestCase* test_case) { return test_case->should_run(); } // AssertHelper constructor. AssertHelper::AssertHelper(TestPartResult::Type type, const char* file, int line, const char* message) : data_(new AssertHelperData(type, file, line, message)) { } AssertHelper::~AssertHelper() { delete data_; } // Message assignment, for assertion streaming support. void AssertHelper::operator=(const Message& message) const { UnitTest::GetInstance()-> AddTestPartResult(data_->type, data_->file, data_->line, AppendUserMessage(data_->message, message), UnitTest::GetInstance()->impl() ->CurrentOsStackTraceExceptTop(1) // Skips the stack frame for this function itself. ); // NOLINT } // Mutex for linked pointers. GTEST_API_ GTEST_DEFINE_STATIC_MUTEX_(g_linked_ptr_mutex); // Application pathname gotten in InitGoogleTest. std::string g_executable_path; // Returns the current application's name, removing directory path if that // is present. FilePath GetCurrentExecutableName() { FilePath result; #if GTEST_OS_WINDOWS result.Set(FilePath(g_executable_path).RemoveExtension("exe")); #else result.Set(FilePath(g_executable_path)); #endif // GTEST_OS_WINDOWS return result.RemoveDirectoryName(); } // Functions for processing the gtest_output flag. // Returns the output format, or "" for normal printed output. std::string UnitTestOptions::GetOutputFormat() { const char* const gtest_output_flag = GTEST_FLAG(output).c_str(); if (gtest_output_flag == NULL) return std::string(""); const char* const colon = strchr(gtest_output_flag, ':'); return (colon == NULL) ? std::string(gtest_output_flag) : std::string(gtest_output_flag, colon - gtest_output_flag); } // Returns the name of the requested output file, or the default if none // was explicitly specified. std::string UnitTestOptions::GetAbsolutePathToOutputFile() { const char* const gtest_output_flag = GTEST_FLAG(output).c_str(); if (gtest_output_flag == NULL) return ""; const char* const colon = strchr(gtest_output_flag, ':'); if (colon == NULL) return internal::FilePath::ConcatPaths( internal::FilePath( UnitTest::GetInstance()->original_working_dir()), internal::FilePath(kDefaultOutputFile)).string(); internal::FilePath output_name(colon + 1); if (!output_name.IsAbsolutePath()) // TODO(wan@google.com): on Windows \some\path is not an absolute // path (as its meaning depends on the current drive), yet the // following logic for turning it into an absolute path is wrong. // Fix it. output_name = internal::FilePath::ConcatPaths( internal::FilePath(UnitTest::GetInstance()->original_working_dir()), internal::FilePath(colon + 1)); if (!output_name.IsDirectory()) return output_name.string(); internal::FilePath result(internal::FilePath::GenerateUniqueFileName( output_name, internal::GetCurrentExecutableName(), GetOutputFormat().c_str())); return result.string(); } // Returns true iff the wildcard pattern matches the string. The // first ':' or '\0' character in pattern marks the end of it. // // This recursive algorithm isn't very efficient, but is clear and // works well enough for matching test names, which are short. bool UnitTestOptions::PatternMatchesString(const char *pattern, const char *str) { switch (*pattern) { case '\0': case ':': // Either ':' or '\0' marks the end of the pattern. return *str == '\0'; case '?': // Matches any single character. return *str != '\0' && PatternMatchesString(pattern + 1, str + 1); case '*': // Matches any string (possibly empty) of characters. return (*str != '\0' && PatternMatchesString(pattern, str + 1)) || PatternMatchesString(pattern + 1, str); default: // Non-special character. Matches itself. return *pattern == *str && PatternMatchesString(pattern + 1, str + 1); } } bool UnitTestOptions::MatchesFilter( const std::string& name, const char* filter) { const char *cur_pattern = filter; for (;;) { if (PatternMatchesString(cur_pattern, name.c_str())) { return true; } // Finds the next pattern in the filter. cur_pattern = strchr(cur_pattern, ':'); // Returns if no more pattern can be found. if (cur_pattern == NULL) { return false; } // Skips the pattern separater (the ':' character). cur_pattern++; } } // Returns true iff the user-specified filter matches the test case // name and the test name. bool UnitTestOptions::FilterMatchesTest(const std::string &test_case_name, const std::string &test_name) { const std::string& full_name = test_case_name + "." + test_name.c_str(); // Split --gtest_filter at '-', if there is one, to separate into // positive filter and negative filter portions const char* const p = GTEST_FLAG(filter).c_str(); const char* const dash = strchr(p, '-'); std::string positive; std::string negative; if (dash == NULL) { positive = GTEST_FLAG(filter).c_str(); // Whole string is a positive filter negative = ""; } else { positive = std::string(p, dash); // Everything up to the dash negative = std::string(dash + 1); // Everything after the dash if (positive.empty()) { // Treat '-test1' as the same as '*-test1' positive = kUniversalFilter; } } // A filter is a colon-separated list of patterns. It matches a // test if any pattern in it matches the test. return (MatchesFilter(full_name, positive.c_str()) && !MatchesFilter(full_name, negative.c_str())); } #if GTEST_HAS_SEH // Returns EXCEPTION_EXECUTE_HANDLER if Google Test should handle the // given SEH exception, or EXCEPTION_CONTINUE_SEARCH otherwise. // This function is useful as an __except condition. int UnitTestOptions::GTestShouldProcessSEH(DWORD exception_code) { // Google Test should handle a SEH exception if: // 1. the user wants it to, AND // 2. this is not a breakpoint exception, AND // 3. this is not a C++ exception (VC++ implements them via SEH, // apparently). // // SEH exception code for C++ exceptions. // (see http://support.microsoft.com/kb/185294 for more information). const DWORD kCxxExceptionCode = 0xe06d7363; bool should_handle = true; if (!GTEST_FLAG(catch_exceptions)) should_handle = false; else if (exception_code == EXCEPTION_BREAKPOINT) should_handle = false; else if (exception_code == kCxxExceptionCode) should_handle = false; return should_handle ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH; } #endif // GTEST_HAS_SEH } // namespace internal // The c'tor sets this object as the test part result reporter used by // Google Test. The 'result' parameter specifies where to report the // results. Intercepts only failures from the current thread. ScopedFakeTestPartResultReporter::ScopedFakeTestPartResultReporter( TestPartResultArray* result) : intercept_mode_(INTERCEPT_ONLY_CURRENT_THREAD), result_(result) { Init(); } // The c'tor sets this object as the test part result reporter used by // Google Test. The 'result' parameter specifies where to report the // results. ScopedFakeTestPartResultReporter::ScopedFakeTestPartResultReporter( InterceptMode intercept_mode, TestPartResultArray* result) : intercept_mode_(intercept_mode), result_(result) { Init(); } void ScopedFakeTestPartResultReporter::Init() { internal::UnitTestImpl* const impl = internal::GetUnitTestImpl(); if (intercept_mode_ == INTERCEPT_ALL_THREADS) { old_reporter_ = impl->GetGlobalTestPartResultReporter(); impl->SetGlobalTestPartResultReporter(this); } else { old_reporter_ = impl->GetTestPartResultReporterForCurrentThread(); impl->SetTestPartResultReporterForCurrentThread(this); } } // The d'tor restores the test part result reporter used by Google Test // before. ScopedFakeTestPartResultReporter::~ScopedFakeTestPartResultReporter() { internal::UnitTestImpl* const impl = internal::GetUnitTestImpl(); if (intercept_mode_ == INTERCEPT_ALL_THREADS) { impl->SetGlobalTestPartResultReporter(old_reporter_); } else { impl->SetTestPartResultReporterForCurrentThread(old_reporter_); } } // Increments the test part result count and remembers the result. // This method is from the TestPartResultReporterInterface interface. void ScopedFakeTestPartResultReporter::ReportTestPartResult( const TestPartResult& result) { result_->Append(result); } namespace internal { // Returns the type ID of ::testing::Test. We should always call this // instead of GetTypeId< ::testing::Test>() to get the type ID of // testing::Test. This is to work around a suspected linker bug when // using Google Test as a framework on Mac OS X. The bug causes // GetTypeId< ::testing::Test>() to return different values depending // on whether the call is from the Google Test framework itself or // from user test code. GetTestTypeId() is guaranteed to always // return the same value, as it always calls GetTypeId<>() from the // gtest.cc, which is within the Google Test framework. TypeId GetTestTypeId() { return GetTypeId(); } // The value of GetTestTypeId() as seen from within the Google Test // library. This is solely for testing GetTestTypeId(). extern const TypeId kTestTypeIdInGoogleTest = GetTestTypeId(); // This predicate-formatter checks that 'results' contains a test part // failure of the given type and that the failure message contains the // given substring. AssertionResult HasOneFailure(const char* /* results_expr */, const char* /* type_expr */, const char* /* substr_expr */, const TestPartResultArray& results, TestPartResult::Type type, const string& substr) { const std::string expected(type == TestPartResult::kFatalFailure ? "1 fatal failure" : "1 non-fatal failure"); Message msg; if (results.size() != 1) { msg << "Expected: " << expected << "\n" << " Actual: " << results.size() << " failures"; for (int i = 0; i < results.size(); i++) { msg << "\n" << results.GetTestPartResult(i); } return AssertionFailure() << msg; } const TestPartResult& r = results.GetTestPartResult(0); if (r.type() != type) { return AssertionFailure() << "Expected: " << expected << "\n" << " Actual:\n" << r; } if (strstr(r.message(), substr.c_str()) == NULL) { return AssertionFailure() << "Expected: " << expected << " containing \"" << substr << "\"\n" << " Actual:\n" << r; } return AssertionSuccess(); } // The constructor of SingleFailureChecker remembers where to look up // test part results, what type of failure we expect, and what // substring the failure message should contain. SingleFailureChecker::SingleFailureChecker( const TestPartResultArray* results, TestPartResult::Type type, const string& substr) : results_(results), type_(type), substr_(substr) {} // The destructor of SingleFailureChecker verifies that the given // TestPartResultArray contains exactly one failure that has the given // type and contains the given substring. If that's not the case, a // non-fatal failure will be generated. SingleFailureChecker::~SingleFailureChecker() { EXPECT_PRED_FORMAT3(HasOneFailure, *results_, type_, substr_); } DefaultGlobalTestPartResultReporter::DefaultGlobalTestPartResultReporter( UnitTestImpl* unit_test) : unit_test_(unit_test) {} void DefaultGlobalTestPartResultReporter::ReportTestPartResult( const TestPartResult& result) { unit_test_->current_test_result()->AddTestPartResult(result); unit_test_->listeners()->repeater()->OnTestPartResult(result); } DefaultPerThreadTestPartResultReporter::DefaultPerThreadTestPartResultReporter( UnitTestImpl* unit_test) : unit_test_(unit_test) {} void DefaultPerThreadTestPartResultReporter::ReportTestPartResult( const TestPartResult& result) { unit_test_->GetGlobalTestPartResultReporter()->ReportTestPartResult(result); } // Returns the global test part result reporter. TestPartResultReporterInterface* UnitTestImpl::GetGlobalTestPartResultReporter() { internal::MutexLock lock(&global_test_part_result_reporter_mutex_); return global_test_part_result_repoter_; } // Sets the global test part result reporter. void UnitTestImpl::SetGlobalTestPartResultReporter( TestPartResultReporterInterface* reporter) { internal::MutexLock lock(&global_test_part_result_reporter_mutex_); global_test_part_result_repoter_ = reporter; } // Returns the test part result reporter for the current thread. TestPartResultReporterInterface* UnitTestImpl::GetTestPartResultReporterForCurrentThread() { return per_thread_test_part_result_reporter_.get(); } // Sets the test part result reporter for the current thread. void UnitTestImpl::SetTestPartResultReporterForCurrentThread( TestPartResultReporterInterface* reporter) { per_thread_test_part_result_reporter_.set(reporter); } // Gets the number of successful test cases. int UnitTestImpl::successful_test_case_count() const { return CountIf(test_cases_, TestCasePassed); } // Gets the number of failed test cases. int UnitTestImpl::failed_test_case_count() const { return CountIf(test_cases_, TestCaseFailed); } // Gets the number of all test cases. int UnitTestImpl::total_test_case_count() const { return static_cast(test_cases_.size()); } // Gets the number of all test cases that contain at least one test // that should run. int UnitTestImpl::test_case_to_run_count() const { return CountIf(test_cases_, ShouldRunTestCase); } // Gets the number of successful tests. int UnitTestImpl::successful_test_count() const { return SumOverTestCaseList(test_cases_, &TestCase::successful_test_count); } // Gets the number of failed tests. int UnitTestImpl::failed_test_count() const { return SumOverTestCaseList(test_cases_, &TestCase::failed_test_count); } // Gets the number of disabled tests that will be reported in the XML report. int UnitTestImpl::reportable_disabled_test_count() const { return SumOverTestCaseList(test_cases_, &TestCase::reportable_disabled_test_count); } // Gets the number of disabled tests. int UnitTestImpl::disabled_test_count() const { return SumOverTestCaseList(test_cases_, &TestCase::disabled_test_count); } // Gets the number of tests to be printed in the XML report. int UnitTestImpl::reportable_test_count() const { return SumOverTestCaseList(test_cases_, &TestCase::reportable_test_count); } // Gets the number of all tests. int UnitTestImpl::total_test_count() const { return SumOverTestCaseList(test_cases_, &TestCase::total_test_count); } // Gets the number of tests that should run. int UnitTestImpl::test_to_run_count() const { return SumOverTestCaseList(test_cases_, &TestCase::test_to_run_count); } // Returns the current OS stack trace as an std::string. // // The maximum number of stack frames to be included is specified by // the gtest_stack_trace_depth flag. The skip_count parameter // specifies the number of top frames to be skipped, which doesn't // count against the number of frames to be included. // // For example, if Foo() calls Bar(), which in turn calls // CurrentOsStackTraceExceptTop(1), Foo() will be included in the // trace but Bar() and CurrentOsStackTraceExceptTop() won't. std::string UnitTestImpl::CurrentOsStackTraceExceptTop(int skip_count) { (void)skip_count; return ""; } // Returns the current time in milliseconds. TimeInMillis GetTimeInMillis() { #if GTEST_OS_WINDOWS_MOBILE || defined(__BORLANDC__) // Difference between 1970-01-01 and 1601-01-01 in milliseconds. // http://analogous.blogspot.com/2005/04/epoch.html const TimeInMillis kJavaEpochToWinFileTimeDelta = static_cast(116444736UL) * 100000UL; const DWORD kTenthMicrosInMilliSecond = 10000; SYSTEMTIME now_systime; FILETIME now_filetime; ULARGE_INTEGER now_int64; // TODO(kenton@google.com): Shouldn't this just use // GetSystemTimeAsFileTime()? GetSystemTime(&now_systime); if (SystemTimeToFileTime(&now_systime, &now_filetime)) { now_int64.LowPart = now_filetime.dwLowDateTime; now_int64.HighPart = now_filetime.dwHighDateTime; now_int64.QuadPart = (now_int64.QuadPart / kTenthMicrosInMilliSecond) - kJavaEpochToWinFileTimeDelta; return now_int64.QuadPart; } return 0; #elif GTEST_OS_WINDOWS && !GTEST_HAS_GETTIMEOFDAY_ __timeb64 now; # ifdef _MSC_VER // MSVC 8 deprecates _ftime64(), so we want to suppress warning 4996 // (deprecated function) there. // TODO(kenton@google.com): Use GetTickCount()? Or use // SystemTimeToFileTime() # pragma warning(push) // Saves the current warning state. # pragma warning(disable:4996) // Temporarily disables warning 4996. _ftime64(&now); # pragma warning(pop) // Restores the warning state. # else _ftime64(&now); # endif // _MSC_VER return static_cast(now.time) * 1000 + now.millitm; #elif GTEST_HAS_GETTIMEOFDAY_ struct timeval now; gettimeofday(&now, NULL); return static_cast(now.tv_sec) * 1000 + now.tv_usec / 1000; #else # error "Don't know how to get the current time on your system." #endif } // Utilities // class String. #if GTEST_OS_WINDOWS_MOBILE // Creates a UTF-16 wide string from the given ANSI string, allocating // memory using new. The caller is responsible for deleting the return // value using delete[]. Returns the wide string, or NULL if the // input is NULL. LPCWSTR String::AnsiToUtf16(const char* ansi) { if (!ansi) return NULL; const int length = strlen(ansi); const int unicode_length = MultiByteToWideChar(CP_ACP, 0, ansi, length, NULL, 0); WCHAR* unicode = new WCHAR[unicode_length + 1]; MultiByteToWideChar(CP_ACP, 0, ansi, length, unicode, unicode_length); unicode[unicode_length] = 0; return unicode; } // Creates an ANSI string from the given wide string, allocating // memory using new. The caller is responsible for deleting the return // value using delete[]. Returns the ANSI string, or NULL if the // input is NULL. const char* String::Utf16ToAnsi(LPCWSTR utf16_str) { if (!utf16_str) return NULL; const int ansi_length = WideCharToMultiByte(CP_ACP, 0, utf16_str, -1, NULL, 0, NULL, NULL); char* ansi = new char[ansi_length + 1]; WideCharToMultiByte(CP_ACP, 0, utf16_str, -1, ansi, ansi_length, NULL, NULL); ansi[ansi_length] = 0; return ansi; } #endif // GTEST_OS_WINDOWS_MOBILE // Compares two C strings. Returns true iff they have the same content. // // Unlike strcmp(), this function can handle NULL argument(s). A NULL // C string is considered different to any non-NULL C string, // including the empty string. bool String::CStringEquals(const char * lhs, const char * rhs) { if (lhs == NULL) return rhs == NULL; if (rhs == NULL) return false; return strcmp(lhs, rhs) == 0; } #if GTEST_HAS_STD_WSTRING || GTEST_HAS_GLOBAL_WSTRING // Converts an array of wide chars to a narrow string using the UTF-8 // encoding, and streams the result to the given Message object. static void StreamWideCharsToMessage(const wchar_t* wstr, size_t length, Message* msg) { for (size_t i = 0; i != length; ) { // NOLINT if (wstr[i] != L'\0') { *msg << WideStringToUtf8(wstr + i, static_cast(length - i)); while (i != length && wstr[i] != L'\0') i++; } else { *msg << '\0'; i++; } } } #endif // GTEST_HAS_STD_WSTRING || GTEST_HAS_GLOBAL_WSTRING } // namespace internal // Constructs an empty Message. // We allocate the stringstream separately because otherwise each use of // ASSERT/EXPECT in a procedure adds over 200 bytes to the procedure's // stack frame leading to huge stack frames in some cases; gcc does not reuse // the stack space. Message::Message() : ss_(new ::std::stringstream) { // By default, we want there to be enough precision when printing // a double to a Message. *ss_ << std::setprecision(std::numeric_limits::digits10 + 2); } // These two overloads allow streaming a wide C string to a Message // using the UTF-8 encoding. Message& Message::operator <<(const wchar_t* wide_c_str) { return *this << internal::String::ShowWideCString(wide_c_str); } Message& Message::operator <<(wchar_t* wide_c_str) { return *this << internal::String::ShowWideCString(wide_c_str); } #if GTEST_HAS_STD_WSTRING // Converts the given wide string to a narrow string using the UTF-8 // encoding, and streams the result to this Message object. Message& Message::operator <<(const ::std::wstring& wstr) { internal::StreamWideCharsToMessage(wstr.c_str(), wstr.length(), this); return *this; } #endif // GTEST_HAS_STD_WSTRING #if GTEST_HAS_GLOBAL_WSTRING // Converts the given wide string to a narrow string using the UTF-8 // encoding, and streams the result to this Message object. Message& Message::operator <<(const ::wstring& wstr) { internal::StreamWideCharsToMessage(wstr.c_str(), wstr.length(), this); return *this; } #endif // GTEST_HAS_GLOBAL_WSTRING // Gets the text streamed to this object so far as an std::string. // Each '\0' character in the buffer is replaced with "\\0". std::string Message::GetString() const { return internal::StringStreamToString(ss_.get()); } // AssertionResult constructors. // Used in EXPECT_TRUE/FALSE(assertion_result). AssertionResult::AssertionResult(const AssertionResult& other) : success_(other.success_), message_(other.message_.get() != NULL ? new ::std::string(*other.message_) : static_cast< ::std::string*>(NULL)) { } // Returns the assertion's negation. Used with EXPECT/ASSERT_FALSE. AssertionResult AssertionResult::operator!() const { AssertionResult negation(!success_); if (message_.get() != NULL) negation << *message_; return negation; } // Makes a successful assertion result. AssertionResult AssertionSuccess() { return AssertionResult(true); } // Makes a failed assertion result. AssertionResult AssertionFailure() { return AssertionResult(false); } // Makes a failed assertion result with the given failure message. // Deprecated; use AssertionFailure() << message. AssertionResult AssertionFailure(const Message& message) { return AssertionFailure() << message; } namespace internal { // Constructs and returns the message for an equality assertion // (e.g. ASSERT_EQ, EXPECT_STREQ, etc) failure. // // The first four parameters are the expressions used in the assertion // and their values, as strings. For example, for ASSERT_EQ(foo, bar) // where foo is 5 and bar is 6, we have: // // expected_expression: "foo" // actual_expression: "bar" // expected_value: "5" // actual_value: "6" // // The ignoring_case parameter is true iff the assertion is a // *_STRCASEEQ*. When it's true, the string " (ignoring case)" will // be inserted into the message. AssertionResult EqFailure(const char* expected_expression, const char* actual_expression, const std::string& expected_value, const std::string& actual_value, bool ignoring_case) { Message msg; msg << "Value of: " << actual_expression; if (actual_value != actual_expression) { msg << "\n Actual: " << actual_value; } msg << "\nExpected: " << expected_expression; if (ignoring_case) { msg << " (ignoring case)"; } if (expected_value != expected_expression) { msg << "\nWhich is: " << expected_value; } return AssertionFailure() << msg; } // Constructs a failure message for Boolean assertions such as EXPECT_TRUE. std::string GetBoolAssertionFailureMessage( const AssertionResult& assertion_result, const char* expression_text, const char* actual_predicate_value, const char* expected_predicate_value) { const char* actual_message = assertion_result.message(); Message msg; msg << "Value of: " << expression_text << "\n Actual: " << actual_predicate_value; if (actual_message[0] != '\0') msg << " (" << actual_message << ")"; msg << "\nExpected: " << expected_predicate_value; return msg.GetString(); } // Helper function for implementing ASSERT_NEAR. AssertionResult DoubleNearPredFormat(const char* expr1, const char* expr2, const char* abs_error_expr, double val1, double val2, double abs_error) { const double diff = fabs(val1 - val2); if (diff <= abs_error) return AssertionSuccess(); // TODO(wan): do not print the value of an expression if it's // already a literal. return AssertionFailure() << "The difference between " << expr1 << " and " << expr2 << " is " << diff << ", which exceeds " << abs_error_expr << ", where\n" << expr1 << " evaluates to " << val1 << ",\n" << expr2 << " evaluates to " << val2 << ", and\n" << abs_error_expr << " evaluates to " << abs_error << "."; } // Helper template for implementing FloatLE() and DoubleLE(). template AssertionResult FloatingPointLE(const char* expr1, const char* expr2, RawType val1, RawType val2) { // Returns success if val1 is less than val2, if (val1 < val2) { return AssertionSuccess(); } // or if val1 is almost equal to val2. const FloatingPoint lhs(val1), rhs(val2); if (lhs.AlmostEquals(rhs)) { return AssertionSuccess(); } // Note that the above two checks will both fail if either val1 or // val2 is NaN, as the IEEE floating-point standard requires that // any predicate involving a NaN must return false. ::std::stringstream val1_ss; val1_ss << std::setprecision(std::numeric_limits::digits10 + 2) << val1; ::std::stringstream val2_ss; val2_ss << std::setprecision(std::numeric_limits::digits10 + 2) << val2; return AssertionFailure() << "Expected: (" << expr1 << ") <= (" << expr2 << ")\n" << " Actual: " << StringStreamToString(&val1_ss) << " vs " << StringStreamToString(&val2_ss); } } // namespace internal // Asserts that val1 is less than, or almost equal to, val2. Fails // otherwise. In particular, it fails if either val1 or val2 is NaN. AssertionResult FloatLE(const char* expr1, const char* expr2, float val1, float val2) { return internal::FloatingPointLE(expr1, expr2, val1, val2); } // Asserts that val1 is less than, or almost equal to, val2. Fails // otherwise. In particular, it fails if either val1 or val2 is NaN. AssertionResult DoubleLE(const char* expr1, const char* expr2, double val1, double val2) { return internal::FloatingPointLE(expr1, expr2, val1, val2); } namespace internal { // The helper function for {ASSERT|EXPECT}_EQ with int or enum // arguments. AssertionResult CmpHelperEQ(const char* expected_expression, const char* actual_expression, BiggestInt expected, BiggestInt actual) { if (expected == actual) { return AssertionSuccess(); } return EqFailure(expected_expression, actual_expression, FormatForComparisonFailureMessage(expected, actual), FormatForComparisonFailureMessage(actual, expected), false); } // A macro for implementing the helper functions needed to implement // ASSERT_?? and EXPECT_?? with integer or enum arguments. It is here // just to avoid copy-and-paste of similar code. #define GTEST_IMPL_CMP_HELPER_(op_name, op)\ AssertionResult CmpHelper##op_name(const char* expr1, const char* expr2, \ BiggestInt val1, BiggestInt val2) {\ if (val1 op val2) {\ return AssertionSuccess();\ } else {\ return AssertionFailure() \ << "Expected: (" << expr1 << ") " #op " (" << expr2\ << "), actual: " << FormatForComparisonFailureMessage(val1, val2)\ << " vs " << FormatForComparisonFailureMessage(val2, val1);\ }\ } // Implements the helper function for {ASSERT|EXPECT}_NE with int or // enum arguments. GTEST_IMPL_CMP_HELPER_(NE, != ) // Implements the helper function for {ASSERT|EXPECT}_LE with int or // enum arguments. GTEST_IMPL_CMP_HELPER_(LE, <= ) // Implements the helper function for {ASSERT|EXPECT}_LT with int or // enum arguments. GTEST_IMPL_CMP_HELPER_(LT, <) // Implements the helper function for {ASSERT|EXPECT}_GE with int or // enum arguments. GTEST_IMPL_CMP_HELPER_(GE, >= ) // Implements the helper function for {ASSERT|EXPECT}_GT with int or // enum arguments. GTEST_IMPL_CMP_HELPER_(GT, >) #undef GTEST_IMPL_CMP_HELPER_ // The helper function for {ASSERT|EXPECT}_STREQ. AssertionResult CmpHelperSTREQ(const char* expected_expression, const char* actual_expression, const char* expected, const char* actual) { if (String::CStringEquals(expected, actual)) { return AssertionSuccess(); } return EqFailure(expected_expression, actual_expression, PrintToString(expected), PrintToString(actual), false); } // The helper function for {ASSERT|EXPECT}_STRCASEEQ. AssertionResult CmpHelperSTRCASEEQ(const char* expected_expression, const char* actual_expression, const char* expected, const char* actual) { if (String::CaseInsensitiveCStringEquals(expected, actual)) { return AssertionSuccess(); } return EqFailure(expected_expression, actual_expression, PrintToString(expected), PrintToString(actual), true); } // The helper function for {ASSERT|EXPECT}_STRNE. AssertionResult CmpHelperSTRNE(const char* s1_expression, const char* s2_expression, const char* s1, const char* s2) { if (!String::CStringEquals(s1, s2)) { return AssertionSuccess(); } else { return AssertionFailure() << "Expected: (" << s1_expression << ") != (" << s2_expression << "), actual: \"" << s1 << "\" vs \"" << s2 << "\""; } } // The helper function for {ASSERT|EXPECT}_STRCASENE. AssertionResult CmpHelperSTRCASENE(const char* s1_expression, const char* s2_expression, const char* s1, const char* s2) { if (!String::CaseInsensitiveCStringEquals(s1, s2)) { return AssertionSuccess(); } else { return AssertionFailure() << "Expected: (" << s1_expression << ") != (" << s2_expression << ") (ignoring case), actual: \"" << s1 << "\" vs \"" << s2 << "\""; } } } // namespace internal namespace { // Helper functions for implementing IsSubString() and IsNotSubstring(). // This group of overloaded functions return true iff needle is a // substring of haystack. NULL is considered a substring of itself // only. bool IsSubstringPred(const char* needle, const char* haystack) { if (needle == NULL || haystack == NULL) return needle == haystack; return strstr(haystack, needle) != NULL; } bool IsSubstringPred(const wchar_t* needle, const wchar_t* haystack) { if (needle == NULL || haystack == NULL) return needle == haystack; return wcsstr(haystack, needle) != NULL; } // StringType here can be either ::std::string or ::std::wstring. template bool IsSubstringPred(const StringType& needle, const StringType& haystack) { return haystack.find(needle) != StringType::npos; } // This function implements either IsSubstring() or IsNotSubstring(), // depending on the value of the expected_to_be_substring parameter. // StringType here can be const char*, const wchar_t*, ::std::string, // or ::std::wstring. template AssertionResult IsSubstringImpl( bool expected_to_be_substring, const char* needle_expr, const char* haystack_expr, const StringType& needle, const StringType& haystack) { if (IsSubstringPred(needle, haystack) == expected_to_be_substring) return AssertionSuccess(); const bool is_wide_string = sizeof(needle[0]) > 1; const char* const begin_string_quote = is_wide_string ? "L\"" : "\""; return AssertionFailure() << "Value of: " << needle_expr << "\n" << " Actual: " << begin_string_quote << needle << "\"\n" << "Expected: " << (expected_to_be_substring ? "" : "not ") << "a substring of " << haystack_expr << "\n" << "Which is: " << begin_string_quote << haystack << "\""; } } // namespace // IsSubstring() and IsNotSubstring() check whether needle is a // substring of haystack (NULL is considered a substring of itself // only), and return an appropriate error message when they fail. AssertionResult IsSubstring( const char* needle_expr, const char* haystack_expr, const char* needle, const char* haystack) { return IsSubstringImpl(true, needle_expr, haystack_expr, needle, haystack); } AssertionResult IsSubstring( const char* needle_expr, const char* haystack_expr, const wchar_t* needle, const wchar_t* haystack) { return IsSubstringImpl(true, needle_expr, haystack_expr, needle, haystack); } AssertionResult IsNotSubstring( const char* needle_expr, const char* haystack_expr, const char* needle, const char* haystack) { return IsSubstringImpl(false, needle_expr, haystack_expr, needle, haystack); } AssertionResult IsNotSubstring( const char* needle_expr, const char* haystack_expr, const wchar_t* needle, const wchar_t* haystack) { return IsSubstringImpl(false, needle_expr, haystack_expr, needle, haystack); } AssertionResult IsSubstring( const char* needle_expr, const char* haystack_expr, const ::std::string& needle, const ::std::string& haystack) { return IsSubstringImpl(true, needle_expr, haystack_expr, needle, haystack); } AssertionResult IsNotSubstring( const char* needle_expr, const char* haystack_expr, const ::std::string& needle, const ::std::string& haystack) { return IsSubstringImpl(false, needle_expr, haystack_expr, needle, haystack); } #if GTEST_HAS_STD_WSTRING AssertionResult IsSubstring( const char* needle_expr, const char* haystack_expr, const ::std::wstring& needle, const ::std::wstring& haystack) { return IsSubstringImpl(true, needle_expr, haystack_expr, needle, haystack); } AssertionResult IsNotSubstring( const char* needle_expr, const char* haystack_expr, const ::std::wstring& needle, const ::std::wstring& haystack) { return IsSubstringImpl(false, needle_expr, haystack_expr, needle, haystack); } #endif // GTEST_HAS_STD_WSTRING namespace internal { #if GTEST_OS_WINDOWS namespace { // Helper function for IsHRESULT{SuccessFailure} predicates AssertionResult HRESULTFailureHelper(const char* expr, const char* expected, long hr) { // NOLINT # if GTEST_OS_WINDOWS_MOBILE // Windows CE doesn't support FormatMessage. const char error_text[] = ""; # else // Looks up the human-readable system message for the HRESULT code // and since we're not passing any params to FormatMessage, we don't // want inserts expanded. const DWORD kFlags = FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS; const DWORD kBufSize = 4096; // Gets the system's human readable message string for this HRESULT. char error_text[kBufSize] = { '\0' }; DWORD message_length = ::FormatMessageA(kFlags, 0, // no source, we're asking system hr, // the error 0, // no line width restrictions error_text, // output buffer kBufSize, // buf size NULL); // no arguments for inserts // Trims tailing white space (FormatMessage leaves a trailing CR-LF) for (; message_length && IsSpace(error_text[message_length - 1]); --message_length) { error_text[message_length - 1] = '\0'; } # endif // GTEST_OS_WINDOWS_MOBILE const std::string error_hex("0x" + String::FormatHexInt(hr)); return ::testing::AssertionFailure() << "Expected: " << expr << " " << expected << ".\n" << " Actual: " << error_hex << " " << error_text << "\n"; } } // namespace AssertionResult IsHRESULTSuccess(const char* expr, long hr) { // NOLINT if (SUCCEEDED(hr)) { return AssertionSuccess(); } return HRESULTFailureHelper(expr, "succeeds", hr); } AssertionResult IsHRESULTFailure(const char* expr, long hr) { // NOLINT if (FAILED(hr)) { return AssertionSuccess(); } return HRESULTFailureHelper(expr, "fails", hr); } #endif // GTEST_OS_WINDOWS // Utility functions for encoding Unicode text (wide strings) in // UTF-8. // A Unicode code-point can have upto 21 bits, and is encoded in UTF-8 // like this: // // Code-point length Encoding // 0 - 7 bits 0xxxxxxx // 8 - 11 bits 110xxxxx 10xxxxxx // 12 - 16 bits 1110xxxx 10xxxxxx 10xxxxxx // 17 - 21 bits 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx // The maximum code-point a one-byte UTF-8 sequence can represent. const UInt32 kMaxCodePoint1 = (static_cast(1) << 7) - 1; // The maximum code-point a two-byte UTF-8 sequence can represent. const UInt32 kMaxCodePoint2 = (static_cast(1) << (5 + 6)) - 1; // The maximum code-point a three-byte UTF-8 sequence can represent. const UInt32 kMaxCodePoint3 = (static_cast(1) << (4 + 2 * 6)) - 1; // The maximum code-point a four-byte UTF-8 sequence can represent. const UInt32 kMaxCodePoint4 = (static_cast(1) << (3 + 3 * 6)) - 1; // Chops off the n lowest bits from a bit pattern. Returns the n // lowest bits. As a side effect, the original bit pattern will be // shifted to the right by n bits. inline UInt32 ChopLowBits(UInt32* bits, int n) { const UInt32 low_bits = *bits & ((static_cast(1) << n) - 1); *bits >>= n; return low_bits; } // Converts a Unicode code point to a narrow string in UTF-8 encoding. // code_point parameter is of type UInt32 because wchar_t may not be // wide enough to contain a code point. // If the code_point is not a valid Unicode code point // (i.e. outside of Unicode range U+0 to U+10FFFF) it will be converted // to "(Invalid Unicode 0xXXXXXXXX)". std::string CodePointToUtf8(UInt32 code_point) { if (code_point > kMaxCodePoint4) { return "(Invalid Unicode 0x" + String::FormatHexInt(code_point) + ")"; } char str[5]; // Big enough for the largest valid code point. if (code_point <= kMaxCodePoint1) { str[1] = '\0'; str[0] = static_cast(code_point); // 0xxxxxxx } else if (code_point <= kMaxCodePoint2) { str[2] = '\0'; str[1] = static_cast(0x80 | ChopLowBits(&code_point, 6)); // 10xxxxxx str[0] = static_cast(0xC0 | code_point); // 110xxxxx } else if (code_point <= kMaxCodePoint3) { str[3] = '\0'; str[2] = static_cast(0x80 | ChopLowBits(&code_point, 6)); // 10xxxxxx str[1] = static_cast(0x80 | ChopLowBits(&code_point, 6)); // 10xxxxxx str[0] = static_cast(0xE0 | code_point); // 1110xxxx } else { // code_point <= kMaxCodePoint4 str[4] = '\0'; str[3] = static_cast(0x80 | ChopLowBits(&code_point, 6)); // 10xxxxxx str[2] = static_cast(0x80 | ChopLowBits(&code_point, 6)); // 10xxxxxx str[1] = static_cast(0x80 | ChopLowBits(&code_point, 6)); // 10xxxxxx str[0] = static_cast(0xF0 | code_point); // 11110xxx } return str; } // The following two functions only make sense if the the system // uses UTF-16 for wide string encoding. All supported systems // with 16 bit wchar_t (Windows, Cygwin, Symbian OS) do use UTF-16. // Determines if the arguments constitute UTF-16 surrogate pair // and thus should be combined into a single Unicode code point // using CreateCodePointFromUtf16SurrogatePair. inline bool IsUtf16SurrogatePair(wchar_t first, wchar_t second) { return sizeof(wchar_t) == 2 && (first & 0xFC00) == 0xD800 && (second & 0xFC00) == 0xDC00; } // Creates a Unicode code point from UTF16 surrogate pair. inline UInt32 CreateCodePointFromUtf16SurrogatePair(wchar_t first, wchar_t second) { const UInt32 mask = (1 << 10) - 1; return (sizeof(wchar_t) == 2) ? (((first & mask) << 10) | (second & mask)) + 0x10000 : // This function should not be called when the condition is // false, but we provide a sensible default in case it is. static_cast(first); } // Converts a wide string to a narrow string in UTF-8 encoding. // The wide string is assumed to have the following encoding: // UTF-16 if sizeof(wchar_t) == 2 (on Windows, Cygwin, Symbian OS) // UTF-32 if sizeof(wchar_t) == 4 (on Linux) // Parameter str points to a null-terminated wide string. // Parameter num_chars may additionally limit the number // of wchar_t characters processed. -1 is used when the entire string // should be processed. // If the string contains code points that are not valid Unicode code points // (i.e. outside of Unicode range U+0 to U+10FFFF) they will be output // as '(Invalid Unicode 0xXXXXXXXX)'. If the string is in UTF16 encoding // and contains invalid UTF-16 surrogate pairs, values in those pairs // will be encoded as individual Unicode characters from Basic Normal Plane. std::string WideStringToUtf8(const wchar_t* str, int num_chars) { if (num_chars == -1) num_chars = static_cast(wcslen(str)); ::std::stringstream stream; for (int i = 0; i < num_chars; ++i) { UInt32 unicode_code_point; if (str[i] == L'\0') { break; } else if (i + 1 < num_chars && IsUtf16SurrogatePair(str[i], str[i + 1])) { unicode_code_point = CreateCodePointFromUtf16SurrogatePair(str[i], str[i + 1]); i++; } else { unicode_code_point = static_cast(str[i]); } stream << CodePointToUtf8(unicode_code_point); } return StringStreamToString(&stream); } // Converts a wide C string to an std::string using the UTF-8 encoding. // NULL will be converted to "(null)". std::string String::ShowWideCString(const wchar_t * wide_c_str) { if (wide_c_str == NULL) return "(null)"; return internal::WideStringToUtf8(wide_c_str, -1); } // Compares two wide C strings. Returns true iff they have the same // content. // // Unlike wcscmp(), this function can handle NULL argument(s). A NULL // C string is considered different to any non-NULL C string, // including the empty string. bool String::WideCStringEquals(const wchar_t * lhs, const wchar_t * rhs) { if (lhs == NULL) return rhs == NULL; if (rhs == NULL) return false; return wcscmp(lhs, rhs) == 0; } // Helper function for *_STREQ on wide strings. AssertionResult CmpHelperSTREQ(const char* expected_expression, const char* actual_expression, const wchar_t* expected, const wchar_t* actual) { if (String::WideCStringEquals(expected, actual)) { return AssertionSuccess(); } return EqFailure(expected_expression, actual_expression, PrintToString(expected), PrintToString(actual), false); } // Helper function for *_STRNE on wide strings. AssertionResult CmpHelperSTRNE(const char* s1_expression, const char* s2_expression, const wchar_t* s1, const wchar_t* s2) { if (!String::WideCStringEquals(s1, s2)) { return AssertionSuccess(); } return AssertionFailure() << "Expected: (" << s1_expression << ") != (" << s2_expression << "), actual: " << PrintToString(s1) << " vs " << PrintToString(s2); } // Compares two C strings, ignoring case. Returns true iff they have // the same content. // // Unlike strcasecmp(), this function can handle NULL argument(s). A // NULL C string is considered different to any non-NULL C string, // including the empty string. bool String::CaseInsensitiveCStringEquals(const char * lhs, const char * rhs) { if (lhs == NULL) return rhs == NULL; if (rhs == NULL) return false; return posix::StrCaseCmp(lhs, rhs) == 0; } // Compares two wide C strings, ignoring case. Returns true iff they // have the same content. // // Unlike wcscasecmp(), this function can handle NULL argument(s). // A NULL C string is considered different to any non-NULL wide C string, // including the empty string. // NB: The implementations on different platforms slightly differ. // On windows, this method uses _wcsicmp which compares according to LC_CTYPE // environment variable. On GNU platform this method uses wcscasecmp // which compares according to LC_CTYPE category of the current locale. // On MacOS X, it uses towlower, which also uses LC_CTYPE category of the // current locale. bool String::CaseInsensitiveWideCStringEquals(const wchar_t* lhs, const wchar_t* rhs) { if (lhs == NULL) return rhs == NULL; if (rhs == NULL) return false; #if GTEST_OS_WINDOWS return _wcsicmp(lhs, rhs) == 0; #elif GTEST_OS_LINUX && !GTEST_OS_LINUX_ANDROID return wcscasecmp(lhs, rhs) == 0; #else // Android, Mac OS X and Cygwin don't define wcscasecmp. // Other unknown OSes may not define it either. wint_t left, right; do { left = towlower(*lhs++); right = towlower(*rhs++); } while (left && left == right); return left == right; #endif // OS selector } // Returns true iff str ends with the given suffix, ignoring case. // Any string is considered to end with an empty suffix. bool String::EndsWithCaseInsensitive( const std::string& str, const std::string& suffix) { const size_t str_len = str.length(); const size_t suffix_len = suffix.length(); return (str_len >= suffix_len) && CaseInsensitiveCStringEquals(str.c_str() + str_len - suffix_len, suffix.c_str()); } // Formats an int value as "%02d". std::string String::FormatIntWidth2(int value) { std::stringstream ss; ss << std::setfill('0') << std::setw(2) << value; return ss.str(); } // Formats an int value as "%X". std::string String::FormatHexInt(int value) { std::stringstream ss; ss << std::hex << std::uppercase << value; return ss.str(); } // Formats a byte as "%02X". std::string String::FormatByte(unsigned char value) { std::stringstream ss; ss << std::setfill('0') << std::setw(2) << std::hex << std::uppercase << static_cast(value); return ss.str(); } // Converts the buffer in a stringstream to an std::string, converting NUL // bytes to "\\0" along the way. std::string StringStreamToString(::std::stringstream* ss) { const ::std::string& str = ss->str(); const char* const start = str.c_str(); const char* const end = start + str.length(); std::string result; result.reserve(2 * (end - start)); for (const char* ch = start; ch != end; ++ch) { if (*ch == '\0') { result += "\\0"; // Replaces NUL with "\\0"; } else { result += *ch; } } return result; } // Appends the user-supplied message to the Google-Test-generated message. std::string AppendUserMessage(const std::string& gtest_msg, const Message& user_msg) { // Appends the user message if it's non-empty. const std::string user_msg_string = user_msg.GetString(); if (user_msg_string.empty()) { return gtest_msg; } return gtest_msg + "\n" + user_msg_string; } } // namespace internal // class TestResult // Creates an empty TestResult. TestResult::TestResult() : death_test_count_(0), elapsed_time_(0) { } // D'tor. TestResult::~TestResult() { } // Returns the i-th test part result among all the results. i can // range from 0 to total_part_count() - 1. If i is not in that range, // aborts the program. const TestPartResult& TestResult::GetTestPartResult(int i) const { if (i < 0 || i >= total_part_count()) internal::posix::Abort(); return test_part_results_.at(i); } // Returns the i-th test property. i can range from 0 to // test_property_count() - 1. If i is not in that range, aborts the // program. const TestProperty& TestResult::GetTestProperty(int i) const { if (i < 0 || i >= test_property_count()) internal::posix::Abort(); return test_properties_.at(i); } // Clears the test part results. void TestResult::ClearTestPartResults() { test_part_results_.clear(); } // Adds a test part result to the list. void TestResult::AddTestPartResult(const TestPartResult& test_part_result) { test_part_results_.push_back(test_part_result); } // Adds a test property to the list. If a property with the same key as the // supplied property is already represented, the value of this test_property // replaces the old value for that key. void TestResult::RecordProperty(const std::string& xml_element, const TestProperty& test_property) { if (!ValidateTestProperty(xml_element, test_property)) { return; } internal::MutexLock lock(&test_properites_mutex_); const std::vector::iterator property_with_matching_key = std::find_if(test_properties_.begin(), test_properties_.end(), internal::TestPropertyKeyIs(test_property.key())); if (property_with_matching_key == test_properties_.end()) { test_properties_.push_back(test_property); return; } property_with_matching_key->SetValue(test_property.value()); } // The list of reserved attributes used in the element of XML // output. static const char* const kReservedTestSuitesAttributes[] = { "disabled", "errors", "failures", "name", "random_seed", "tests", "time", "timestamp" }; // The list of reserved attributes used in the element of XML // output. static const char* const kReservedTestSuiteAttributes[] = { "disabled", "errors", "failures", "name", "tests", "time" }; // The list of reserved attributes used in the element of XML output. static const char* const kReservedTestCaseAttributes[] = { "classname", "name", "status", "time", "type_param", "value_param" }; template std::vector ArrayAsVector(const char* const (&array)[kSize]) { return std::vector(array, array + kSize); } static std::vector GetReservedAttributesForElement( const std::string& xml_element) { if (xml_element == "testsuites") { return ArrayAsVector(kReservedTestSuitesAttributes); } else if (xml_element == "testsuite") { return ArrayAsVector(kReservedTestSuiteAttributes); } else if (xml_element == "testcase") { return ArrayAsVector(kReservedTestCaseAttributes); } else { GTEST_CHECK_(false) << "Unrecognized xml_element provided: " << xml_element; } // This code is unreachable but some compilers may not realizes that. return std::vector(); } static std::string FormatWordList(const std::vector& words) { Message word_list; for (size_t i = 0; i < words.size(); ++i) { if (i > 0 && words.size() > 2) { word_list << ", "; } if (i == words.size() - 1) { word_list << "and "; } word_list << "'" << words[i] << "'"; } return word_list.GetString(); } bool ValidateTestPropertyName(const std::string& property_name, const std::vector& reserved_names) { if (std::find(reserved_names.begin(), reserved_names.end(), property_name) != reserved_names.end()) { ADD_FAILURE() << "Reserved key used in RecordProperty(): " << property_name << " (" << FormatWordList(reserved_names) << " are reserved by " << GTEST_NAME_ << ")"; return false; } return true; } // Adds a failure if the key is a reserved attribute of the element named // xml_element. Returns true if the property is valid. bool TestResult::ValidateTestProperty(const std::string& xml_element, const TestProperty& test_property) { return ValidateTestPropertyName(test_property.key(), GetReservedAttributesForElement(xml_element)); } // Clears the object. void TestResult::Clear() { test_part_results_.clear(); test_properties_.clear(); death_test_count_ = 0; elapsed_time_ = 0; } // Returns true iff the test failed. bool TestResult::Failed() const { for (int i = 0; i < total_part_count(); ++i) { if (GetTestPartResult(i).failed()) return true; } return false; } // Returns true iff the test part fatally failed. static bool TestPartFatallyFailed(const TestPartResult& result) { return result.fatally_failed(); } // Returns true iff the test fatally failed. bool TestResult::HasFatalFailure() const { return CountIf(test_part_results_, TestPartFatallyFailed) > 0; } // Returns true iff the test part non-fatally failed. static bool TestPartNonfatallyFailed(const TestPartResult& result) { return result.nonfatally_failed(); } // Returns true iff the test has a non-fatal failure. bool TestResult::HasNonfatalFailure() const { return CountIf(test_part_results_, TestPartNonfatallyFailed) > 0; } // Gets the number of all test parts. This is the sum of the number // of successful test parts and the number of failed test parts. int TestResult::total_part_count() const { return static_cast(test_part_results_.size()); } // Returns the number of the test properties. int TestResult::test_property_count() const { return static_cast(test_properties_.size()); } // class Test // Creates a Test object. // The c'tor saves the values of all Google Test flags. Test::Test() : gtest_flag_saver_(new internal::GTestFlagSaver) { } // The d'tor restores the values of all Google Test flags. Test::~Test() { delete gtest_flag_saver_; } // Sets up the test fixture. // // A sub-class may override this. void Test::SetUp() { } // Tears down the test fixture. // // A sub-class may override this. void Test::TearDown() { } // Allows user supplied key value pairs to be recorded for later output. void Test::RecordProperty(const std::string& key, const std::string& value) { UnitTest::GetInstance()->RecordProperty(key, value); } // Allows user supplied key value pairs to be recorded for later output. void Test::RecordProperty(const std::string& key, int value) { Message value_message; value_message << value; RecordProperty(key, value_message.GetString().c_str()); } namespace internal { void ReportFailureInUnknownLocation(TestPartResult::Type result_type, const std::string& message) { // This function is a friend of UnitTest and as such has access to // AddTestPartResult. UnitTest::GetInstance()->AddTestPartResult( result_type, NULL, // No info about the source file where the exception occurred. -1, // We have no info on which line caused the exception. message, ""); // No stack trace, either. } } // namespace internal // Google Test requires all tests in the same test case to use the same test // fixture class. This function checks if the current test has the // same fixture class as the first test in the current test case. If // yes, it returns true; otherwise it generates a Google Test failure and // returns false. bool Test::HasSameFixtureClass() { internal::UnitTestImpl* const impl = internal::GetUnitTestImpl(); const TestCase* const test_case = impl->current_test_case(); // Info about the first test in the current test case. const TestInfo* const first_test_info = test_case->test_info_list()[0]; const internal::TypeId first_fixture_id = first_test_info->fixture_class_id_; const char* const first_test_name = first_test_info->name(); // Info about the current test. const TestInfo* const this_test_info = impl->current_test_info(); const internal::TypeId this_fixture_id = this_test_info->fixture_class_id_; const char* const this_test_name = this_test_info->name(); if (this_fixture_id != first_fixture_id) { // Is the first test defined using TEST? const bool first_is_TEST = first_fixture_id == internal::GetTestTypeId(); // Is this test defined using TEST? const bool this_is_TEST = this_fixture_id == internal::GetTestTypeId(); if (first_is_TEST || this_is_TEST) { // The user mixed TEST and TEST_F in this test case - we'll tell // him/her how to fix it. // Gets the name of the TEST and the name of the TEST_F. Note // that first_is_TEST and this_is_TEST cannot both be true, as // the fixture IDs are different for the two tests. const char* const TEST_name = first_is_TEST ? first_test_name : this_test_name; const char* const TEST_F_name = first_is_TEST ? this_test_name : first_test_name; ADD_FAILURE() << "All tests in the same test case must use the same test fixture\n" << "class, so mixing TEST_F and TEST in the same test case is\n" << "illegal. In test case " << this_test_info->test_case_name() << ",\n" << "test " << TEST_F_name << " is defined using TEST_F but\n" << "test " << TEST_name << " is defined using TEST. You probably\n" << "want to change the TEST to TEST_F or move it to another test\n" << "case."; } else { // The user defined two fixture classes with the same name in // two namespaces - we'll tell him/her how to fix it. ADD_FAILURE() << "All tests in the same test case must use the same test fixture\n" << "class. However, in test case " << this_test_info->test_case_name() << ",\n" << "you defined test " << first_test_name << " and test " << this_test_name << "\n" << "using two different test fixture classes. This can happen if\n" << "the two classes are from different namespaces or translation\n" << "units and have the same name. You should probably rename one\n" << "of the classes to put the tests into different test cases."; } return false; } return true; } #if GTEST_HAS_SEH // Adds an "exception thrown" fatal failure to the current test. This // function returns its result via an output parameter pointer because VC++ // prohibits creation of objects with destructors on stack in functions // using __try (see error C2712). static std::string* FormatSehExceptionMessage(DWORD exception_code, const char* location) { Message message; message << "SEH exception with code 0x" << std::setbase(16) << exception_code << std::setbase(10) << " thrown in " << location << "."; return new std::string(message.GetString()); } #endif // GTEST_HAS_SEH namespace internal { #if GTEST_HAS_EXCEPTIONS // Adds an "exception thrown" fatal failure to the current test. static std::string FormatCxxExceptionMessage(const char* description, const char* location) { Message message; if (description != NULL) { message << "C++ exception with description \"" << description << "\""; } else { message << "Unknown C++ exception"; } message << " thrown in " << location << "."; return message.GetString(); } static std::string PrintTestPartResultToString( const TestPartResult& test_part_result); GoogleTestFailureException::GoogleTestFailureException( const TestPartResult& failure) : ::std::runtime_error(PrintTestPartResultToString(failure).c_str()) {} #endif // GTEST_HAS_EXCEPTIONS // We put these helper functions in the internal namespace as IBM's xlC // compiler rejects the code if they were declared static. // Runs the given method and handles SEH exceptions it throws, when // SEH is supported; returns the 0-value for type Result in case of an // SEH exception. (Microsoft compilers cannot handle SEH and C++ // exceptions in the same function. Therefore, we provide a separate // wrapper function for handling SEH exceptions.) template Result HandleSehExceptionsInMethodIfSupported( T* object, Result(T::*method)(), const char* location) { #if GTEST_HAS_SEH __try { return (object->*method)(); } __except (internal::UnitTestOptions::GTestShouldProcessSEH( // NOLINT GetExceptionCode())) { // We create the exception message on the heap because VC++ prohibits // creation of objects with destructors on stack in functions using __try // (see error C2712). std::string* exception_message = FormatSehExceptionMessage( GetExceptionCode(), location); internal::ReportFailureInUnknownLocation(TestPartResult::kFatalFailure, *exception_message); delete exception_message; return static_cast(0); } #else (void)location; return (object->*method)(); #endif // GTEST_HAS_SEH } // Runs the given method and catches and reports C++ and/or SEH-style // exceptions, if they are supported; returns the 0-value for type // Result in case of an SEH exception. template Result HandleExceptionsInMethodIfSupported( T* object, Result(T::*method)(), const char* location) { // NOTE: The user code can affect the way in which Google Test handles // exceptions by setting GTEST_FLAG(catch_exceptions), but only before // RUN_ALL_TESTS() starts. It is technically possible to check the flag // after the exception is caught and either report or re-throw the // exception based on the flag's value: // // try { // // Perform the test method. // } catch (...) { // if (GTEST_FLAG(catch_exceptions)) // // Report the exception as failure. // else // throw; // Re-throws the original exception. // } // // However, the purpose of this flag is to allow the program to drop into // the debugger when the exception is thrown. On most platforms, once the // control enters the catch block, the exception origin information is // lost and the debugger will stop the program at the point of the // re-throw in this function -- instead of at the point of the original // throw statement in the code under test. For this reason, we perform // the check early, sacrificing the ability to affect Google Test's // exception handling in the method where the exception is thrown. if (internal::GetUnitTestImpl()->catch_exceptions()) { #if GTEST_HAS_EXCEPTIONS try { return HandleSehExceptionsInMethodIfSupported(object, method, location); } catch (const internal::GoogleTestFailureException&) { // NOLINT // This exception type can only be thrown by a failed Google // Test assertion with the intention of letting another testing // framework catch it. Therefore we just re-throw it. throw; } catch (const std::exception& e) { // NOLINT internal::ReportFailureInUnknownLocation( TestPartResult::kFatalFailure, FormatCxxExceptionMessage(e.what(), location)); } catch (...) { // NOLINT internal::ReportFailureInUnknownLocation( TestPartResult::kFatalFailure, FormatCxxExceptionMessage(NULL, location)); } return static_cast(0); #else return HandleSehExceptionsInMethodIfSupported(object, method, location); #endif // GTEST_HAS_EXCEPTIONS } else { return (object->*method)(); } } } // namespace internal // Runs the test and updates the test result. void Test::Run() { if (!HasSameFixtureClass()) return; internal::UnitTestImpl* const impl = internal::GetUnitTestImpl(); impl->os_stack_trace_getter()->UponLeavingGTest(); internal::HandleExceptionsInMethodIfSupported(this, &Test::SetUp, "SetUp()"); // We will run the test only if SetUp() was successful. if (!HasFatalFailure()) { impl->os_stack_trace_getter()->UponLeavingGTest(); internal::HandleExceptionsInMethodIfSupported( this, &Test::TestBody, "the test body"); } // However, we want to clean up as much as possible. Hence we will // always call TearDown(), even if SetUp() or the test body has // failed. impl->os_stack_trace_getter()->UponLeavingGTest(); internal::HandleExceptionsInMethodIfSupported( this, &Test::TearDown, "TearDown()"); } // Returns true iff the current test has a fatal failure. bool Test::HasFatalFailure() { return internal::GetUnitTestImpl()->current_test_result()->HasFatalFailure(); } // Returns true iff the current test has a non-fatal failure. bool Test::HasNonfatalFailure() { return internal::GetUnitTestImpl()->current_test_result()-> HasNonfatalFailure(); } // class TestInfo // Constructs a TestInfo object. It assumes ownership of the test factory // object. TestInfo::TestInfo(const std::string& a_test_case_name, const std::string& a_name, const char* a_type_param, const char* a_value_param, internal::TypeId fixture_class_id, internal::TestFactoryBase* factory) : test_case_name_(a_test_case_name), name_(a_name), type_param_(a_type_param ? new std::string(a_type_param) : NULL), value_param_(a_value_param ? new std::string(a_value_param) : NULL), fixture_class_id_(fixture_class_id), should_run_(false), is_disabled_(false), matches_filter_(false), factory_(factory), result_() {} // Destructs a TestInfo object. TestInfo::~TestInfo() { delete factory_; } namespace internal { // Creates a new TestInfo object and registers it with Google Test; // returns the created object. // // Arguments: // // test_case_name: name of the test case // name: name of the test // type_param: the name of the test's type parameter, or NULL if // this is not a typed or a type-parameterized test. // value_param: text representation of the test's value parameter, // or NULL if this is not a value-parameterized test. // fixture_class_id: ID of the test fixture class // set_up_tc: pointer to the function that sets up the test case // tear_down_tc: pointer to the function that tears down the test case // factory: pointer to the factory that creates a test object. // The newly created TestInfo instance will assume // ownership of the factory object. TestInfo* MakeAndRegisterTestInfo( const char* test_case_name, const char* name, const char* type_param, const char* value_param, TypeId fixture_class_id, SetUpTestCaseFunc set_up_tc, TearDownTestCaseFunc tear_down_tc, TestFactoryBase* factory) { TestInfo* const test_info = new TestInfo(test_case_name, name, type_param, value_param, fixture_class_id, factory); GetUnitTestImpl()->AddTestInfo(set_up_tc, tear_down_tc, test_info); return test_info; } #if GTEST_HAS_PARAM_TEST void ReportInvalidTestCaseType(const char* test_case_name, const char* file, int line) { Message errors; errors << "Attempted redefinition of test case " << test_case_name << ".\n" << "All tests in the same test case must use the same test fixture\n" << "class. However, in test case " << test_case_name << ", you tried\n" << "to define a test using a fixture class different from the one\n" << "used earlier. This can happen if the two fixture classes are\n" << "from different namespaces and have the same name. You should\n" << "probably rename one of the classes to put the tests into different\n" << "test cases."; fprintf(stderr, "%s %s", FormatFileLocation(file, line).c_str(), errors.GetString().c_str()); } #endif // GTEST_HAS_PARAM_TEST } // namespace internal namespace { // A predicate that checks the test name of a TestInfo against a known // value. // // This is used for implementation of the TestCase class only. We put // it in the anonymous namespace to prevent polluting the outer // namespace. // // TestNameIs is copyable. class TestNameIs { public: // Constructor. // // TestNameIs has NO default constructor. explicit TestNameIs(const char* name) : name_(name) {} // Returns true iff the test name of test_info matches name_. bool operator()(const TestInfo * test_info) const { return test_info && test_info->name() == name_; } private: std::string name_; }; } // namespace namespace internal { // This method expands all parameterized tests registered with macros TEST_P // and INSTANTIATE_TEST_CASE_P into regular tests and registers those. // This will be done just once during the program runtime. void UnitTestImpl::RegisterParameterizedTests() { #if GTEST_HAS_PARAM_TEST if (!parameterized_tests_registered_) { parameterized_test_registry_.RegisterTests(); parameterized_tests_registered_ = true; } #endif } } // namespace internal // Creates the test object, runs it, records its result, and then // deletes it. void TestInfo::Run() { if (!should_run_) return; // Tells UnitTest where to store test result. internal::UnitTestImpl* const impl = internal::GetUnitTestImpl(); impl->set_current_test_info(this); TestEventListener* repeater = UnitTest::GetInstance()->listeners().repeater(); // Notifies the unit test event listeners that a test is about to start. repeater->OnTestStart(*this); const TimeInMillis start = internal::GetTimeInMillis(); impl->os_stack_trace_getter()->UponLeavingGTest(); // Creates the test object. Test* const test = internal::HandleExceptionsInMethodIfSupported( factory_, &internal::TestFactoryBase::CreateTest, "the test fixture's constructor"); // Runs the test only if the test object was created and its // constructor didn't generate a fatal failure. if ((test != NULL) && !Test::HasFatalFailure()) { // This doesn't throw as all user code that can throw are wrapped into // exception handling code. test->Run(); } // Deletes the test object. impl->os_stack_trace_getter()->UponLeavingGTest(); internal::HandleExceptionsInMethodIfSupported( test, &Test::DeleteSelf_, "the test fixture's destructor"); result_.set_elapsed_time(internal::GetTimeInMillis() - start); // Notifies the unit test event listener that a test has just finished. repeater->OnTestEnd(*this); // Tells UnitTest to stop associating assertion results to this // test. impl->set_current_test_info(NULL); } // class TestCase // Gets the number of successful tests in this test case. int TestCase::successful_test_count() const { return CountIf(test_info_list_, TestPassed); } // Gets the number of failed tests in this test case. int TestCase::failed_test_count() const { return CountIf(test_info_list_, TestFailed); } // Gets the number of disabled tests that will be reported in the XML report. int TestCase::reportable_disabled_test_count() const { return CountIf(test_info_list_, TestReportableDisabled); } // Gets the number of disabled tests in this test case. int TestCase::disabled_test_count() const { return CountIf(test_info_list_, TestDisabled); } // Gets the number of tests to be printed in the XML report. int TestCase::reportable_test_count() const { return CountIf(test_info_list_, TestReportable); } // Get the number of tests in this test case that should run. int TestCase::test_to_run_count() const { return CountIf(test_info_list_, ShouldRunTest); } // Gets the number of all tests. int TestCase::total_test_count() const { return static_cast(test_info_list_.size()); } // Creates a TestCase with the given name. // // Arguments: // // name: name of the test case // a_type_param: the name of the test case's type parameter, or NULL if // this is not a typed or a type-parameterized test case. // set_up_tc: pointer to the function that sets up the test case // tear_down_tc: pointer to the function that tears down the test case TestCase::TestCase(const char* a_name, const char* a_type_param, Test::SetUpTestCaseFunc set_up_tc, Test::TearDownTestCaseFunc tear_down_tc) : name_(a_name), type_param_(a_type_param ? new std::string(a_type_param) : NULL), set_up_tc_(set_up_tc), tear_down_tc_(tear_down_tc), should_run_(false), elapsed_time_(0) { } // Destructor of TestCase. TestCase::~TestCase() { // Deletes every Test in the collection. ForEach(test_info_list_, internal::Delete); } // Returns the i-th test among all the tests. i can range from 0 to // total_test_count() - 1. If i is not in that range, returns NULL. const TestInfo* TestCase::GetTestInfo(int i) const { const int index = GetElementOr(test_indices_, i, -1); return index < 0 ? NULL : test_info_list_[index]; } // Returns the i-th test among all the tests. i can range from 0 to // total_test_count() - 1. If i is not in that range, returns NULL. TestInfo* TestCase::GetMutableTestInfo(int i) { const int index = GetElementOr(test_indices_, i, -1); return index < 0 ? NULL : test_info_list_[index]; } // Adds a test to this test case. Will delete the test upon // destruction of the TestCase object. void TestCase::AddTestInfo(TestInfo * test_info) { test_info_list_.push_back(test_info); test_indices_.push_back(static_cast(test_indices_.size())); } // Runs every test in this TestCase. void TestCase::Run() { if (!should_run_) return; internal::UnitTestImpl* const impl = internal::GetUnitTestImpl(); impl->set_current_test_case(this); TestEventListener* repeater = UnitTest::GetInstance()->listeners().repeater(); repeater->OnTestCaseStart(*this); impl->os_stack_trace_getter()->UponLeavingGTest(); internal::HandleExceptionsInMethodIfSupported( this, &TestCase::RunSetUpTestCase, "SetUpTestCase()"); const internal::TimeInMillis start = internal::GetTimeInMillis(); for (int i = 0; i < total_test_count(); i++) { GetMutableTestInfo(i)->Run(); } elapsed_time_ = internal::GetTimeInMillis() - start; impl->os_stack_trace_getter()->UponLeavingGTest(); internal::HandleExceptionsInMethodIfSupported( this, &TestCase::RunTearDownTestCase, "TearDownTestCase()"); repeater->OnTestCaseEnd(*this); impl->set_current_test_case(NULL); } // Clears the results of all tests in this test case. void TestCase::ClearResult() { ad_hoc_test_result_.Clear(); ForEach(test_info_list_, TestInfo::ClearTestResult); } // Shuffles the tests in this test case. void TestCase::ShuffleTests(internal::Random* random) { Shuffle(random, &test_indices_); } // Restores the test order to before the first shuffle. void TestCase::UnshuffleTests() { for (size_t i = 0; i < test_indices_.size(); i++) { test_indices_[i] = static_cast(i); } } // Formats a countable noun. Depending on its quantity, either the // singular form or the plural form is used. e.g. // // FormatCountableNoun(1, "formula", "formuli") returns "1 formula". // FormatCountableNoun(5, "book", "books") returns "5 books". static std::string FormatCountableNoun(int count, const char * singular_form, const char * plural_form) { return internal::StreamableToString(count) + " " + (count == 1 ? singular_form : plural_form); } // Formats the count of tests. static std::string FormatTestCount(int test_count) { return FormatCountableNoun(test_count, "test", "tests"); } // Formats the count of test cases. static std::string FormatTestCaseCount(int test_case_count) { return FormatCountableNoun(test_case_count, "test case", "test cases"); } // Converts a TestPartResult::Type enum to human-friendly string // representation. Both kNonFatalFailure and kFatalFailure are translated // to "Failure", as the user usually doesn't care about the difference // between the two when viewing the test result. static const char * TestPartResultTypeToString(TestPartResult::Type type) { switch (type) { case TestPartResult::kSuccess: return "Success"; case TestPartResult::kNonFatalFailure: case TestPartResult::kFatalFailure: #ifdef _MSC_VER return "error: "; #else return "Failure\n"; #endif default: return "Unknown result type"; } } namespace internal { // Prints a TestPartResult to an std::string. static std::string PrintTestPartResultToString( const TestPartResult& test_part_result) { return (Message() << internal::FormatFileLocation(test_part_result.file_name(), test_part_result.line_number()) << " " << TestPartResultTypeToString(test_part_result.type()) << test_part_result.message()).GetString(); } // Prints a TestPartResult. static void PrintTestPartResult(const TestPartResult& test_part_result) { const std::string& result = PrintTestPartResultToString(test_part_result); printf("%s\n", result.c_str()); fflush(stdout); // If the test program runs in Visual Studio or a debugger, the // following statements add the test part result message to the Output // window such that the user can double-click on it to jump to the // corresponding source code location; otherwise they do nothing. #if GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MOBILE // We don't call OutputDebugString*() on Windows Mobile, as printing // to stdout is done by OutputDebugString() there already - we don't // want the same message printed twice. ::OutputDebugStringA(result.c_str()); ::OutputDebugStringA("\n"); #endif } // class PrettyUnitTestResultPrinter enum GTestColor { COLOR_DEFAULT, COLOR_RED, COLOR_GREEN, COLOR_YELLOW }; #if GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MOBILE // Returns the character attribute for the given color. WORD GetColorAttribute(GTestColor color) { switch (color) { case COLOR_RED: return FOREGROUND_RED; case COLOR_GREEN: return FOREGROUND_GREEN; case COLOR_YELLOW: return FOREGROUND_RED | FOREGROUND_GREEN; default: return 0; } } #else // Returns the ANSI color code for the given color. COLOR_DEFAULT is // an invalid input. const char* GetAnsiColorCode(GTestColor color) { switch (color) { case COLOR_RED: return "1"; case COLOR_GREEN: return "2"; case COLOR_YELLOW: return "3"; default: return NULL; }; } #endif // GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MOBILE // Returns true iff Google Test should use colors in the output. bool ShouldUseColor(bool stdout_is_tty) { const char* const gtest_color = GTEST_FLAG(color).c_str(); if (String::CaseInsensitiveCStringEquals(gtest_color, "auto")) { #if GTEST_OS_WINDOWS // On Windows the TERM variable is usually not set, but the // console there does support colors. return stdout_is_tty; #else // On non-Windows platforms, we rely on the TERM variable. const char* const term = posix::GetEnv("TERM"); const bool term_supports_color = String::CStringEquals(term, "xterm") || String::CStringEquals(term, "xterm-color") || String::CStringEquals(term, "xterm-256color") || String::CStringEquals(term, "screen") || String::CStringEquals(term, "screen-256color") || String::CStringEquals(term, "linux") || String::CStringEquals(term, "cygwin"); return stdout_is_tty && term_supports_color; #endif // GTEST_OS_WINDOWS } return String::CaseInsensitiveCStringEquals(gtest_color, "yes") || String::CaseInsensitiveCStringEquals(gtest_color, "true") || String::CaseInsensitiveCStringEquals(gtest_color, "t") || String::CStringEquals(gtest_color, "1"); // We take "yes", "true", "t", and "1" as meaning "yes". If the // value is neither one of these nor "auto", we treat it as "no" to // be conservative. } // Helpers for printing colored strings to stdout. Note that on Windows, we // cannot simply emit special characters and have the terminal change colors. // This routine must actually emit the characters rather than return a string // that would be colored when printed, as can be done on Linux. void ColoredPrintf(GTestColor color, const char* fmt, ...) { va_list args; va_start(args, fmt); #if GTEST_OS_WINDOWS_MOBILE || GTEST_OS_SYMBIAN || GTEST_OS_ZOS || GTEST_OS_IOS const bool use_color = false; #else static const bool in_color_mode = ShouldUseColor(posix::IsATTY(posix::FileNo(stdout)) != 0); const bool use_color = in_color_mode && (color != COLOR_DEFAULT); #endif // GTEST_OS_WINDOWS_MOBILE || GTEST_OS_SYMBIAN || GTEST_OS_ZOS // The '!= 0' comparison is necessary to satisfy MSVC 7.1. if (!use_color) { vprintf(fmt, args); va_end(args); return; } #if GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MOBILE const HANDLE stdout_handle = GetStdHandle(STD_OUTPUT_HANDLE); // Gets the current text color. CONSOLE_SCREEN_BUFFER_INFO buffer_info; GetConsoleScreenBufferInfo(stdout_handle, &buffer_info); const WORD old_color_attrs = buffer_info.wAttributes; // We need to flush the stream buffers into the console before each // SetConsoleTextAttribute call lest it affect the text that is already // printed but has not yet reached the console. fflush(stdout); SetConsoleTextAttribute(stdout_handle, GetColorAttribute(color) | FOREGROUND_INTENSITY); vprintf(fmt, args); fflush(stdout); // Restores the text color. SetConsoleTextAttribute(stdout_handle, old_color_attrs); #else printf("\033[0;3%sm", GetAnsiColorCode(color)); vprintf(fmt, args); printf("\033[m"); // Resets the terminal to default. #endif // GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MOBILE va_end(args); } // Text printed in Google Test's text output and --gunit_list_tests // output to label the type parameter and value parameter for a test. static const char kTypeParamLabel[] = "TypeParam"; static const char kValueParamLabel[] = "GetParam()"; void PrintFullTestCommentIfPresent(const TestInfo& test_info) { const char* const type_param = test_info.type_param(); const char* const value_param = test_info.value_param(); if (type_param != NULL || value_param != NULL) { printf(", where "); if (type_param != NULL) { printf("%s = %s", kTypeParamLabel, type_param); if (value_param != NULL) printf(" and "); } if (value_param != NULL) { printf("%s = %s", kValueParamLabel, value_param); } } } // This class implements the TestEventListener interface. // // Class PrettyUnitTestResultPrinter is copyable. class PrettyUnitTestResultPrinter : public TestEventListener { public: PrettyUnitTestResultPrinter() {} static void PrintTestName(const char * test_case, const char * test) { printf("%s.%s", test_case, test); } // The following methods override what's in the TestEventListener class. virtual void OnTestProgramStart(const UnitTest& /*unit_test*/) {} virtual void OnTestIterationStart(const UnitTest& unit_test, int iteration); virtual void OnEnvironmentsSetUpStart(const UnitTest& unit_test); virtual void OnEnvironmentsSetUpEnd(const UnitTest& /*unit_test*/) {} virtual void OnTestCaseStart(const TestCase& test_case); virtual void OnTestStart(const TestInfo& test_info); virtual void OnTestPartResult(const TestPartResult& result); virtual void OnTestEnd(const TestInfo& test_info); virtual void OnTestCaseEnd(const TestCase& test_case); virtual void OnEnvironmentsTearDownStart(const UnitTest& unit_test); virtual void OnEnvironmentsTearDownEnd(const UnitTest& /*unit_test*/) {} virtual void OnTestIterationEnd(const UnitTest& unit_test, int iteration); virtual void OnTestProgramEnd(const UnitTest& /*unit_test*/) {} private: static void PrintFailedTests(const UnitTest& unit_test); }; // Fired before each iteration of tests starts. void PrettyUnitTestResultPrinter::OnTestIterationStart( const UnitTest& unit_test, int iteration) { if (GTEST_FLAG(repeat) != 1) printf("\nRepeating all tests (iteration %d) . . .\n\n", iteration + 1); const char* const filter = GTEST_FLAG(filter).c_str(); // Prints the filter if it's not *. This reminds the user that some // tests may be skipped. if (!String::CStringEquals(filter, kUniversalFilter)) { ColoredPrintf(COLOR_YELLOW, "Note: %s filter = %s\n", GTEST_NAME_, filter); } if (internal::ShouldShard(kTestTotalShards, kTestShardIndex, false)) { const Int32 shard_index = Int32FromEnvOrDie(kTestShardIndex, -1); ColoredPrintf(COLOR_YELLOW, "Note: This is test shard %d of %s.\n", static_cast(shard_index) + 1, internal::posix::GetEnv(kTestTotalShards)); } if (GTEST_FLAG(shuffle)) { ColoredPrintf(COLOR_YELLOW, "Note: Randomizing tests' orders with a seed of %d .\n", unit_test.random_seed()); } ColoredPrintf(COLOR_GREEN, "[==========] "); printf("Running %s from %s.\n", FormatTestCount(unit_test.test_to_run_count()).c_str(), FormatTestCaseCount(unit_test.test_case_to_run_count()).c_str()); fflush(stdout); } void PrettyUnitTestResultPrinter::OnEnvironmentsSetUpStart( const UnitTest& /*unit_test*/) { ColoredPrintf(COLOR_GREEN, "[----------] "); printf("Global test environment set-up.\n"); fflush(stdout); } void PrettyUnitTestResultPrinter::OnTestCaseStart(const TestCase& test_case) { const std::string counts = FormatCountableNoun(test_case.test_to_run_count(), "test", "tests"); ColoredPrintf(COLOR_GREEN, "[----------] "); printf("%s from %s", counts.c_str(), test_case.name()); if (test_case.type_param() == NULL) { printf("\n"); } else { printf(", where %s = %s\n", kTypeParamLabel, test_case.type_param()); } fflush(stdout); } void PrettyUnitTestResultPrinter::OnTestStart(const TestInfo& test_info) { ColoredPrintf(COLOR_GREEN, "[ RUN ] "); PrintTestName(test_info.test_case_name(), test_info.name()); printf("\n"); fflush(stdout); } // Called after an assertion failure. void PrettyUnitTestResultPrinter::OnTestPartResult( const TestPartResult& result) { // If the test part succeeded, we don't need to do anything. if (result.type() == TestPartResult::kSuccess) return; // Print failure message from the assertion (e.g. expected this and got that). PrintTestPartResult(result); fflush(stdout); } void PrettyUnitTestResultPrinter::OnTestEnd(const TestInfo& test_info) { if (test_info.result()->Passed()) { ColoredPrintf(COLOR_GREEN, "[ OK ] "); } else { ColoredPrintf(COLOR_RED, "[ FAILED ] "); } PrintTestName(test_info.test_case_name(), test_info.name()); if (test_info.result()->Failed()) PrintFullTestCommentIfPresent(test_info); if (GTEST_FLAG(print_time)) { printf(" (%s ms)\n", internal::StreamableToString( test_info.result()->elapsed_time()).c_str()); } else { printf("\n"); } fflush(stdout); } void PrettyUnitTestResultPrinter::OnTestCaseEnd(const TestCase& test_case) { if (!GTEST_FLAG(print_time)) return; const std::string counts = FormatCountableNoun(test_case.test_to_run_count(), "test", "tests"); ColoredPrintf(COLOR_GREEN, "[----------] "); printf("%s from %s (%s ms total)\n\n", counts.c_str(), test_case.name(), internal::StreamableToString(test_case.elapsed_time()).c_str()); fflush(stdout); } void PrettyUnitTestResultPrinter::OnEnvironmentsTearDownStart( const UnitTest& /*unit_test*/) { ColoredPrintf(COLOR_GREEN, "[----------] "); printf("Global test environment tear-down\n"); fflush(stdout); } // Internal helper for printing the list of failed tests. void PrettyUnitTestResultPrinter::PrintFailedTests(const UnitTest& unit_test) { const int failed_test_count = unit_test.failed_test_count(); if (failed_test_count == 0) { return; } for (int i = 0; i < unit_test.total_test_case_count(); ++i) { const TestCase& test_case = *unit_test.GetTestCase(i); if (!test_case.should_run() || (test_case.failed_test_count() == 0)) { continue; } for (int j = 0; j < test_case.total_test_count(); ++j) { const TestInfo& test_info = *test_case.GetTestInfo(j); if (!test_info.should_run() || test_info.result()->Passed()) { continue; } ColoredPrintf(COLOR_RED, "[ FAILED ] "); printf("%s.%s", test_case.name(), test_info.name()); PrintFullTestCommentIfPresent(test_info); printf("\n"); } } } void PrettyUnitTestResultPrinter::OnTestIterationEnd(const UnitTest& unit_test, int /*iteration*/) { ColoredPrintf(COLOR_GREEN, "[==========] "); printf("%s from %s ran.", FormatTestCount(unit_test.test_to_run_count()).c_str(), FormatTestCaseCount(unit_test.test_case_to_run_count()).c_str()); if (GTEST_FLAG(print_time)) { printf(" (%s ms total)", internal::StreamableToString(unit_test.elapsed_time()).c_str()); } printf("\n"); ColoredPrintf(COLOR_GREEN, "[ PASSED ] "); printf("%s.\n", FormatTestCount(unit_test.successful_test_count()).c_str()); int num_failures = unit_test.failed_test_count(); if (!unit_test.Passed()) { const int failed_test_count = unit_test.failed_test_count(); ColoredPrintf(COLOR_RED, "[ FAILED ] "); printf("%s, listed below:\n", FormatTestCount(failed_test_count).c_str()); PrintFailedTests(unit_test); printf("\n%2d FAILED %s\n", num_failures, num_failures == 1 ? "TEST" : "TESTS"); } int num_disabled = unit_test.reportable_disabled_test_count(); if (num_disabled && !GTEST_FLAG(also_run_disabled_tests)) { if (!num_failures) { printf("\n"); // Add a spacer if no FAILURE banner is displayed. } ColoredPrintf(COLOR_YELLOW, " YOU HAVE %d DISABLED %s\n\n", num_disabled, num_disabled == 1 ? "TEST" : "TESTS"); } // Ensure that Google Test output is printed before, e.g., heapchecker output. fflush(stdout); } // End PrettyUnitTestResultPrinter // class TestEventRepeater // // This class forwards events to other event listeners. class TestEventRepeater : public TestEventListener { public: TestEventRepeater() : forwarding_enabled_(true) {} virtual ~TestEventRepeater(); void Append(TestEventListener *listener); TestEventListener* Release(TestEventListener* listener); // Controls whether events will be forwarded to listeners_. Set to false // in death test child processes. bool forwarding_enabled() const { return forwarding_enabled_; } void set_forwarding_enabled(bool enable) { forwarding_enabled_ = enable; } virtual void OnTestProgramStart(const UnitTest& unit_test); virtual void OnTestIterationStart(const UnitTest& unit_test, int iteration); virtual void OnEnvironmentsSetUpStart(const UnitTest& unit_test); virtual void OnEnvironmentsSetUpEnd(const UnitTest& unit_test); virtual void OnTestCaseStart(const TestCase& test_case); virtual void OnTestStart(const TestInfo& test_info); virtual void OnTestPartResult(const TestPartResult& result); virtual void OnTestEnd(const TestInfo& test_info); virtual void OnTestCaseEnd(const TestCase& test_case); virtual void OnEnvironmentsTearDownStart(const UnitTest& unit_test); virtual void OnEnvironmentsTearDownEnd(const UnitTest& unit_test); virtual void OnTestIterationEnd(const UnitTest& unit_test, int iteration); virtual void OnTestProgramEnd(const UnitTest& unit_test); private: // Controls whether events will be forwarded to listeners_. Set to false // in death test child processes. bool forwarding_enabled_; // The list of listeners that receive events. std::vector listeners_; GTEST_DISALLOW_COPY_AND_ASSIGN_(TestEventRepeater); }; TestEventRepeater::~TestEventRepeater() { ForEach(listeners_, Delete); } void TestEventRepeater::Append(TestEventListener *listener) { listeners_.push_back(listener); } // TODO(vladl@google.com): Factor the search functionality into Vector::Find. TestEventListener* TestEventRepeater::Release(TestEventListener *listener) { for (size_t i = 0; i < listeners_.size(); ++i) { if (listeners_[i] == listener) { listeners_.erase(listeners_.begin() + i); return listener; } } return NULL; } // Since most methods are very similar, use macros to reduce boilerplate. // This defines a member that forwards the call to all listeners. #define GTEST_REPEATER_METHOD_(Name, Type) \ void TestEventRepeater::Name(const Type& parameter) { \ if (forwarding_enabled_) { \ for (size_t i = 0; i < listeners_.size(); i++) { \ listeners_[i]->Name(parameter); \ } \ } \ } // This defines a member that forwards the call to all listeners in reverse // order. #define GTEST_REVERSE_REPEATER_METHOD_(Name, Type) \ void TestEventRepeater::Name(const Type& parameter) { \ if (forwarding_enabled_) { \ for (int i = static_cast(listeners_.size()) - 1; i >= 0; i--) { \ listeners_[i]->Name(parameter); \ } \ } \ } GTEST_REPEATER_METHOD_(OnTestProgramStart, UnitTest) GTEST_REPEATER_METHOD_(OnEnvironmentsSetUpStart, UnitTest) GTEST_REPEATER_METHOD_(OnTestCaseStart, TestCase) GTEST_REPEATER_METHOD_(OnTestStart, TestInfo) GTEST_REPEATER_METHOD_(OnTestPartResult, TestPartResult) GTEST_REPEATER_METHOD_(OnEnvironmentsTearDownStart, UnitTest) GTEST_REVERSE_REPEATER_METHOD_(OnEnvironmentsSetUpEnd, UnitTest) GTEST_REVERSE_REPEATER_METHOD_(OnEnvironmentsTearDownEnd, UnitTest) GTEST_REVERSE_REPEATER_METHOD_(OnTestEnd, TestInfo) GTEST_REVERSE_REPEATER_METHOD_(OnTestCaseEnd, TestCase) GTEST_REVERSE_REPEATER_METHOD_(OnTestProgramEnd, UnitTest) #undef GTEST_REPEATER_METHOD_ #undef GTEST_REVERSE_REPEATER_METHOD_ void TestEventRepeater::OnTestIterationStart(const UnitTest& unit_test, int iteration) { if (forwarding_enabled_) { for (size_t i = 0; i < listeners_.size(); i++) { listeners_[i]->OnTestIterationStart(unit_test, iteration); } } } void TestEventRepeater::OnTestIterationEnd(const UnitTest& unit_test, int iteration) { if (forwarding_enabled_) { for (int i = static_cast(listeners_.size()) - 1; i >= 0; i--) { listeners_[i]->OnTestIterationEnd(unit_test, iteration); } } } // End TestEventRepeater // This class generates an XML output file. class XmlUnitTestResultPrinter : public EmptyTestEventListener { public: explicit XmlUnitTestResultPrinter(const char* output_file); virtual void OnTestIterationEnd(const UnitTest& unit_test, int iteration); private: // Is c a whitespace character that is normalized to a space character // when it appears in an XML attribute value? static bool IsNormalizableWhitespace(char c) { return c == 0x9 || c == 0xA || c == 0xD; } // May c appear in a well-formed XML document? static bool IsValidXmlCharacter(char c) { return IsNormalizableWhitespace(c) || c >= 0x20; } // Returns an XML-escaped copy of the input string str. If // is_attribute is true, the text is meant to appear as an attribute // value, and normalizable whitespace is preserved by replacing it // with character references. static std::string EscapeXml(const std::string& str, bool is_attribute); // Returns the given string with all characters invalid in XML removed. static std::string RemoveInvalidXmlCharacters(const std::string& str); // Convenience wrapper around EscapeXml when str is an attribute value. static std::string EscapeXmlAttribute(const std::string& str) { return EscapeXml(str, true); } // Convenience wrapper around EscapeXml when str is not an attribute value. static std::string EscapeXmlText(const char* str) { return EscapeXml(str, false); } // Verifies that the given attribute belongs to the given element and // streams the attribute as XML. static void OutputXmlAttribute(std::ostream* stream, const std::string& element_name, const std::string& name, const std::string& value); // Streams an XML CDATA section, escaping invalid CDATA sequences as needed. static void OutputXmlCDataSection(::std::ostream* stream, const char* data); // Streams an XML representation of a TestInfo object. static void OutputXmlTestInfo(::std::ostream* stream, const char* test_case_name, const TestInfo& test_info); // Prints an XML representation of a TestCase object static void PrintXmlTestCase(::std::ostream* stream, const TestCase& test_case); // Prints an XML summary of unit_test to output stream out. static void PrintXmlUnitTest(::std::ostream* stream, const UnitTest& unit_test); // Produces a string representing the test properties in a result as space // delimited XML attributes based on the property key="value" pairs. // When the std::string is not empty, it includes a space at the beginning, // to delimit this attribute from prior attributes. static std::string TestPropertiesAsXmlAttributes(const TestResult& result); // The output file. const std::string output_file_; GTEST_DISALLOW_COPY_AND_ASSIGN_(XmlUnitTestResultPrinter); }; // Creates a new XmlUnitTestResultPrinter. XmlUnitTestResultPrinter::XmlUnitTestResultPrinter(const char* output_file) : output_file_(output_file) { if (output_file_.c_str() == NULL || output_file_.empty()) { fprintf(stderr, "XML output file may not be null\n"); fflush(stderr); exit(EXIT_FAILURE); } } // Called after the unit test ends. void XmlUnitTestResultPrinter::OnTestIterationEnd(const UnitTest& unit_test, int /*iteration*/) { FILE* xmlout = NULL; FilePath output_file(output_file_); FilePath output_dir(output_file.RemoveFileName()); if (output_dir.CreateDirectoriesRecursively()) { xmlout = posix::FOpen(output_file_.c_str(), "w"); } if (xmlout == NULL) { // TODO(wan): report the reason of the failure. // // We don't do it for now as: // // 1. There is no urgent need for it. // 2. It's a bit involved to make the errno variable thread-safe on // all three operating systems (Linux, Windows, and Mac OS). // 3. To interpret the meaning of errno in a thread-safe way, // we need the strerror_r() function, which is not available on // Windows. fprintf(stderr, "Unable to open file \"%s\"\n", output_file_.c_str()); fflush(stderr); exit(EXIT_FAILURE); } std::stringstream stream; PrintXmlUnitTest(&stream, unit_test); fprintf(xmlout, "%s", StringStreamToString(&stream).c_str()); fclose(xmlout); } // Returns an XML-escaped copy of the input string str. If is_attribute // is true, the text is meant to appear as an attribute value, and // normalizable whitespace is preserved by replacing it with character // references. // // Invalid XML characters in str, if any, are stripped from the output. // It is expected that most, if not all, of the text processed by this // module will consist of ordinary English text. // If this module is ever modified to produce version 1.1 XML output, // most invalid characters can be retained using character references. // TODO(wan): It might be nice to have a minimally invasive, human-readable // escaping scheme for invalid characters, rather than dropping them. std::string XmlUnitTestResultPrinter::EscapeXml( const std::string& str, bool is_attribute) { Message m; for (size_t i = 0; i < str.size(); ++i) { const char ch = str[i]; switch (ch) { case '<': m << "<"; break; case '>': m << ">"; break; case '&': m << "&"; break; case '\'': if (is_attribute) m << "'"; else m << '\''; break; case '"': if (is_attribute) m << """; else m << '"'; break; default: if (IsValidXmlCharacter(ch)) { if (is_attribute && IsNormalizableWhitespace(ch)) m << "&#x" << String::FormatByte(static_cast(ch)) << ";"; else m << ch; } break; } } return m.GetString(); } // Returns the given string with all characters invalid in XML removed. // Currently invalid characters are dropped from the string. An // alternative is to replace them with certain characters such as . or ?. std::string XmlUnitTestResultPrinter::RemoveInvalidXmlCharacters( const std::string& str) { std::string output; output.reserve(str.size()); for (std::string::const_iterator it = str.begin(); it != str.end(); ++it) if (IsValidXmlCharacter(*it)) output.push_back(*it); return output; } // The following routines generate an XML representation of a UnitTest // object. // // This is how Google Test concepts map to the DTD: // // <-- corresponds to a UnitTest object // <-- corresponds to a TestCase object // <-- corresponds to a TestInfo object // ... // ... // ... // <-- individual assertion failures // // // // Formats the given time in milliseconds as seconds. std::string FormatTimeInMillisAsSeconds(TimeInMillis ms) { ::std::stringstream ss; ss << ms / 1000.0; return ss.str(); } // Converts the given epoch time in milliseconds to a date string in the ISO // 8601 format, without the timezone information. std::string FormatEpochTimeInMillisAsIso8601(TimeInMillis ms) { // Using non-reentrant version as localtime_r is not portable. time_t seconds = static_cast(ms / 1000); #ifdef _MSC_VER # pragma warning(push) // Saves the current warning state. # pragma warning(disable:4996) // Temporarily disables warning 4996 // (function or variable may be unsafe). const struct tm* const time_struct = localtime(&seconds); // NOLINT # pragma warning(pop) // Restores the warning state again. #else const struct tm* const time_struct = localtime(&seconds); // NOLINT #endif if (time_struct == NULL) return ""; // Invalid ms value // YYYY-MM-DDThh:mm:ss return StreamableToString(time_struct->tm_year + 1900) + "-" + String::FormatIntWidth2(time_struct->tm_mon + 1) + "-" + String::FormatIntWidth2(time_struct->tm_mday) + "T" + String::FormatIntWidth2(time_struct->tm_hour) + ":" + String::FormatIntWidth2(time_struct->tm_min) + ":" + String::FormatIntWidth2(time_struct->tm_sec); } // Streams an XML CDATA section, escaping invalid CDATA sequences as needed. void XmlUnitTestResultPrinter::OutputXmlCDataSection(::std::ostream* stream, const char* data) { const char* segment = data; *stream << ""); if (next_segment != NULL) { stream->write( segment, static_cast(next_segment - segment)); *stream << "]]>]]>"); } else { *stream << segment; break; } } *stream << "]]>"; } void XmlUnitTestResultPrinter::OutputXmlAttribute( std::ostream* stream, const std::string& element_name, const std::string& name, const std::string& value) { const std::vector& allowed_names = GetReservedAttributesForElement(element_name); GTEST_CHECK_(std::find(allowed_names.begin(), allowed_names.end(), name) != allowed_names.end()) << "Attribute " << name << " is not allowed for element <" << element_name << ">."; *stream << " " << name << "=\"" << EscapeXmlAttribute(value) << "\""; } // Prints an XML representation of a TestInfo object. // TODO(wan): There is also value in printing properties with the plain printer. void XmlUnitTestResultPrinter::OutputXmlTestInfo(::std::ostream* stream, const char* test_case_name, const TestInfo& test_info) { const TestResult& result = *test_info.result(); const std::string kTestcase = "testcase"; *stream << " \n"; } const string location = internal::FormatCompilerIndependentFileLocation( part.file_name(), part.line_number()); const string summary = location + "\n" + part.summary(); *stream << " "; const string detail = location + "\n" + part.message(); OutputXmlCDataSection(stream, RemoveInvalidXmlCharacters(detail).c_str()); *stream << "\n"; } } if (failures == 0) *stream << " />\n"; else *stream << " \n"; } // Prints an XML representation of a TestCase object void XmlUnitTestResultPrinter::PrintXmlTestCase(std::ostream* stream, const TestCase& test_case) { const std::string kTestsuite = "testsuite"; *stream << " <" << kTestsuite; OutputXmlAttribute(stream, kTestsuite, "name", test_case.name()); OutputXmlAttribute(stream, kTestsuite, "tests", StreamableToString(test_case.reportable_test_count())); OutputXmlAttribute(stream, kTestsuite, "failures", StreamableToString(test_case.failed_test_count())); OutputXmlAttribute( stream, kTestsuite, "disabled", StreamableToString(test_case.reportable_disabled_test_count())); OutputXmlAttribute(stream, kTestsuite, "errors", "0"); OutputXmlAttribute(stream, kTestsuite, "time", FormatTimeInMillisAsSeconds(test_case.elapsed_time())); *stream << TestPropertiesAsXmlAttributes(test_case.ad_hoc_test_result()) << ">\n"; for (int i = 0; i < test_case.total_test_count(); ++i) { if (test_case.GetTestInfo(i)->is_reportable()) OutputXmlTestInfo(stream, test_case.name(), *test_case.GetTestInfo(i)); } *stream << " \n"; } // Prints an XML summary of unit_test to output stream out. void XmlUnitTestResultPrinter::PrintXmlUnitTest(std::ostream* stream, const UnitTest& unit_test) { const std::string kTestsuites = "testsuites"; *stream << "\n"; *stream << "<" << kTestsuites; OutputXmlAttribute(stream, kTestsuites, "tests", StreamableToString(unit_test.reportable_test_count())); OutputXmlAttribute(stream, kTestsuites, "failures", StreamableToString(unit_test.failed_test_count())); OutputXmlAttribute( stream, kTestsuites, "disabled", StreamableToString(unit_test.reportable_disabled_test_count())); OutputXmlAttribute(stream, kTestsuites, "errors", "0"); OutputXmlAttribute( stream, kTestsuites, "timestamp", FormatEpochTimeInMillisAsIso8601(unit_test.start_timestamp())); OutputXmlAttribute(stream, kTestsuites, "time", FormatTimeInMillisAsSeconds(unit_test.elapsed_time())); if (GTEST_FLAG(shuffle)) { OutputXmlAttribute(stream, kTestsuites, "random_seed", StreamableToString(unit_test.random_seed())); } *stream << TestPropertiesAsXmlAttributes(unit_test.ad_hoc_test_result()); OutputXmlAttribute(stream, kTestsuites, "name", "AllTests"); *stream << ">\n"; for (int i = 0; i < unit_test.total_test_case_count(); ++i) { if (unit_test.GetTestCase(i)->reportable_test_count() > 0) PrintXmlTestCase(stream, *unit_test.GetTestCase(i)); } *stream << "\n"; } // Produces a string representing the test properties in a result as space // delimited XML attributes based on the property key="value" pairs. std::string XmlUnitTestResultPrinter::TestPropertiesAsXmlAttributes( const TestResult& result) { Message attributes; for (int i = 0; i < result.test_property_count(); ++i) { const TestProperty& property = result.GetTestProperty(i); attributes << " " << property.key() << "=" << "\"" << EscapeXmlAttribute(property.value()) << "\""; } return attributes.GetString(); } // End XmlUnitTestResultPrinter #if GTEST_CAN_STREAM_RESULTS_ // Checks if str contains '=', '&', '%' or '\n' characters. If yes, // replaces them by "%xx" where xx is their hexadecimal value. For // example, replaces "=" with "%3D". This algorithm is O(strlen(str)) // in both time and space -- important as the input str may contain an // arbitrarily long test failure message and stack trace. string StreamingListener::UrlEncode(const char* str) { string result; result.reserve(strlen(str) + 1); for (char ch = *str; ch != '\0'; ch = *++str) { switch (ch) { case '%': case '=': case '&': case '\n': result.append("%" + String::FormatByte(static_cast(ch))); break; default: result.push_back(ch); break; } } return result; } void StreamingListener::SocketWriter::MakeConnection() { GTEST_CHECK_(sockfd_ == -1) << "MakeConnection() can't be called when there is already a connection."; addrinfo hints; memset(&hints, 0, sizeof(hints)); hints.ai_family = AF_UNSPEC; // To allow both IPv4 and IPv6 addresses. hints.ai_socktype = SOCK_STREAM; addrinfo* servinfo = NULL; // Use the getaddrinfo() to get a linked list of IP addresses for // the given host name. const int error_num = getaddrinfo( host_name_.c_str(), port_num_.c_str(), &hints, &servinfo); if (error_num != 0) { GTEST_LOG_(WARNING) << "stream_result_to: getaddrinfo() failed: " << gai_strerror(error_num); } // Loop through all the results and connect to the first we can. for (addrinfo* cur_addr = servinfo; sockfd_ == -1 && cur_addr != NULL; cur_addr = cur_addr->ai_next) { sockfd_ = socket( cur_addr->ai_family, cur_addr->ai_socktype, cur_addr->ai_protocol); if (sockfd_ != -1) { // Connect the client socket to the server socket. if (connect(sockfd_, cur_addr->ai_addr, cur_addr->ai_addrlen) == -1) { close(sockfd_); sockfd_ = -1; } } } freeaddrinfo(servinfo); // all done with this structure if (sockfd_ == -1) { GTEST_LOG_(WARNING) << "stream_result_to: failed to connect to " << host_name_ << ":" << port_num_; } } // End of class Streaming Listener #endif // GTEST_CAN_STREAM_RESULTS__ // Class ScopedTrace // Pushes the given source file location and message onto a per-thread // trace stack maintained by Google Test. ScopedTrace::ScopedTrace(const char* file, int line, const Message& message) GTEST_LOCK_EXCLUDED_(&UnitTest::mutex_) { TraceInfo trace; trace.file = file; trace.line = line; trace.message = message.GetString(); UnitTest::GetInstance()->PushGTestTrace(trace); } // Pops the info pushed by the c'tor. ScopedTrace::~ScopedTrace() GTEST_LOCK_EXCLUDED_(&UnitTest::mutex_) { UnitTest::GetInstance()->PopGTestTrace(); } // class OsStackTraceGetter // Returns the current OS stack trace as an std::string. Parameters: // // max_depth - the maximum number of stack frames to be included // in the trace. // skip_count - the number of top frames to be skipped; doesn't count // against max_depth. // string OsStackTraceGetter::CurrentStackTrace(int /* max_depth */, int /* skip_count */) GTEST_LOCK_EXCLUDED_(mutex_) { return ""; } void OsStackTraceGetter::UponLeavingGTest() GTEST_LOCK_EXCLUDED_(mutex_) { } const char* const OsStackTraceGetter::kElidedFramesMarker = "... " GTEST_NAME_ " internal frames ..."; // A helper class that creates the premature-exit file in its // constructor and deletes the file in its destructor. class ScopedPrematureExitFile { public: explicit ScopedPrematureExitFile(const char* premature_exit_filepath) : premature_exit_filepath_(premature_exit_filepath) { // If a path to the premature-exit file is specified... if (premature_exit_filepath != NULL && *premature_exit_filepath != '\0') { // create the file with a single "0" character in it. I/O // errors are ignored as there's nothing better we can do and we // don't want to fail the test because of this. FILE* pfile = posix::FOpen(premature_exit_filepath, "w"); fwrite("0", 1, 1, pfile); fclose(pfile); } } ~ScopedPrematureExitFile() { if (premature_exit_filepath_ != NULL && *premature_exit_filepath_ != '\0') { remove(premature_exit_filepath_); } } private: const char* const premature_exit_filepath_; GTEST_DISALLOW_COPY_AND_ASSIGN_(ScopedPrematureExitFile); }; } // namespace internal // class TestEventListeners TestEventListeners::TestEventListeners() : repeater_(new internal::TestEventRepeater()), default_result_printer_(NULL), default_xml_generator_(NULL) { } TestEventListeners::~TestEventListeners() { delete repeater_; } // Returns the standard listener responsible for the default console // output. Can be removed from the listeners list to shut down default // console output. Note that removing this object from the listener list // with Release transfers its ownership to the user. void TestEventListeners::Append(TestEventListener* listener) { repeater_->Append(listener); } // Removes the given event listener from the list and returns it. It then // becomes the caller's responsibility to delete the listener. Returns // NULL if the listener is not found in the list. TestEventListener* TestEventListeners::Release(TestEventListener* listener) { if (listener == default_result_printer_) default_result_printer_ = NULL; else if (listener == default_xml_generator_) default_xml_generator_ = NULL; return repeater_->Release(listener); } // Returns repeater that broadcasts the TestEventListener events to all // subscribers. TestEventListener* TestEventListeners::repeater() { return repeater_; } // Sets the default_result_printer attribute to the provided listener. // The listener is also added to the listener list and previous // default_result_printer is removed from it and deleted. The listener can // also be NULL in which case it will not be added to the list. Does // nothing if the previous and the current listener objects are the same. void TestEventListeners::SetDefaultResultPrinter(TestEventListener* listener) { if (default_result_printer_ != listener) { // It is an error to pass this method a listener that is already in the // list. delete Release(default_result_printer_); default_result_printer_ = listener; if (listener != NULL) Append(listener); } } // Sets the default_xml_generator attribute to the provided listener. The // listener is also added to the listener list and previous // default_xml_generator is removed from it and deleted. The listener can // also be NULL in which case it will not be added to the list. Does // nothing if the previous and the current listener objects are the same. void TestEventListeners::SetDefaultXmlGenerator(TestEventListener* listener) { if (default_xml_generator_ != listener) { // It is an error to pass this method a listener that is already in the // list. delete Release(default_xml_generator_); default_xml_generator_ = listener; if (listener != NULL) Append(listener); } } // Controls whether events will be forwarded by the repeater to the // listeners in the list. bool TestEventListeners::EventForwardingEnabled() const { return repeater_->forwarding_enabled(); } void TestEventListeners::SuppressEventForwarding() { repeater_->set_forwarding_enabled(false); } // class UnitTest // Gets the singleton UnitTest object. The first time this method is // called, a UnitTest object is constructed and returned. Consecutive // calls will return the same object. // // We don't protect this under mutex_ as a user is not supposed to // call this before main() starts, from which point on the return // value will never change. UnitTest* UnitTest::GetInstance() { // When compiled with MSVC 7.1 in optimized mode, destroying the // UnitTest object upon exiting the program messes up the exit code, // causing successful tests to appear failed. We have to use a // different implementation in this case to bypass the compiler bug. // This implementation makes the compiler happy, at the cost of // leaking the UnitTest object. // CodeGear C++Builder insists on a public destructor for the // default implementation. Use this implementation to keep good OO // design with private destructor. #if (_MSC_VER == 1310 && !defined(_DEBUG)) || defined(__BORLANDC__) static UnitTest* const instance = new UnitTest; return instance; #else static UnitTest instance; return &instance; #endif // (_MSC_VER == 1310 && !defined(_DEBUG)) || defined(__BORLANDC__) } // Gets the number of successful test cases. int UnitTest::successful_test_case_count() const { return impl()->successful_test_case_count(); } // Gets the number of failed test cases. int UnitTest::failed_test_case_count() const { return impl()->failed_test_case_count(); } // Gets the number of all test cases. int UnitTest::total_test_case_count() const { return impl()->total_test_case_count(); } // Gets the number of all test cases that contain at least one test // that should run. int UnitTest::test_case_to_run_count() const { return impl()->test_case_to_run_count(); } // Gets the number of successful tests. int UnitTest::successful_test_count() const { return impl()->successful_test_count(); } // Gets the number of failed tests. int UnitTest::failed_test_count() const { return impl()->failed_test_count(); } // Gets the number of disabled tests that will be reported in the XML report. int UnitTest::reportable_disabled_test_count() const { return impl()->reportable_disabled_test_count(); } // Gets the number of disabled tests. int UnitTest::disabled_test_count() const { return impl()->disabled_test_count(); } // Gets the number of tests to be printed in the XML report. int UnitTest::reportable_test_count() const { return impl()->reportable_test_count(); } // Gets the number of all tests. int UnitTest::total_test_count() const { return impl()->total_test_count(); } // Gets the number of tests that should run. int UnitTest::test_to_run_count() const { return impl()->test_to_run_count(); } // Gets the time of the test program start, in ms from the start of the // UNIX epoch. internal::TimeInMillis UnitTest::start_timestamp() const { return impl()->start_timestamp(); } // Gets the elapsed time, in milliseconds. internal::TimeInMillis UnitTest::elapsed_time() const { return impl()->elapsed_time(); } // Returns true iff the unit test passed (i.e. all test cases passed). bool UnitTest::Passed() const { return impl()->Passed(); } // Returns true iff the unit test failed (i.e. some test case failed // or something outside of all tests failed). bool UnitTest::Failed() const { return impl()->Failed(); } // Gets the i-th test case among all the test cases. i can range from 0 to // total_test_case_count() - 1. If i is not in that range, returns NULL. const TestCase* UnitTest::GetTestCase(int i) const { return impl()->GetTestCase(i); } // Returns the TestResult containing information on test failures and // properties logged outside of individual test cases. const TestResult& UnitTest::ad_hoc_test_result() const { return *impl()->ad_hoc_test_result(); } // Gets the i-th test case among all the test cases. i can range from 0 to // total_test_case_count() - 1. If i is not in that range, returns NULL. TestCase* UnitTest::GetMutableTestCase(int i) { return impl()->GetMutableTestCase(i); } // Returns the list of event listeners that can be used to track events // inside Google Test. TestEventListeners& UnitTest::listeners() { return *impl()->listeners(); } // Registers and returns a global test environment. When a test // program is run, all global test environments will be set-up in the // order they were registered. After all tests in the program have // finished, all global test environments will be torn-down in the // *reverse* order they were registered. // // The UnitTest object takes ownership of the given environment. // // We don't protect this under mutex_, as we only support calling it // from the main thread. Environment* UnitTest::AddEnvironment(Environment* env) { if (env == NULL) { return NULL; } impl_->environments().push_back(env); return env; } // Adds a TestPartResult to the current TestResult object. All Google Test // assertion macros (e.g. ASSERT_TRUE, EXPECT_EQ, etc) eventually call // this to report their results. The user code should use the // assertion macros instead of calling this directly. void UnitTest::AddTestPartResult( TestPartResult::Type result_type, const char* file_name, int line_number, const std::string& message, const std::string& os_stack_trace) GTEST_LOCK_EXCLUDED_(mutex_) { Message msg; msg << message; internal::MutexLock lock(&mutex_); if (impl_->gtest_trace_stack().size() > 0) { msg << "\n" << GTEST_NAME_ << " trace:"; for (int i = static_cast(impl_->gtest_trace_stack().size()); i > 0; --i) { const internal::TraceInfo& trace = impl_->gtest_trace_stack()[i - 1]; msg << "\n" << internal::FormatFileLocation(trace.file, trace.line) << " " << trace.message; } } if (os_stack_trace.c_str() != NULL && !os_stack_trace.empty()) { msg << internal::kStackTraceMarker << os_stack_trace; } const TestPartResult result = TestPartResult(result_type, file_name, line_number, msg.GetString().c_str()); impl_->GetTestPartResultReporterForCurrentThread()-> ReportTestPartResult(result); if (result_type != TestPartResult::kSuccess) { // gtest_break_on_failure takes precedence over // gtest_throw_on_failure. This allows a user to set the latter // in the code (perhaps in order to use Google Test assertions // with another testing framework) and specify the former on the // command line for debugging. if (GTEST_FLAG(break_on_failure)) { #if GTEST_OS_WINDOWS // Using DebugBreak on Windows allows gtest to still break into a debugger // when a failure happens and both the --gtest_break_on_failure and // the --gtest_catch_exceptions flags are specified. DebugBreak(); #else // Dereference NULL through a volatile pointer to prevent the compiler // from removing. We use this rather than abort() or __builtin_trap() for // portability: Symbian doesn't implement abort() well, and some debuggers // don't correctly trap abort(). *static_cast(NULL) = 1; #endif // GTEST_OS_WINDOWS } else if (GTEST_FLAG(throw_on_failure)) { #if GTEST_HAS_EXCEPTIONS throw internal::GoogleTestFailureException(result); #else // We cannot call abort() as it generates a pop-up in debug mode // that cannot be suppressed in VC 7.1 or below. exit(1); #endif } } } // Adds a TestProperty to the current TestResult object when invoked from // inside a test, to current TestCase's ad_hoc_test_result_ when invoked // from SetUpTestCase or TearDownTestCase, or to the global property set // when invoked elsewhere. If the result already contains a property with // the same key, the value will be updated. void UnitTest::RecordProperty(const std::string& key, const std::string& value) { impl_->RecordProperty(TestProperty(key, value)); } // Runs all tests in this UnitTest object and prints the result. // Returns 0 if successful, or 1 otherwise. // // We don't protect this under mutex_, as we only support calling it // from the main thread. int UnitTest::Run() { const bool in_death_test_child_process = internal::GTEST_FLAG(internal_run_death_test).length() > 0; // Google Test implements this protocol for catching that a test // program exits before returning control to Google Test: // // 1. Upon start, Google Test creates a file whose absolute path // is specified by the environment variable // TEST_PREMATURE_EXIT_FILE. // 2. When Google Test has finished its work, it deletes the file. // // This allows a test runner to set TEST_PREMATURE_EXIT_FILE before // running a Google-Test-based test program and check the existence // of the file at the end of the test execution to see if it has // exited prematurely. // If we are in the child process of a death test, don't // create/delete the premature exit file, as doing so is unnecessary // and will confuse the parent process. Otherwise, create/delete // the file upon entering/leaving this function. If the program // somehow exits before this function has a chance to return, the // premature-exit file will be left undeleted, causing a test runner // that understands the premature-exit-file protocol to report the // test as having failed. const internal::ScopedPrematureExitFile premature_exit_file( in_death_test_child_process ? NULL : internal::posix::GetEnv("TEST_PREMATURE_EXIT_FILE")); // Captures the value of GTEST_FLAG(catch_exceptions). This value will be // used for the duration of the program. impl()->set_catch_exceptions(GTEST_FLAG(catch_exceptions)); #if GTEST_HAS_SEH // Either the user wants Google Test to catch exceptions thrown by the // tests or this is executing in the context of death test child // process. In either case the user does not want to see pop-up dialogs // about crashes - they are expected. if (impl()->catch_exceptions() || in_death_test_child_process) { # if !GTEST_OS_WINDOWS_MOBILE // SetErrorMode doesn't exist on CE. SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOALIGNMENTFAULTEXCEPT | SEM_NOGPFAULTERRORBOX | SEM_NOOPENFILEERRORBOX); # endif // !GTEST_OS_WINDOWS_MOBILE # if (defined(_MSC_VER) || GTEST_OS_WINDOWS_MINGW) && !GTEST_OS_WINDOWS_MOBILE // Death test children can be terminated with _abort(). On Windows, // _abort() can show a dialog with a warning message. This forces the // abort message to go to stderr instead. _set_error_mode(_OUT_TO_STDERR); # endif # if _MSC_VER >= 1400 && !GTEST_OS_WINDOWS_MOBILE // In the debug version, Visual Studio pops up a separate dialog // offering a choice to debug the aborted program. We need to suppress // this dialog or it will pop up for every EXPECT/ASSERT_DEATH statement // executed. Google Test will notify the user of any unexpected // failure via stderr. // // VC++ doesn't define _set_abort_behavior() prior to the version 8.0. // Users of prior VC versions shall suffer the agony and pain of // clicking through the countless debug dialogs. // TODO(vladl@google.com): find a way to suppress the abort dialog() in the // debug mode when compiled with VC 7.1 or lower. if (!GTEST_FLAG(break_on_failure)) _set_abort_behavior( 0x0, // Clear the following flags: _WRITE_ABORT_MSG | _CALL_REPORTFAULT); // pop-up window, core dump. # endif } #endif // GTEST_HAS_SEH return internal::HandleExceptionsInMethodIfSupported( impl(), &internal::UnitTestImpl::RunAllTests, "auxiliary test code (environments or event listeners)") ? 0 : 1; } // Returns the working directory when the first TEST() or TEST_F() was // executed. const char* UnitTest::original_working_dir() const { return impl_->original_working_dir_.c_str(); } // Returns the TestCase object for the test that's currently running, // or NULL if no test is running. const TestCase* UnitTest::current_test_case() const GTEST_LOCK_EXCLUDED_(mutex_) { internal::MutexLock lock(&mutex_); return impl_->current_test_case(); } // Returns the TestInfo object for the test that's currently running, // or NULL if no test is running. const TestInfo* UnitTest::current_test_info() const GTEST_LOCK_EXCLUDED_(mutex_) { internal::MutexLock lock(&mutex_); return impl_->current_test_info(); } // Returns the random seed used at the start of the current test run. int UnitTest::random_seed() const { return impl_->random_seed(); } #if GTEST_HAS_PARAM_TEST // Returns ParameterizedTestCaseRegistry object used to keep track of // value-parameterized tests and instantiate and register them. internal::ParameterizedTestCaseRegistry& UnitTest::parameterized_test_registry() GTEST_LOCK_EXCLUDED_(mutex_) { return impl_->parameterized_test_registry(); } #endif // GTEST_HAS_PARAM_TEST // Creates an empty UnitTest. UnitTest::UnitTest() { impl_ = new internal::UnitTestImpl(this); } // Destructor of UnitTest. UnitTest::~UnitTest() { delete impl_; } // Pushes a trace defined by SCOPED_TRACE() on to the per-thread // Google Test trace stack. void UnitTest::PushGTestTrace(const internal::TraceInfo& trace) GTEST_LOCK_EXCLUDED_(mutex_) { internal::MutexLock lock(&mutex_); impl_->gtest_trace_stack().push_back(trace); } // Pops a trace from the per-thread Google Test trace stack. void UnitTest::PopGTestTrace() GTEST_LOCK_EXCLUDED_(mutex_) { internal::MutexLock lock(&mutex_); impl_->gtest_trace_stack().pop_back(); } namespace internal { UnitTestImpl::UnitTestImpl(UnitTest* parent) : parent_(parent), #ifdef _MSC_VER # pragma warning(push) // Saves the current warning state. # pragma warning(disable:4355) // Temporarily disables warning 4355 // (using this in initializer). default_global_test_part_result_reporter_(this), default_per_thread_test_part_result_reporter_(this), # pragma warning(pop) // Restores the warning state again. #else default_global_test_part_result_reporter_(this), default_per_thread_test_part_result_reporter_(this), #endif // _MSC_VER global_test_part_result_repoter_( &default_global_test_part_result_reporter_), per_thread_test_part_result_reporter_( &default_per_thread_test_part_result_reporter_), #if GTEST_HAS_PARAM_TEST parameterized_test_registry_(), parameterized_tests_registered_(false), #endif // GTEST_HAS_PARAM_TEST last_death_test_case_(-1), current_test_case_(NULL), current_test_info_(NULL), ad_hoc_test_result_(), os_stack_trace_getter_(NULL), post_flag_parse_init_performed_(false), random_seed_(0), // Will be overridden by the flag before first use. random_(0), // Will be reseeded before first use. start_timestamp_(0), elapsed_time_(0), #if GTEST_HAS_DEATH_TEST death_test_factory_(new DefaultDeathTestFactory), #endif // Will be overridden by the flag before first use. catch_exceptions_(false) { listeners()->SetDefaultResultPrinter(new PrettyUnitTestResultPrinter); } UnitTestImpl::~UnitTestImpl() { // Deletes every TestCase. ForEach(test_cases_, internal::Delete); // Deletes every Environment. ForEach(environments_, internal::Delete); delete os_stack_trace_getter_; } // Adds a TestProperty to the current TestResult object when invoked in a // context of a test, to current test case's ad_hoc_test_result when invoke // from SetUpTestCase/TearDownTestCase, or to the global property set // otherwise. If the result already contains a property with the same key, // the value will be updated. void UnitTestImpl::RecordProperty(const TestProperty& test_property) { std::string xml_element; TestResult* test_result; // TestResult appropriate for property recording. if (current_test_info_ != NULL) { xml_element = "testcase"; test_result = &(current_test_info_->result_); } else if (current_test_case_ != NULL) { xml_element = "testsuite"; test_result = &(current_test_case_->ad_hoc_test_result_); } else { xml_element = "testsuites"; test_result = &ad_hoc_test_result_; } test_result->RecordProperty(xml_element, test_property); } #if GTEST_HAS_DEATH_TEST // Disables event forwarding if the control is currently in a death test // subprocess. Must not be called before InitGoogleTest. void UnitTestImpl::SuppressTestEventsIfInSubprocess() { if (internal_run_death_test_flag_.get() != NULL) listeners()->SuppressEventForwarding(); } #endif // GTEST_HAS_DEATH_TEST // Initializes event listeners performing XML output as specified by // UnitTestOptions. Must not be called before InitGoogleTest. void UnitTestImpl::ConfigureXmlOutput() { const std::string& output_format = UnitTestOptions::GetOutputFormat(); if (output_format == "xml") { listeners()->SetDefaultXmlGenerator(new XmlUnitTestResultPrinter( UnitTestOptions::GetAbsolutePathToOutputFile().c_str())); } else if (output_format != "") { printf("WARNING: unrecognized output format \"%s\" ignored.\n", output_format.c_str()); fflush(stdout); } } #if GTEST_CAN_STREAM_RESULTS_ // Initializes event listeners for streaming test results in string form. // Must not be called before InitGoogleTest. void UnitTestImpl::ConfigureStreamingOutput() { const std::string& target = GTEST_FLAG(stream_result_to); if (!target.empty()) { const size_t pos = target.find(':'); if (pos != std::string::npos) { listeners()->Append(new StreamingListener(target.substr(0, pos), target.substr(pos + 1))); } else { printf("WARNING: unrecognized streaming target \"%s\" ignored.\n", target.c_str()); fflush(stdout); } } } #endif // GTEST_CAN_STREAM_RESULTS_ // Performs initialization dependent upon flag values obtained in // ParseGoogleTestFlagsOnly. Is called from InitGoogleTest after the call to // ParseGoogleTestFlagsOnly. In case a user neglects to call InitGoogleTest // this function is also called from RunAllTests. Since this function can be // called more than once, it has to be idempotent. void UnitTestImpl::PostFlagParsingInit() { // Ensures that this function does not execute more than once. if (!post_flag_parse_init_performed_) { post_flag_parse_init_performed_ = true; #if GTEST_HAS_DEATH_TEST InitDeathTestSubprocessControlInfo(); SuppressTestEventsIfInSubprocess(); #endif // GTEST_HAS_DEATH_TEST // Registers parameterized tests. This makes parameterized tests // available to the UnitTest reflection API without running // RUN_ALL_TESTS. RegisterParameterizedTests(); // Configures listeners for XML output. This makes it possible for users // to shut down the default XML output before invoking RUN_ALL_TESTS. ConfigureXmlOutput(); #if GTEST_CAN_STREAM_RESULTS_ // Configures listeners for streaming test results to the specified server. ConfigureStreamingOutput(); #endif // GTEST_CAN_STREAM_RESULTS_ } } // A predicate that checks the name of a TestCase against a known // value. // // This is used for implementation of the UnitTest class only. We put // it in the anonymous namespace to prevent polluting the outer // namespace. // // TestCaseNameIs is copyable. class TestCaseNameIs { public: // Constructor. explicit TestCaseNameIs(const std::string& name) : name_(name) {} // Returns true iff the name of test_case matches name_. bool operator()(const TestCase* test_case) const { return test_case != NULL && strcmp(test_case->name(), name_.c_str()) == 0; } private: std::string name_; }; // Finds and returns a TestCase with the given name. If one doesn't // exist, creates one and returns it. It's the CALLER'S // RESPONSIBILITY to ensure that this function is only called WHEN THE // TESTS ARE NOT SHUFFLED. // // Arguments: // // test_case_name: name of the test case // type_param: the name of the test case's type parameter, or NULL if // this is not a typed or a type-parameterized test case. // set_up_tc: pointer to the function that sets up the test case // tear_down_tc: pointer to the function that tears down the test case TestCase* UnitTestImpl::GetTestCase(const char* test_case_name, const char* type_param, Test::SetUpTestCaseFunc set_up_tc, Test::TearDownTestCaseFunc tear_down_tc) { // Can we find a TestCase with the given name? const std::vector::const_iterator test_case = std::find_if(test_cases_.begin(), test_cases_.end(), TestCaseNameIs(test_case_name)); if (test_case != test_cases_.end()) return *test_case; // No. Let's create one. TestCase* const new_test_case = new TestCase(test_case_name, type_param, set_up_tc, tear_down_tc); // Is this a death test case? if (internal::UnitTestOptions::MatchesFilter(test_case_name, kDeathTestCaseFilter)) { // Yes. Inserts the test case after the last death test case // defined so far. This only works when the test cases haven't // been shuffled. Otherwise we may end up running a death test // after a non-death test. ++last_death_test_case_; test_cases_.insert(test_cases_.begin() + last_death_test_case_, new_test_case); } else { // No. Appends to the end of the list. test_cases_.push_back(new_test_case); } test_case_indices_.push_back(static_cast(test_case_indices_.size())); return new_test_case; } // Helpers for setting up / tearing down the given environment. They // are for use in the ForEach() function. static void SetUpEnvironment(Environment* env) { env->SetUp(); } static void TearDownEnvironment(Environment* env) { env->TearDown(); } // Runs all tests in this UnitTest object, prints the result, and // returns true if all tests are successful. If any exception is // thrown during a test, the test is considered to be failed, but the // rest of the tests will still be run. // // When parameterized tests are enabled, it expands and registers // parameterized tests first in RegisterParameterizedTests(). // All other functions called from RunAllTests() may safely assume that // parameterized tests are ready to be counted and run. bool UnitTestImpl::RunAllTests() { // Makes sure InitGoogleTest() was called. if (!GTestIsInitialized()) { printf("%s", "\nThis test program did NOT call ::testing::InitGoogleTest " "before calling RUN_ALL_TESTS(). Please fix it.\n"); return false; } // Do not run any test if the --help flag was specified. if (g_help_flag) return true; // Repeats the call to the post-flag parsing initialization in case the // user didn't call InitGoogleTest. PostFlagParsingInit(); // Even if sharding is not on, test runners may want to use the // GTEST_SHARD_STATUS_FILE to query whether the test supports the sharding // protocol. internal::WriteToShardStatusFileIfNeeded(); // True iff we are in a subprocess for running a thread-safe-style // death test. bool in_subprocess_for_death_test = false; #if GTEST_HAS_DEATH_TEST in_subprocess_for_death_test = (internal_run_death_test_flag_.get() != NULL); #endif // GTEST_HAS_DEATH_TEST const bool should_shard = ShouldShard(kTestTotalShards, kTestShardIndex, in_subprocess_for_death_test); // Compares the full test names with the filter to decide which // tests to run. const bool has_tests_to_run = FilterTests(should_shard ? HONOR_SHARDING_PROTOCOL : IGNORE_SHARDING_PROTOCOL) > 0; // Lists the tests and exits if the --gtest_list_tests flag was specified. if (GTEST_FLAG(list_tests)) { // This must be called *after* FilterTests() has been called. ListTestsMatchingFilter(); return true; } random_seed_ = GTEST_FLAG(shuffle) ? GetRandomSeedFromFlag(GTEST_FLAG(random_seed)) : 0; // True iff at least one test has failed. bool failed = false; TestEventListener* repeater = listeners()->repeater(); start_timestamp_ = GetTimeInMillis(); repeater->OnTestProgramStart(*parent_); // How many times to repeat the tests? We don't want to repeat them // when we are inside the subprocess of a death test. const int repeat = in_subprocess_for_death_test ? 1 : GTEST_FLAG(repeat); // Repeats forever if the repeat count is negative. const bool forever = repeat < 0; for (int i = 0; forever || i != repeat; i++) { // We want to preserve failures generated by ad-hoc test // assertions executed before RUN_ALL_TESTS(). ClearNonAdHocTestResult(); const TimeInMillis start = GetTimeInMillis(); // Shuffles test cases and tests if requested. if (has_tests_to_run && GTEST_FLAG(shuffle)) { random()->Reseed(random_seed_); // This should be done before calling OnTestIterationStart(), // such that a test event listener can see the actual test order // in the event. ShuffleTests(); } // Tells the unit test event listeners that the tests are about to start. repeater->OnTestIterationStart(*parent_, i); // Runs each test case if there is at least one test to run. if (has_tests_to_run) { // Sets up all environments beforehand. repeater->OnEnvironmentsSetUpStart(*parent_); ForEach(environments_, SetUpEnvironment); repeater->OnEnvironmentsSetUpEnd(*parent_); // Runs the tests only if there was no fatal failure during global // set-up. if (!Test::HasFatalFailure()) { for (int test_index = 0; test_index < total_test_case_count(); test_index++) { GetMutableTestCase(test_index)->Run(); } } // Tears down all environments in reverse order afterwards. repeater->OnEnvironmentsTearDownStart(*parent_); std::for_each(environments_.rbegin(), environments_.rend(), TearDownEnvironment); repeater->OnEnvironmentsTearDownEnd(*parent_); } elapsed_time_ = GetTimeInMillis() - start; // Tells the unit test event listener that the tests have just finished. repeater->OnTestIterationEnd(*parent_, i); // Gets the result and clears it. if (!Passed()) { failed = true; } // Restores the original test order after the iteration. This // allows the user to quickly repro a failure that happens in the // N-th iteration without repeating the first (N - 1) iterations. // This is not enclosed in "if (GTEST_FLAG(shuffle)) { ... }", in // case the user somehow changes the value of the flag somewhere // (it's always safe to unshuffle the tests). UnshuffleTests(); if (GTEST_FLAG(shuffle)) { // Picks a new random seed for each iteration. random_seed_ = GetNextRandomSeed(random_seed_); } } repeater->OnTestProgramEnd(*parent_); return !failed; } // Reads the GTEST_SHARD_STATUS_FILE environment variable, and creates the file // if the variable is present. If a file already exists at this location, this // function will write over it. If the variable is present, but the file cannot // be created, prints an error and exits. void WriteToShardStatusFileIfNeeded() { const char* const test_shard_file = posix::GetEnv(kTestShardStatusFile); if (test_shard_file != NULL) { FILE* const file = posix::FOpen(test_shard_file, "w"); if (file == NULL) { ColoredPrintf(COLOR_RED, "Could not write to the test shard status file \"%s\" " "specified by the %s environment variable.\n", test_shard_file, kTestShardStatusFile); fflush(stdout); exit(EXIT_FAILURE); } fclose(file); } } // Checks whether sharding is enabled by examining the relevant // environment variable values. If the variables are present, // but inconsistent (i.e., shard_index >= total_shards), prints // an error and exits. If in_subprocess_for_death_test, sharding is // disabled because it must only be applied to the original test // process. Otherwise, we could filter out death tests we intended to execute. bool ShouldShard(const char* total_shards_env, const char* shard_index_env, bool in_subprocess_for_death_test) { if (in_subprocess_for_death_test) { return false; } const Int32 total_shards = Int32FromEnvOrDie(total_shards_env, -1); const Int32 shard_index = Int32FromEnvOrDie(shard_index_env, -1); if (total_shards == -1 && shard_index == -1) { return false; } else if (total_shards == -1 && shard_index != -1) { const Message msg = Message() << "Invalid environment variables: you have " << kTestShardIndex << " = " << shard_index << ", but have left " << kTestTotalShards << " unset.\n"; ColoredPrintf(COLOR_RED, msg.GetString().c_str()); fflush(stdout); exit(EXIT_FAILURE); } else if (total_shards != -1 && shard_index == -1) { const Message msg = Message() << "Invalid environment variables: you have " << kTestTotalShards << " = " << total_shards << ", but have left " << kTestShardIndex << " unset.\n"; ColoredPrintf(COLOR_RED, msg.GetString().c_str()); fflush(stdout); exit(EXIT_FAILURE); } else if (shard_index < 0 || shard_index >= total_shards) { const Message msg = Message() << "Invalid environment variables: we require 0 <= " << kTestShardIndex << " < " << kTestTotalShards << ", but you have " << kTestShardIndex << "=" << shard_index << ", " << kTestTotalShards << "=" << total_shards << ".\n"; ColoredPrintf(COLOR_RED, msg.GetString().c_str()); fflush(stdout); exit(EXIT_FAILURE); } return total_shards > 1; } // Parses the environment variable var as an Int32. If it is unset, // returns default_val. If it is not an Int32, prints an error // and aborts. Int32 Int32FromEnvOrDie(const char* var, Int32 default_val) { const char* str_val = posix::GetEnv(var); if (str_val == NULL) { return default_val; } Int32 result; if (!ParseInt32(Message() << "The value of environment variable " << var, str_val, &result)) { exit(EXIT_FAILURE); } return result; } // Given the total number of shards, the shard index, and the test id, // returns true iff the test should be run on this shard. The test id is // some arbitrary but unique non-negative integer assigned to each test // method. Assumes that 0 <= shard_index < total_shards. bool ShouldRunTestOnShard(int total_shards, int shard_index, int test_id) { return (test_id % total_shards) == shard_index; } // Compares the name of each test with the user-specified filter to // decide whether the test should be run, then records the result in // each TestCase and TestInfo object. // If shard_tests == true, further filters tests based on sharding // variables in the environment - see // http://code.google.com/p/googletest/wiki/GoogleTestAdvancedGuide. // Returns the number of tests that should run. int UnitTestImpl::FilterTests(ReactionToSharding shard_tests) { const Int32 total_shards = shard_tests == HONOR_SHARDING_PROTOCOL ? Int32FromEnvOrDie(kTestTotalShards, -1) : -1; const Int32 shard_index = shard_tests == HONOR_SHARDING_PROTOCOL ? Int32FromEnvOrDie(kTestShardIndex, -1) : -1; // num_runnable_tests are the number of tests that will // run across all shards (i.e., match filter and are not disabled). // num_selected_tests are the number of tests to be run on // this shard. int num_runnable_tests = 0; int num_selected_tests = 0; for (size_t i = 0; i < test_cases_.size(); i++) { TestCase* const test_case = test_cases_[i]; const std::string &test_case_name = test_case->name(); test_case->set_should_run(false); for (size_t j = 0; j < test_case->test_info_list().size(); j++) { TestInfo* const test_info = test_case->test_info_list()[j]; const std::string test_name(test_info->name()); // A test is disabled if test case name or test name matches // kDisableTestFilter. const bool is_disabled = internal::UnitTestOptions::MatchesFilter(test_case_name, kDisableTestFilter) || internal::UnitTestOptions::MatchesFilter(test_name, kDisableTestFilter); test_info->is_disabled_ = is_disabled; const bool matches_filter = internal::UnitTestOptions::FilterMatchesTest(test_case_name, test_name); test_info->matches_filter_ = matches_filter; const bool is_runnable = (GTEST_FLAG(also_run_disabled_tests) || !is_disabled) && matches_filter; const bool is_selected = is_runnable && (shard_tests == IGNORE_SHARDING_PROTOCOL || ShouldRunTestOnShard(total_shards, shard_index, num_runnable_tests)); num_runnable_tests += is_runnable; num_selected_tests += is_selected; test_info->should_run_ = is_selected; test_case->set_should_run(test_case->should_run() || is_selected); } } return num_selected_tests; } // Prints the given C-string on a single line by replacing all '\n' // characters with string "\\n". If the output takes more than // max_length characters, only prints the first max_length characters // and "...". static void PrintOnOneLine(const char* str, int max_length) { if (str != NULL) { for (int i = 0; *str != '\0'; ++str) { if (i >= max_length) { printf("..."); break; } if (*str == '\n') { printf("\\n"); i += 2; } else { printf("%c", *str); ++i; } } } } // Prints the names of the tests matching the user-specified filter flag. void UnitTestImpl::ListTestsMatchingFilter() { // Print at most this many characters for each type/value parameter. const int kMaxParamLength = 250; for (size_t i = 0; i < test_cases_.size(); i++) { const TestCase* const test_case = test_cases_[i]; bool printed_test_case_name = false; for (size_t j = 0; j < test_case->test_info_list().size(); j++) { const TestInfo* const test_info = test_case->test_info_list()[j]; if (test_info->matches_filter_) { if (!printed_test_case_name) { printed_test_case_name = true; printf("%s.", test_case->name()); if (test_case->type_param() != NULL) { printf(" # %s = ", kTypeParamLabel); // We print the type parameter on a single line to make // the output easy to parse by a program. PrintOnOneLine(test_case->type_param(), kMaxParamLength); } printf("\n"); } printf(" %s", test_info->name()); if (test_info->value_param() != NULL) { printf(" # %s = ", kValueParamLabel); // We print the value parameter on a single line to make the // output easy to parse by a program. PrintOnOneLine(test_info->value_param(), kMaxParamLength); } printf("\n"); } } } fflush(stdout); } // Sets the OS stack trace getter. // // Does nothing if the input and the current OS stack trace getter are // the same; otherwise, deletes the old getter and makes the input the // current getter. void UnitTestImpl::set_os_stack_trace_getter( OsStackTraceGetterInterface* getter) { if (os_stack_trace_getter_ != getter) { delete os_stack_trace_getter_; os_stack_trace_getter_ = getter; } } // Returns the current OS stack trace getter if it is not NULL; // otherwise, creates an OsStackTraceGetter, makes it the current // getter, and returns it. OsStackTraceGetterInterface* UnitTestImpl::os_stack_trace_getter() { if (os_stack_trace_getter_ == NULL) { os_stack_trace_getter_ = new OsStackTraceGetter; } return os_stack_trace_getter_; } // Returns the TestResult for the test that's currently running, or // the TestResult for the ad hoc test if no test is running. TestResult* UnitTestImpl::current_test_result() { return current_test_info_ ? &(current_test_info_->result_) : &ad_hoc_test_result_; } // Shuffles all test cases, and the tests within each test case, // making sure that death tests are still run first. void UnitTestImpl::ShuffleTests() { // Shuffles the death test cases. ShuffleRange(random(), 0, last_death_test_case_ + 1, &test_case_indices_); // Shuffles the non-death test cases. ShuffleRange(random(), last_death_test_case_ + 1, static_cast(test_cases_.size()), &test_case_indices_); // Shuffles the tests inside each test case. for (size_t i = 0; i < test_cases_.size(); i++) { test_cases_[i]->ShuffleTests(random()); } } // Restores the test cases and tests to their order before the first shuffle. void UnitTestImpl::UnshuffleTests() { for (size_t i = 0; i < test_cases_.size(); i++) { // Unshuffles the tests in each test case. test_cases_[i]->UnshuffleTests(); // Resets the index of each test case. test_case_indices_[i] = static_cast(i); } } // Returns the current OS stack trace as an std::string. // // The maximum number of stack frames to be included is specified by // the gtest_stack_trace_depth flag. The skip_count parameter // specifies the number of top frames to be skipped, which doesn't // count against the number of frames to be included. // // For example, if Foo() calls Bar(), which in turn calls // GetCurrentOsStackTraceExceptTop(..., 1), Foo() will be included in // the trace but Bar() and GetCurrentOsStackTraceExceptTop() won't. std::string GetCurrentOsStackTraceExceptTop(UnitTest* /*unit_test*/, int skip_count) { // We pass skip_count + 1 to skip this wrapper function in addition // to what the user really wants to skip. return GetUnitTestImpl()->CurrentOsStackTraceExceptTop(skip_count + 1); } // Used by the GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_ macro to // suppress unreachable code warnings. namespace { class ClassUniqueToAlwaysTrue {}; } bool IsTrue(bool condition) { return condition; } bool AlwaysTrue() { #if GTEST_HAS_EXCEPTIONS // This condition is always false so AlwaysTrue() never actually throws, // but it makes the compiler think that it may throw. if (IsTrue(false)) throw ClassUniqueToAlwaysTrue(); #endif // GTEST_HAS_EXCEPTIONS return true; } // If *pstr starts with the given prefix, modifies *pstr to be right // past the prefix and returns true; otherwise leaves *pstr unchanged // and returns false. None of pstr, *pstr, and prefix can be NULL. bool SkipPrefix(const char* prefix, const char** pstr) { const size_t prefix_len = strlen(prefix); if (strncmp(*pstr, prefix, prefix_len) == 0) { *pstr += prefix_len; return true; } return false; } // Parses a string as a command line flag. The string should have // the format "--flag=value". When def_optional is true, the "=value" // part can be omitted. // // Returns the value of the flag, or NULL if the parsing failed. const char* ParseFlagValue(const char* str, const char* flag, bool def_optional) { // str and flag must not be NULL. if (str == NULL || flag == NULL) return NULL; // The flag must start with "--" followed by GTEST_FLAG_PREFIX_. const std::string flag_str = std::string("--") + GTEST_FLAG_PREFIX_ + flag; const size_t flag_len = flag_str.length(); if (strncmp(str, flag_str.c_str(), flag_len) != 0) return NULL; // Skips the flag name. const char* flag_end = str + flag_len; // When def_optional is true, it's OK to not have a "=value" part. if (def_optional && (flag_end[0] == '\0')) { return flag_end; } // If def_optional is true and there are more characters after the // flag name, or if def_optional is false, there must be a '=' after // the flag name. if (flag_end[0] != '=') return NULL; // Returns the string after "=". return flag_end + 1; } // Parses a string for a bool flag, in the form of either // "--flag=value" or "--flag". // // In the former case, the value is taken as true as long as it does // not start with '0', 'f', or 'F'. // // In the latter case, the value is taken as true. // // On success, stores the value of the flag in *value, and returns // true. On failure, returns false without changing *value. bool ParseBoolFlag(const char* str, const char* flag, bool* value) { // Gets the value of the flag as a string. const char* const value_str = ParseFlagValue(str, flag, true); // Aborts if the parsing failed. if (value_str == NULL) return false; // Converts the string value to a bool. *value = !(*value_str == '0' || *value_str == 'f' || *value_str == 'F'); return true; } // Parses a string for an Int32 flag, in the form of // "--flag=value". // // On success, stores the value of the flag in *value, and returns // true. On failure, returns false without changing *value. bool ParseInt32Flag(const char* str, const char* flag, Int32* value) { // Gets the value of the flag as a string. const char* const value_str = ParseFlagValue(str, flag, false); // Aborts if the parsing failed. if (value_str == NULL) return false; // Sets *value to the value of the flag. return ParseInt32(Message() << "The value of flag --" << flag, value_str, value); } // Parses a string for a string flag, in the form of // "--flag=value". // // On success, stores the value of the flag in *value, and returns // true. On failure, returns false without changing *value. bool ParseStringFlag(const char* str, const char* flag, std::string* value) { // Gets the value of the flag as a string. const char* const value_str = ParseFlagValue(str, flag, false); // Aborts if the parsing failed. if (value_str == NULL) return false; // Sets *value to the value of the flag. *value = value_str; return true; } // Determines whether a string has a prefix that Google Test uses for its // flags, i.e., starts with GTEST_FLAG_PREFIX_ or GTEST_FLAG_PREFIX_DASH_. // If Google Test detects that a command line flag has its prefix but is not // recognized, it will print its help message. Flags starting with // GTEST_INTERNAL_PREFIX_ followed by "internal_" are considered Google Test // internal flags and do not trigger the help message. static bool HasGoogleTestFlagPrefix(const char* str) { return (SkipPrefix("--", &str) || SkipPrefix("-", &str) || SkipPrefix("/", &str)) && !SkipPrefix(GTEST_FLAG_PREFIX_ "internal_", &str) && (SkipPrefix(GTEST_FLAG_PREFIX_, &str) || SkipPrefix(GTEST_FLAG_PREFIX_DASH_, &str)); } // Prints a string containing code-encoded text. The following escape // sequences can be used in the string to control the text color: // // @@ prints a single '@' character. // @R changes the color to red. // @G changes the color to green. // @Y changes the color to yellow. // @D changes to the default terminal text color. // // TODO(wan@google.com): Write tests for this once we add stdout // capturing to Google Test. static void PrintColorEncoded(const char* str) { GTestColor color = COLOR_DEFAULT; // The current color. // Conceptually, we split the string into segments divided by escape // sequences. Then we print one segment at a time. At the end of // each iteration, the str pointer advances to the beginning of the // next segment. for (;;) { const char* p = strchr(str, '@'); if (p == NULL) { ColoredPrintf(color, "%s", str); return; } ColoredPrintf(color, "%s", std::string(str, p).c_str()); const char ch = p[1]; str = p + 2; if (ch == '@') { ColoredPrintf(color, "@"); } else if (ch == 'D') { color = COLOR_DEFAULT; } else if (ch == 'R') { color = COLOR_RED; } else if (ch == 'G') { color = COLOR_GREEN; } else if (ch == 'Y') { color = COLOR_YELLOW; } else { --str; } } } static const char kColorEncodedHelpMessage[] = "This program contains tests written using " GTEST_NAME_ ". You can use the\n" "following command line flags to control its behavior:\n" "\n" "Test Selection:\n" " @G--" GTEST_FLAG_PREFIX_ "list_tests@D\n" " List the names of all tests instead of running them. The name of\n" " TEST(Foo, Bar) is \"Foo.Bar\".\n" " @G--" GTEST_FLAG_PREFIX_ "filter=@YPOSTIVE_PATTERNS" "[@G-@YNEGATIVE_PATTERNS]@D\n" " Run only the tests whose name matches one of the positive patterns but\n" " none of the negative patterns. '?' matches any single character; '*'\n" " matches any substring; ':' separates two patterns.\n" " @G--" GTEST_FLAG_PREFIX_ "also_run_disabled_tests@D\n" " Run all disabled tests too.\n" "\n" "Test Execution:\n" " @G--" GTEST_FLAG_PREFIX_ "repeat=@Y[COUNT]@D\n" " Run the tests repeatedly; use a negative count to repeat forever.\n" " @G--" GTEST_FLAG_PREFIX_ "shuffle@D\n" " Randomize tests' orders on every iteration.\n" " @G--" GTEST_FLAG_PREFIX_ "random_seed=@Y[NUMBER]@D\n" " Random number seed to use for shuffling test orders (between 1 and\n" " 99999, or 0 to use a seed based on the current time).\n" "\n" "Test Output:\n" " @G--" GTEST_FLAG_PREFIX_ "color=@Y(@Gyes@Y|@Gno@Y|@Gauto@Y)@D\n" " Enable/disable colored output. The default is @Gauto@D.\n" " -@G-" GTEST_FLAG_PREFIX_ "print_time=0@D\n" " Don't print the elapsed time of each test.\n" " @G--" GTEST_FLAG_PREFIX_ "output=xml@Y[@G:@YDIRECTORY_PATH@G" GTEST_PATH_SEP_ "@Y|@G:@YFILE_PATH]@D\n" " Generate an XML report in the given directory or with the given file\n" " name. @YFILE_PATH@D defaults to @Gtest_details.xml@D.\n" #if GTEST_CAN_STREAM_RESULTS_ " @G--" GTEST_FLAG_PREFIX_ "stream_result_to=@YHOST@G:@YPORT@D\n" " Stream test results to the given server.\n" #endif // GTEST_CAN_STREAM_RESULTS_ "\n" "Assertion Behavior:\n" #if GTEST_HAS_DEATH_TEST && !GTEST_OS_WINDOWS " @G--" GTEST_FLAG_PREFIX_ "death_test_style=@Y(@Gfast@Y|@Gthreadsafe@Y)@D\n" " Set the default death test style.\n" #endif // GTEST_HAS_DEATH_TEST && !GTEST_OS_WINDOWS " @G--" GTEST_FLAG_PREFIX_ "break_on_failure@D\n" " Turn assertion failures into debugger break-points.\n" " @G--" GTEST_FLAG_PREFIX_ "throw_on_failure@D\n" " Turn assertion failures into C++ exceptions.\n" " @G--" GTEST_FLAG_PREFIX_ "catch_exceptions=0@D\n" " Do not report exceptions as test failures. Instead, allow them\n" " to crash the program or throw a pop-up (on Windows).\n" "\n" "Except for @G--" GTEST_FLAG_PREFIX_ "list_tests@D, you can alternatively set " "the corresponding\n" "environment variable of a flag (all letters in upper-case). For example, to\n" "disable colored text output, you can either specify @G--" GTEST_FLAG_PREFIX_ "color=no@D or set\n" "the @G" GTEST_FLAG_PREFIX_UPPER_ "COLOR@D environment variable to @Gno@D.\n" "\n" "For more information, please read the " GTEST_NAME_ " documentation at\n" "@G" GTEST_PROJECT_URL_ "@D. If you find a bug in " GTEST_NAME_ "\n" "(not one in your own code or tests), please report it to\n" "@G<" GTEST_DEV_EMAIL_ ">@D.\n"; // Parses the command line for Google Test flags, without initializing // other parts of Google Test. The type parameter CharType can be // instantiated to either char or wchar_t. template void ParseGoogleTestFlagsOnlyImpl(int* argc, CharType** argv) { for (int i = 1; i < *argc; i++) { const std::string arg_string = StreamableToString(argv[i]); const char* const arg = arg_string.c_str(); using internal::ParseBoolFlag; using internal::ParseInt32Flag; using internal::ParseStringFlag; // Do we see a Google Test flag? if (ParseBoolFlag(arg, kAlsoRunDisabledTestsFlag, >EST_FLAG(also_run_disabled_tests)) || ParseBoolFlag(arg, kBreakOnFailureFlag, >EST_FLAG(break_on_failure)) || ParseBoolFlag(arg, kCatchExceptionsFlag, >EST_FLAG(catch_exceptions)) || ParseStringFlag(arg, kColorFlag, >EST_FLAG(color)) || ParseStringFlag(arg, kDeathTestStyleFlag, >EST_FLAG(death_test_style)) || ParseBoolFlag(arg, kDeathTestUseFork, >EST_FLAG(death_test_use_fork)) || ParseStringFlag(arg, kFilterFlag, >EST_FLAG(filter)) || ParseStringFlag(arg, kInternalRunDeathTestFlag, >EST_FLAG(internal_run_death_test)) || ParseBoolFlag(arg, kListTestsFlag, >EST_FLAG(list_tests)) || ParseStringFlag(arg, kOutputFlag, >EST_FLAG(output)) || ParseBoolFlag(arg, kPrintTimeFlag, >EST_FLAG(print_time)) || ParseInt32Flag(arg, kRandomSeedFlag, >EST_FLAG(random_seed)) || ParseInt32Flag(arg, kRepeatFlag, >EST_FLAG(repeat)) || ParseBoolFlag(arg, kShuffleFlag, >EST_FLAG(shuffle)) || ParseInt32Flag(arg, kStackTraceDepthFlag, >EST_FLAG(stack_trace_depth)) || ParseStringFlag(arg, kStreamResultToFlag, >EST_FLAG(stream_result_to)) || ParseBoolFlag(arg, kThrowOnFailureFlag, >EST_FLAG(throw_on_failure)) ) { // Yes. Shift the remainder of the argv list left by one. Note // that argv has (*argc + 1) elements, the last one always being // NULL. The following loop moves the trailing NULL element as // well. for (int j = i; j != *argc; j++) { argv[j] = argv[j + 1]; } // Decrements the argument count. (*argc)--; // We also need to decrement the iterator as we just removed // an element. i--; } else if (arg_string == "--help" || arg_string == "-h" || arg_string == "-?" || arg_string == "/?" || HasGoogleTestFlagPrefix(arg)) { // Both help flag and unrecognized Google Test flags (excluding // internal ones) trigger help display. g_help_flag = true; } } if (g_help_flag) { // We print the help here instead of in RUN_ALL_TESTS(), as the // latter may not be called at all if the user is using Google // Test with another testing framework. PrintColorEncoded(kColorEncodedHelpMessage); } } // Parses the command line for Google Test flags, without initializing // other parts of Google Test. void ParseGoogleTestFlagsOnly(int* argc, char** argv) { ParseGoogleTestFlagsOnlyImpl(argc, argv); } void ParseGoogleTestFlagsOnly(int* argc, wchar_t** argv) { ParseGoogleTestFlagsOnlyImpl(argc, argv); } // The internal implementation of InitGoogleTest(). // // The type parameter CharType can be instantiated to either char or // wchar_t. template void InitGoogleTestImpl(int* argc, CharType** argv) { g_init_gtest_count++; // We don't want to run the initialization code twice. if (g_init_gtest_count != 1) return; if (*argc <= 0) return; internal::g_executable_path = internal::StreamableToString(argv[0]); #if GTEST_HAS_DEATH_TEST g_argvs.clear(); for (int i = 0; i != *argc; i++) { g_argvs.push_back(StreamableToString(argv[i])); } #endif // GTEST_HAS_DEATH_TEST ParseGoogleTestFlagsOnly(argc, argv); GetUnitTestImpl()->PostFlagParsingInit(); } } // namespace internal // Initializes Google Test. This must be called before calling // RUN_ALL_TESTS(). In particular, it parses a command line for the // flags that Google Test recognizes. Whenever a Google Test flag is // seen, it is removed from argv, and *argc is decremented. // // No value is returned. Instead, the Google Test flag variables are // updated. // // Calling the function for the second time has no user-visible effect. void InitGoogleTest(int* argc, char** argv) { internal::InitGoogleTestImpl(argc, argv); } // This overloaded version can be used in Windows programs compiled in // UNICODE mode. void InitGoogleTest(int* argc, wchar_t** argv) { internal::InitGoogleTestImpl(argc, argv); } } // namespace testing // Copyright 2005, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // Author: wan@google.com (Zhanyong Wan), vladl@google.com (Vlad Losev) // // This file implements death tests. #if GTEST_HAS_DEATH_TEST # if GTEST_OS_MAC # include # endif // GTEST_OS_MAC # include # include # include # if GTEST_OS_LINUX # include # endif // GTEST_OS_LINUX # include # if GTEST_OS_WINDOWS # include # else # include # include # endif // GTEST_OS_WINDOWS # if GTEST_OS_QNX # include # endif // GTEST_OS_QNX #endif // GTEST_HAS_DEATH_TEST // Indicates that this translation unit is part of Google Test's // implementation. It must come before gtest-internal-inl.h is // included, or there will be a compiler error. This trick is to // prevent a user from accidentally including gtest-internal-inl.h in // his code. #define GTEST_IMPLEMENTATION_ 1 #undef GTEST_IMPLEMENTATION_ namespace testing { // Constants. // The default death test style. static const char kDefaultDeathTestStyle[] = "fast"; GTEST_DEFINE_string_( death_test_style, internal::StringFromGTestEnv("death_test_style", kDefaultDeathTestStyle), "Indicates how to run a death test in a forked child process: " "\"threadsafe\" (child process re-executes the test binary " "from the beginning, running only the specific death test) or " "\"fast\" (child process runs the death test immediately " "after forking)."); GTEST_DEFINE_bool_( death_test_use_fork, internal::BoolFromGTestEnv("death_test_use_fork", false), "Instructs to use fork()/_exit() instead of clone() in death tests. " "Ignored and always uses fork() on POSIX systems where clone() is not " "implemented. Useful when running under valgrind or similar tools if " "those do not support clone(). Valgrind 3.3.1 will just fail if " "it sees an unsupported combination of clone() flags. " "It is not recommended to use this flag w/o valgrind though it will " "work in 99% of the cases. Once valgrind is fixed, this flag will " "most likely be removed."); namespace internal { GTEST_DEFINE_string_( internal_run_death_test, "", "Indicates the file, line number, temporal index of " "the single death test to run, and a file descriptor to " "which a success code may be sent, all separated by " "the '|' characters. This flag is specified if and only if the current " "process is a sub-process launched for running a thread-safe " "death test. FOR INTERNAL USE ONLY."); } // namespace internal #if GTEST_HAS_DEATH_TEST namespace internal { // Valid only for fast death tests. Indicates the code is running in the // child process of a fast style death test. static bool g_in_fast_death_test_child = false; // Returns a Boolean value indicating whether the caller is currently // executing in the context of the death test child process. Tools such as // Valgrind heap checkers may need this to modify their behavior in death // tests. IMPORTANT: This is an internal utility. Using it may break the // implementation of death tests. User code MUST NOT use it. bool InDeathTestChild() { # if GTEST_OS_WINDOWS // On Windows, death tests are thread-safe regardless of the value of the // death_test_style flag. return !GTEST_FLAG(internal_run_death_test).empty(); # else if (GTEST_FLAG(death_test_style) == "threadsafe") return !GTEST_FLAG(internal_run_death_test).empty(); else return g_in_fast_death_test_child; #endif } } // namespace internal // ExitedWithCode constructor. ExitedWithCode::ExitedWithCode(int exit_code) : exit_code_(exit_code) { } // ExitedWithCode function-call operator. bool ExitedWithCode::operator()(int exit_status) const { # if GTEST_OS_WINDOWS return exit_status == exit_code_; # else return WIFEXITED(exit_status) && WEXITSTATUS(exit_status) == exit_code_; # endif // GTEST_OS_WINDOWS } # if !GTEST_OS_WINDOWS // KilledBySignal constructor. KilledBySignal::KilledBySignal(int signum) : signum_(signum) { } // KilledBySignal function-call operator. bool KilledBySignal::operator()(int exit_status) const { return WIFSIGNALED(exit_status) && WTERMSIG(exit_status) == signum_; } # endif // !GTEST_OS_WINDOWS namespace internal { // Utilities needed for death tests. // Generates a textual description of a given exit code, in the format // specified by wait(2). static std::string ExitSummary(int exit_code) { Message m; # if GTEST_OS_WINDOWS m << "Exited with exit status " << exit_code; # else if (WIFEXITED(exit_code)) { m << "Exited with exit status " << WEXITSTATUS(exit_code); } else if (WIFSIGNALED(exit_code)) { m << "Terminated by signal " << WTERMSIG(exit_code); } # ifdef WCOREDUMP if (WCOREDUMP(exit_code)) { m << " (core dumped)"; } # endif # endif // GTEST_OS_WINDOWS return m.GetString(); } // Returns true if exit_status describes a process that was terminated // by a signal, or exited normally with a nonzero exit code. bool ExitedUnsuccessfully(int exit_status) { return !ExitedWithCode(0)(exit_status); } # if !GTEST_OS_WINDOWS // Generates a textual failure message when a death test finds more than // one thread running, or cannot determine the number of threads, prior // to executing the given statement. It is the responsibility of the // caller not to pass a thread_count of 1. static std::string DeathTestThreadWarning(size_t thread_count) { Message msg; msg << "Death tests use fork(), which is unsafe particularly" << " in a threaded context. For this test, " << GTEST_NAME_ << " "; if (thread_count == 0) msg << "couldn't detect the number of threads."; else msg << "detected " << thread_count << " threads."; return msg.GetString(); } # endif // !GTEST_OS_WINDOWS // Flag characters for reporting a death test that did not die. static const char kDeathTestLived = 'L'; static const char kDeathTestReturned = 'R'; static const char kDeathTestThrew = 'T'; static const char kDeathTestInternalError = 'I'; // An enumeration describing all of the possible ways that a death test can // conclude. DIED means that the process died while executing the test // code; LIVED means that process lived beyond the end of the test code; // RETURNED means that the test statement attempted to execute a return // statement, which is not allowed; THREW means that the test statement // returned control by throwing an exception. IN_PROGRESS means the test // has not yet concluded. // TODO(vladl@google.com): Unify names and possibly values for // AbortReason, DeathTestOutcome, and flag characters above. enum DeathTestOutcome { IN_PROGRESS, DIED, LIVED, RETURNED, THREW }; // Routine for aborting the program which is safe to call from an // exec-style death test child process, in which case the error // message is propagated back to the parent process. Otherwise, the // message is simply printed to stderr. In either case, the program // then exits with status 1. void DeathTestAbort(const std::string& message) { // On a POSIX system, this function may be called from a threadsafe-style // death test child process, which operates on a very small stack. Use // the heap for any additional non-minuscule memory requirements. const InternalRunDeathTestFlag* const flag = GetUnitTestImpl()->internal_run_death_test_flag(); if (flag != NULL) { FILE* parent = posix::FDOpen(flag->write_fd(), "w"); fputc(kDeathTestInternalError, parent); fprintf(parent, "%s", message.c_str()); fflush(parent); _exit(1); } else { fprintf(stderr, "%s", message.c_str()); fflush(stderr); posix::Abort(); } } // A replacement for CHECK that calls DeathTestAbort if the assertion // fails. # define GTEST_DEATH_TEST_CHECK_(expression) \ do { \ if (!::testing::internal::IsTrue(expression)) { \ DeathTestAbort( \ ::std::string("CHECK failed: File ") + __FILE__ + ", line " \ + ::testing::internal::StreamableToString(__LINE__) + ": " \ + #expression); \ } \ } while (::testing::internal::AlwaysFalse()) // This macro is similar to GTEST_DEATH_TEST_CHECK_, but it is meant for // evaluating any system call that fulfills two conditions: it must return // -1 on failure, and set errno to EINTR when it is interrupted and // should be tried again. The macro expands to a loop that repeatedly // evaluates the expression as long as it evaluates to -1 and sets // errno to EINTR. If the expression evaluates to -1 but errno is // something other than EINTR, DeathTestAbort is called. # define GTEST_DEATH_TEST_CHECK_SYSCALL_(expression) \ do { \ int gtest_retval; \ do { \ gtest_retval = (expression); \ } while (gtest_retval == -1 && errno == EINTR); \ if (gtest_retval == -1) { \ DeathTestAbort( \ ::std::string("CHECK failed: File ") + __FILE__ + ", line " \ + ::testing::internal::StreamableToString(__LINE__) + ": " \ + #expression + " != -1"); \ } \ } while (::testing::internal::AlwaysFalse()) // Returns the message describing the last system error in errno. std::string GetLastErrnoDescription() { return errno == 0 ? "" : posix::StrError(errno); } // This is called from a death test parent process to read a failure // message from the death test child process and log it with the FATAL // severity. On Windows, the message is read from a pipe handle. On other // platforms, it is read from a file descriptor. static void FailFromInternalError(int fd) { Message error; char buffer[256]; int num_read; do { while ((num_read = posix::Read(fd, buffer, 255)) > 0) { buffer[num_read] = '\0'; error << buffer; } } while (num_read == -1 && errno == EINTR); if (num_read == 0) { GTEST_LOG_(FATAL) << error.GetString(); } else { const int last_error = errno; GTEST_LOG_(FATAL) << "Error while reading death test internal: " << GetLastErrnoDescription() << " [" << last_error << "]"; } } // Death test constructor. Increments the running death test count // for the current test. DeathTest::DeathTest() { TestInfo* const info = GetUnitTestImpl()->current_test_info(); if (info == NULL) { DeathTestAbort("Cannot run a death test outside of a TEST or " "TEST_F construct"); } } // Creates and returns a death test by dispatching to the current // death test factory. bool DeathTest::Create(const char* statement, const RE* regex, const char* file, int line, DeathTest** test) { return GetUnitTestImpl()->death_test_factory()->Create( statement, regex, file, line, test); } const char* DeathTest::LastMessage() { return last_death_test_message_.c_str(); } void DeathTest::set_last_death_test_message(const std::string& message) { last_death_test_message_ = message; } std::string DeathTest::last_death_test_message_; // Provides cross platform implementation for some death functionality. class DeathTestImpl : public DeathTest { protected: DeathTestImpl(const char* a_statement, const RE* a_regex) : statement_(a_statement), regex_(a_regex), spawned_(false), status_(-1), outcome_(IN_PROGRESS), read_fd_(-1), write_fd_(-1) {} // read_fd_ is expected to be closed and cleared by a derived class. ~DeathTestImpl() { GTEST_DEATH_TEST_CHECK_(read_fd_ == -1); } void Abort(AbortReason reason); virtual bool Passed(bool status_ok); const char* statement() const { return statement_; } const RE* regex() const { return regex_; } bool spawned() const { return spawned_; } void set_spawned(bool is_spawned) { spawned_ = is_spawned; } int status() const { return status_; } void set_status(int a_status) { status_ = a_status; } DeathTestOutcome outcome() const { return outcome_; } void set_outcome(DeathTestOutcome an_outcome) { outcome_ = an_outcome; } int read_fd() const { return read_fd_; } void set_read_fd(int fd) { read_fd_ = fd; } int write_fd() const { return write_fd_; } void set_write_fd(int fd) { write_fd_ = fd; } // Called in the parent process only. Reads the result code of the death // test child process via a pipe, interprets it to set the outcome_ // member, and closes read_fd_. Outputs diagnostics and terminates in // case of unexpected codes. void ReadAndInterpretStatusByte(); private: // The textual content of the code this object is testing. This class // doesn't own this string and should not attempt to delete it. const char* const statement_; // The regular expression which test output must match. DeathTestImpl // doesn't own this object and should not attempt to delete it. const RE* const regex_; // True if the death test child process has been successfully spawned. bool spawned_; // The exit status of the child process. int status_; // How the death test concluded. DeathTestOutcome outcome_; // Descriptor to the read end of the pipe to the child process. It is // always -1 in the child process. The child keeps its write end of the // pipe in write_fd_. int read_fd_; // Descriptor to the child's write end of the pipe to the parent process. // It is always -1 in the parent process. The parent keeps its end of the // pipe in read_fd_. int write_fd_; }; // Called in the parent process only. Reads the result code of the death // test child process via a pipe, interprets it to set the outcome_ // member, and closes read_fd_. Outputs diagnostics and terminates in // case of unexpected codes. void DeathTestImpl::ReadAndInterpretStatusByte() { char flag; int bytes_read; // The read() here blocks until data is available (signifying the // failure of the death test) or until the pipe is closed (signifying // its success), so it's okay to call this in the parent before // the child process has exited. do { bytes_read = posix::Read(read_fd(), &flag, 1); } while (bytes_read == -1 && errno == EINTR); if (bytes_read == 0) { set_outcome(DIED); } else if (bytes_read == 1) { switch (flag) { case kDeathTestReturned: set_outcome(RETURNED); break; case kDeathTestThrew: set_outcome(THREW); break; case kDeathTestLived: set_outcome(LIVED); break; case kDeathTestInternalError: FailFromInternalError(read_fd()); // Does not return. break; default: GTEST_LOG_(FATAL) << "Death test child process reported " << "unexpected status byte (" << static_cast(flag) << ")"; } } else { GTEST_LOG_(FATAL) << "Read from death test child process failed: " << GetLastErrnoDescription(); } GTEST_DEATH_TEST_CHECK_SYSCALL_(posix::Close(read_fd())); set_read_fd(-1); } // Signals that the death test code which should have exited, didn't. // Should be called only in a death test child process. // Writes a status byte to the child's status file descriptor, then // calls _exit(1). void DeathTestImpl::Abort(AbortReason reason) { // The parent process considers the death test to be a failure if // it finds any data in our pipe. So, here we write a single flag byte // to the pipe, then exit. const char status_ch = reason == TEST_DID_NOT_DIE ? kDeathTestLived : reason == TEST_THREW_EXCEPTION ? kDeathTestThrew : kDeathTestReturned; GTEST_DEATH_TEST_CHECK_SYSCALL_(posix::Write(write_fd(), &status_ch, 1)); // We are leaking the descriptor here because on some platforms (i.e., // when built as Windows DLL), destructors of global objects will still // run after calling _exit(). On such systems, write_fd_ will be // indirectly closed from the destructor of UnitTestImpl, causing double // close if it is also closed here. On debug configurations, double close // may assert. As there are no in-process buffers to flush here, we are // relying on the OS to close the descriptor after the process terminates // when the destructors are not run. _exit(1); // Exits w/o any normal exit hooks (we were supposed to crash) } // Returns an indented copy of stderr output for a death test. // This makes distinguishing death test output lines from regular log lines // much easier. static ::std::string FormatDeathTestOutput(const ::std::string& output) { ::std::string ret; for (size_t at = 0; ; ) { const size_t line_end = output.find('\n', at); ret += "[ DEATH ] "; if (line_end == ::std::string::npos) { ret += output.substr(at); break; } ret += output.substr(at, line_end + 1 - at); at = line_end + 1; } return ret; } // Assesses the success or failure of a death test, using both private // members which have previously been set, and one argument: // // Private data members: // outcome: An enumeration describing how the death test // concluded: DIED, LIVED, THREW, or RETURNED. The death test // fails in the latter three cases. // status: The exit status of the child process. On *nix, it is in the // in the format specified by wait(2). On Windows, this is the // value supplied to the ExitProcess() API or a numeric code // of the exception that terminated the program. // regex: A regular expression object to be applied to // the test's captured standard error output; the death test // fails if it does not match. // // Argument: // status_ok: true if exit_status is acceptable in the context of // this particular death test, which fails if it is false // // Returns true iff all of the above conditions are met. Otherwise, the // first failing condition, in the order given above, is the one that is // reported. Also sets the last death test message string. bool DeathTestImpl::Passed(bool status_ok) { if (!spawned()) return false; const std::string error_message = GetCapturedStderr(); bool success = false; Message buffer; buffer << "Death test: " << statement() << "\n"; switch (outcome()) { case LIVED: buffer << " Result: failed to die.\n" << " Error msg:\n" << FormatDeathTestOutput(error_message); break; case THREW: buffer << " Result: threw an exception.\n" << " Error msg:\n" << FormatDeathTestOutput(error_message); break; case RETURNED: buffer << " Result: illegal return in test statement.\n" << " Error msg:\n" << FormatDeathTestOutput(error_message); break; case DIED: if (status_ok) { const bool matched = RE::PartialMatch(error_message.c_str(), *regex()); if (matched) { success = true; } else { buffer << " Result: died but not with expected error.\n" << " Expected: " << regex()->pattern() << "\n" << "Actual msg:\n" << FormatDeathTestOutput(error_message); } } else { buffer << " Result: died but not with expected exit code:\n" << " " << ExitSummary(status()) << "\n" << "Actual msg:\n" << FormatDeathTestOutput(error_message); } break; case IN_PROGRESS: default: GTEST_LOG_(FATAL) << "DeathTest::Passed somehow called before conclusion of test"; } DeathTest::set_last_death_test_message(buffer.GetString()); return success; } # if GTEST_OS_WINDOWS // WindowsDeathTest implements death tests on Windows. Due to the // specifics of starting new processes on Windows, death tests there are // always threadsafe, and Google Test considers the // --gtest_death_test_style=fast setting to be equivalent to // --gtest_death_test_style=threadsafe there. // // A few implementation notes: Like the Linux version, the Windows // implementation uses pipes for child-to-parent communication. But due to // the specifics of pipes on Windows, some extra steps are required: // // 1. The parent creates a communication pipe and stores handles to both // ends of it. // 2. The parent starts the child and provides it with the information // necessary to acquire the handle to the write end of the pipe. // 3. The child acquires the write end of the pipe and signals the parent // using a Windows event. // 4. Now the parent can release the write end of the pipe on its side. If // this is done before step 3, the object's reference count goes down to // 0 and it is destroyed, preventing the child from acquiring it. The // parent now has to release it, or read operations on the read end of // the pipe will not return when the child terminates. // 5. The parent reads child's output through the pipe (outcome code and // any possible error messages) from the pipe, and its stderr and then // determines whether to fail the test. // // Note: to distinguish Win32 API calls from the local method and function // calls, the former are explicitly resolved in the global namespace. // class WindowsDeathTest : public DeathTestImpl { public: WindowsDeathTest(const char* a_statement, const RE* a_regex, const char* file, int line) : DeathTestImpl(a_statement, a_regex), file_(file), line_(line) {} // All of these virtual functions are inherited from DeathTest. virtual int Wait(); virtual TestRole AssumeRole(); private: // The name of the file in which the death test is located. const char* const file_; // The line number on which the death test is located. const int line_; // Handle to the write end of the pipe to the child process. AutoHandle write_handle_; // Child process handle. AutoHandle child_handle_; // Event the child process uses to signal the parent that it has // acquired the handle to the write end of the pipe. After seeing this // event the parent can release its own handles to make sure its // ReadFile() calls return when the child terminates. AutoHandle event_handle_; }; // Waits for the child in a death test to exit, returning its exit // status, or 0 if no child process exists. As a side effect, sets the // outcome data member. int WindowsDeathTest::Wait() { if (!spawned()) return 0; // Wait until the child either signals that it has acquired the write end // of the pipe or it dies. const HANDLE wait_handles[2] = { child_handle_.Get(), event_handle_.Get() }; switch (::WaitForMultipleObjects(2, wait_handles, FALSE, // Waits for any of the handles. INFINITE)) { case WAIT_OBJECT_0: case WAIT_OBJECT_0 + 1: break; default: GTEST_DEATH_TEST_CHECK_(false); // Should not get here. } // The child has acquired the write end of the pipe or exited. // We release the handle on our side and continue. write_handle_.Reset(); event_handle_.Reset(); ReadAndInterpretStatusByte(); // Waits for the child process to exit if it haven't already. This // returns immediately if the child has already exited, regardless of // whether previous calls to WaitForMultipleObjects synchronized on this // handle or not. GTEST_DEATH_TEST_CHECK_( WAIT_OBJECT_0 == ::WaitForSingleObject(child_handle_.Get(), INFINITE)); DWORD status_code; GTEST_DEATH_TEST_CHECK_( ::GetExitCodeProcess(child_handle_.Get(), &status_code) != FALSE); child_handle_.Reset(); set_status(static_cast(status_code)); return status(); } // The AssumeRole process for a Windows death test. It creates a child // process with the same executable as the current process to run the // death test. The child process is given the --gtest_filter and // --gtest_internal_run_death_test flags such that it knows to run the // current death test only. DeathTest::TestRole WindowsDeathTest::AssumeRole() { const UnitTestImpl* const impl = GetUnitTestImpl(); const InternalRunDeathTestFlag* const flag = impl->internal_run_death_test_flag(); const TestInfo* const info = impl->current_test_info(); const int death_test_index = info->result()->death_test_count(); if (flag != NULL) { // ParseInternalRunDeathTestFlag() has performed all the necessary // processing. set_write_fd(flag->write_fd()); return EXECUTE_TEST; } // WindowsDeathTest uses an anonymous pipe to communicate results of // a death test. SECURITY_ATTRIBUTES handles_are_inheritable = { sizeof(SECURITY_ATTRIBUTES), NULL, TRUE }; HANDLE read_handle, write_handle; GTEST_DEATH_TEST_CHECK_( ::CreatePipe(&read_handle, &write_handle, &handles_are_inheritable, 0) // Default buffer size. != FALSE); set_read_fd(::_open_osfhandle(reinterpret_cast(read_handle), O_RDONLY)); write_handle_.Reset(write_handle); event_handle_.Reset(::CreateEvent( &handles_are_inheritable, TRUE, // The event will automatically reset to non-signaled state. FALSE, // The initial state is non-signalled. NULL)); // The even is unnamed. GTEST_DEATH_TEST_CHECK_(event_handle_.Get() != NULL); const std::string filter_flag = std::string("--") + GTEST_FLAG_PREFIX_ + kFilterFlag + "=" + info->test_case_name() + "." + info->name(); const std::string internal_flag = std::string("--") + GTEST_FLAG_PREFIX_ + kInternalRunDeathTestFlag + "=" + file_ + "|" + StreamableToString(line_) + "|" + StreamableToString(death_test_index) + "|" + StreamableToString(static_cast(::GetCurrentProcessId())) + // size_t has the same width as pointers on both 32-bit and 64-bit // Windows platforms. // See http://msdn.microsoft.com/en-us/library/tcxf1dw6.aspx. "|" + StreamableToString(reinterpret_cast(write_handle)) + "|" + StreamableToString(reinterpret_cast(event_handle_.Get())); char executable_path[_MAX_PATH + 1]; // NOLINT GTEST_DEATH_TEST_CHECK_( _MAX_PATH + 1 != ::GetModuleFileNameA(NULL, executable_path, _MAX_PATH)); std::string command_line = std::string(::GetCommandLineA()) + " " + filter_flag + " \"" + internal_flag + "\""; DeathTest::set_last_death_test_message(""); CaptureStderr(); // Flush the log buffers since the log streams are shared with the child. FlushInfoLog(); // The child process will share the standard handles with the parent. STARTUPINFOA startup_info; memset(&startup_info, 0, sizeof(STARTUPINFO)); startup_info.dwFlags = STARTF_USESTDHANDLES; startup_info.hStdInput = ::GetStdHandle(STD_INPUT_HANDLE); startup_info.hStdOutput = ::GetStdHandle(STD_OUTPUT_HANDLE); startup_info.hStdError = ::GetStdHandle(STD_ERROR_HANDLE); PROCESS_INFORMATION process_info; GTEST_DEATH_TEST_CHECK_(::CreateProcessA( executable_path, const_cast(command_line.c_str()), NULL, // Retuned process handle is not inheritable. NULL, // Retuned thread handle is not inheritable. TRUE, // Child inherits all inheritable handles (for write_handle_). 0x0, // Default creation flags. NULL, // Inherit the parent's environment. UnitTest::GetInstance()->original_working_dir(), &startup_info, &process_info) != FALSE); child_handle_.Reset(process_info.hProcess); ::CloseHandle(process_info.hThread); set_spawned(true); return OVERSEE_TEST; } # else // We are not on Windows. // ForkingDeathTest provides implementations for most of the abstract // methods of the DeathTest interface. Only the AssumeRole method is // left undefined. class ForkingDeathTest : public DeathTestImpl { public: ForkingDeathTest(const char* statement, const RE* regex); // All of these virtual functions are inherited from DeathTest. virtual int Wait(); protected: void set_child_pid(pid_t child_pid) { child_pid_ = child_pid; } private: // PID of child process during death test; 0 in the child process itself. pid_t child_pid_; }; // Constructs a ForkingDeathTest. ForkingDeathTest::ForkingDeathTest(const char* a_statement, const RE* a_regex) : DeathTestImpl(a_statement, a_regex), child_pid_(-1) {} // Waits for the child in a death test to exit, returning its exit // status, or 0 if no child process exists. As a side effect, sets the // outcome data member. int ForkingDeathTest::Wait() { if (!spawned()) return 0; ReadAndInterpretStatusByte(); int status_value; GTEST_DEATH_TEST_CHECK_SYSCALL_(waitpid(child_pid_, &status_value, 0)); set_status(status_value); return status_value; } // A concrete death test class that forks, then immediately runs the test // in the child process. class NoExecDeathTest : public ForkingDeathTest { public: NoExecDeathTest(const char* a_statement, const RE* a_regex) : ForkingDeathTest(a_statement, a_regex) { } virtual TestRole AssumeRole(); }; // The AssumeRole process for a fork-and-run death test. It implements a // straightforward fork, with a simple pipe to transmit the status byte. DeathTest::TestRole NoExecDeathTest::AssumeRole() { const size_t thread_count = GetThreadCount(); if (thread_count != 1) { GTEST_LOG_(WARNING) << DeathTestThreadWarning(thread_count); } int pipe_fd[2]; GTEST_DEATH_TEST_CHECK_(pipe(pipe_fd) != -1); DeathTest::set_last_death_test_message(""); CaptureStderr(); // When we fork the process below, the log file buffers are copied, but the // file descriptors are shared. We flush all log files here so that closing // the file descriptors in the child process doesn't throw off the // synchronization between descriptors and buffers in the parent process. // This is as close to the fork as possible to avoid a race condition in case // there are multiple threads running before the death test, and another // thread writes to the log file. FlushInfoLog(); const pid_t child_pid = fork(); GTEST_DEATH_TEST_CHECK_(child_pid != -1); set_child_pid(child_pid); if (child_pid == 0) { GTEST_DEATH_TEST_CHECK_SYSCALL_(close(pipe_fd[0])); set_write_fd(pipe_fd[1]); // Redirects all logging to stderr in the child process to prevent // concurrent writes to the log files. We capture stderr in the parent // process and append the child process' output to a log. LogToStderr(); // Event forwarding to the listeners of event listener API mush be shut // down in death test subprocesses. GetUnitTestImpl()->listeners()->SuppressEventForwarding(); g_in_fast_death_test_child = true; return EXECUTE_TEST; } else { GTEST_DEATH_TEST_CHECK_SYSCALL_(close(pipe_fd[1])); set_read_fd(pipe_fd[0]); set_spawned(true); return OVERSEE_TEST; } } // A concrete death test class that forks and re-executes the main // program from the beginning, with command-line flags set that cause // only this specific death test to be run. class ExecDeathTest : public ForkingDeathTest { public: ExecDeathTest(const char* a_statement, const RE* a_regex, const char* file, int line) : ForkingDeathTest(a_statement, a_regex), file_(file), line_(line) { } virtual TestRole AssumeRole(); private: static ::std::vector GetArgvsForDeathTestChildProcess() { ::std::vector args = GetInjectableArgvs(); return args; } // The name of the file in which the death test is located. const char* const file_; // The line number on which the death test is located. const int line_; }; // Utility class for accumulating command-line arguments. class Arguments { public: Arguments() { args_.push_back(NULL); } ~Arguments() { for (std::vector::iterator i = args_.begin(); i != args_.end(); ++i) { free(*i); } } void AddArgument(const char* argument) { args_.insert(args_.end() - 1, posix::StrDup(argument)); } template void AddArguments(const ::std::vector& arguments) { for (typename ::std::vector::const_iterator i = arguments.begin(); i != arguments.end(); ++i) { args_.insert(args_.end() - 1, posix::StrDup(i->c_str())); } } char* const* Argv() { return &args_[0]; } private: std::vector args_; }; // A struct that encompasses the arguments to the child process of a // threadsafe-style death test process. struct ExecDeathTestArgs { char* const* argv; // Command-line arguments for the child's call to exec int close_fd; // File descriptor to close; the read end of a pipe }; # if GTEST_OS_MAC inline char** GetEnviron() { // When Google Test is built as a framework on MacOS X, the environ variable // is unavailable. Apple's documentation (man environ) recommends using // _NSGetEnviron() instead. return *_NSGetEnviron(); } # else // Some POSIX platforms expect you to declare environ. extern "C" makes // it reside in the global namespace. extern "C" char** environ; inline char** GetEnviron() { return environ; } # endif // GTEST_OS_MAC # if !GTEST_OS_QNX // The main function for a threadsafe-style death test child process. // This function is called in a clone()-ed process and thus must avoid // any potentially unsafe operations like malloc or libc functions. static int ExecDeathTestChildMain(void* child_arg) { ExecDeathTestArgs* const args = static_cast(child_arg); GTEST_DEATH_TEST_CHECK_SYSCALL_(close(args->close_fd)); // We need to execute the test program in the same environment where // it was originally invoked. Therefore we change to the original // working directory first. const char* const original_dir = UnitTest::GetInstance()->original_working_dir(); // We can safely call chdir() as it's a direct system call. if (chdir(original_dir) != 0) { DeathTestAbort(std::string("chdir(\"") + original_dir + "\") failed: " + GetLastErrnoDescription()); return EXIT_FAILURE; } // We can safely call execve() as it's a direct system call. We // cannot use execvp() as it's a libc function and thus potentially // unsafe. Since execve() doesn't search the PATH, the user must // invoke the test program via a valid path that contains at least // one path separator. execve(args->argv[0], args->argv, GetEnviron()); DeathTestAbort(std::string("execve(") + args->argv[0] + ", ...) in " + original_dir + " failed: " + GetLastErrnoDescription()); return EXIT_FAILURE; } # endif // !GTEST_OS_QNX // Two utility routines that together determine the direction the stack // grows. // This could be accomplished more elegantly by a single recursive // function, but we want to guard against the unlikely possibility of // a smart compiler optimizing the recursion away. // // GTEST_NO_INLINE_ is required to prevent GCC 4.6 from inlining // StackLowerThanAddress into StackGrowsDown, which then doesn't give // correct answer. void StackLowerThanAddress(const void* ptr, bool* result) GTEST_NO_INLINE_; void StackLowerThanAddress(const void* ptr, bool* result) { int dummy; *result = (&dummy < ptr); } bool StackGrowsDown() { int dummy; bool result; StackLowerThanAddress(&dummy, &result); return result; } // Spawns a child process with the same executable as the current process in // a thread-safe manner and instructs it to run the death test. The // implementation uses fork(2) + exec. On systems where clone(2) is // available, it is used instead, being slightly more thread-safe. On QNX, // fork supports only single-threaded environments, so this function uses // spawn(2) there instead. The function dies with an error message if // anything goes wrong. static pid_t ExecDeathTestSpawnChild(char* const* argv, int close_fd) { ExecDeathTestArgs args = { argv, close_fd }; pid_t child_pid = -1; # if GTEST_OS_QNX // Obtains the current directory and sets it to be closed in the child // process. const int cwd_fd = open(".", O_RDONLY); GTEST_DEATH_TEST_CHECK_(cwd_fd != -1); GTEST_DEATH_TEST_CHECK_SYSCALL_(fcntl(cwd_fd, F_SETFD, FD_CLOEXEC)); // We need to execute the test program in the same environment where // it was originally invoked. Therefore we change to the original // working directory first. const char* const original_dir = UnitTest::GetInstance()->original_working_dir(); // We can safely call chdir() as it's a direct system call. if (chdir(original_dir) != 0) { DeathTestAbort(std::string("chdir(\"") + original_dir + "\") failed: " + GetLastErrnoDescription()); return EXIT_FAILURE; } int fd_flags; // Set close_fd to be closed after spawn. GTEST_DEATH_TEST_CHECK_SYSCALL_(fd_flags = fcntl(close_fd, F_GETFD)); GTEST_DEATH_TEST_CHECK_SYSCALL_(fcntl(close_fd, F_SETFD, fd_flags | FD_CLOEXEC)); struct inheritance inherit = { 0 }; // spawn is a system call. child_pid = spawn(args.argv[0], 0, NULL, &inherit, args.argv, GetEnviron()); // Restores the current working directory. GTEST_DEATH_TEST_CHECK_(fchdir(cwd_fd) != -1); GTEST_DEATH_TEST_CHECK_SYSCALL_(close(cwd_fd)); # else // GTEST_OS_QNX # if GTEST_OS_LINUX // When a SIGPROF signal is received while fork() or clone() are executing, // the process may hang. To avoid this, we ignore SIGPROF here and re-enable // it after the call to fork()/clone() is complete. struct sigaction saved_sigprof_action; struct sigaction ignore_sigprof_action; memset(&ignore_sigprof_action, 0, sizeof(ignore_sigprof_action)); sigemptyset(&ignore_sigprof_action.sa_mask); ignore_sigprof_action.sa_handler = SIG_IGN; GTEST_DEATH_TEST_CHECK_SYSCALL_(sigaction( SIGPROF, &ignore_sigprof_action, &saved_sigprof_action)); # endif // GTEST_OS_LINUX # if GTEST_HAS_CLONE const bool use_fork = GTEST_FLAG(death_test_use_fork); if (!use_fork) { static const bool stack_grows_down = StackGrowsDown(); const size_t stack_size = getpagesize(); // MMAP_ANONYMOUS is not defined on Mac, so we use MAP_ANON instead. void* const stack = mmap(NULL, stack_size, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0); GTEST_DEATH_TEST_CHECK_(stack != MAP_FAILED); // Maximum stack alignment in bytes: For a downward-growing stack, this // amount is subtracted from size of the stack space to get an address // that is within the stack space and is aligned on all systems we care // about. As far as I know there is no ABI with stack alignment greater // than 64. We assume stack and stack_size already have alignment of // kMaxStackAlignment. const size_t kMaxStackAlignment = 64; void* const stack_top = static_cast(stack) + (stack_grows_down ? stack_size - kMaxStackAlignment : 0); GTEST_DEATH_TEST_CHECK_(stack_size > kMaxStackAlignment && reinterpret_cast(stack_top) % kMaxStackAlignment == 0); child_pid = clone(&ExecDeathTestChildMain, stack_top, SIGCHLD, &args); GTEST_DEATH_TEST_CHECK_(munmap(stack, stack_size) != -1); } # else const bool use_fork = true; # endif // GTEST_HAS_CLONE if (use_fork && (child_pid = fork()) == 0) { ExecDeathTestChildMain(&args); _exit(0); } # endif // GTEST_OS_QNX # if GTEST_OS_LINUX GTEST_DEATH_TEST_CHECK_SYSCALL_( sigaction(SIGPROF, &saved_sigprof_action, NULL)); # endif // GTEST_OS_LINUX GTEST_DEATH_TEST_CHECK_(child_pid != -1); return child_pid; } // The AssumeRole process for a fork-and-exec death test. It re-executes the // main program from the beginning, setting the --gtest_filter // and --gtest_internal_run_death_test flags to cause only the current // death test to be re-run. DeathTest::TestRole ExecDeathTest::AssumeRole() { const UnitTestImpl* const impl = GetUnitTestImpl(); const InternalRunDeathTestFlag* const flag = impl->internal_run_death_test_flag(); const TestInfo* const info = impl->current_test_info(); const int death_test_index = info->result()->death_test_count(); if (flag != NULL) { set_write_fd(flag->write_fd()); return EXECUTE_TEST; } int pipe_fd[2]; GTEST_DEATH_TEST_CHECK_(pipe(pipe_fd) != -1); // Clear the close-on-exec flag on the write end of the pipe, lest // it be closed when the child process does an exec: GTEST_DEATH_TEST_CHECK_(fcntl(pipe_fd[1], F_SETFD, 0) != -1); const std::string filter_flag = std::string("--") + GTEST_FLAG_PREFIX_ + kFilterFlag + "=" + info->test_case_name() + "." + info->name(); const std::string internal_flag = std::string("--") + GTEST_FLAG_PREFIX_ + kInternalRunDeathTestFlag + "=" + file_ + "|" + StreamableToString(line_) + "|" + StreamableToString(death_test_index) + "|" + StreamableToString(pipe_fd[1]); Arguments args; args.AddArguments(GetArgvsForDeathTestChildProcess()); args.AddArgument(filter_flag.c_str()); args.AddArgument(internal_flag.c_str()); DeathTest::set_last_death_test_message(""); CaptureStderr(); // See the comment in NoExecDeathTest::AssumeRole for why the next line // is necessary. FlushInfoLog(); const pid_t child_pid = ExecDeathTestSpawnChild(args.Argv(), pipe_fd[0]); GTEST_DEATH_TEST_CHECK_SYSCALL_(close(pipe_fd[1])); set_child_pid(child_pid); set_read_fd(pipe_fd[0]); set_spawned(true); return OVERSEE_TEST; } # endif // !GTEST_OS_WINDOWS // Creates a concrete DeathTest-derived class that depends on the // --gtest_death_test_style flag, and sets the pointer pointed to // by the "test" argument to its address. If the test should be // skipped, sets that pointer to NULL. Returns true, unless the // flag is set to an invalid value. bool DefaultDeathTestFactory::Create(const char* statement, const RE* regex, const char* file, int line, DeathTest** test) { UnitTestImpl* const impl = GetUnitTestImpl(); const InternalRunDeathTestFlag* const flag = impl->internal_run_death_test_flag(); const int death_test_index = impl->current_test_info() ->increment_death_test_count(); if (flag != NULL) { if (death_test_index > flag->index()) { DeathTest::set_last_death_test_message( "Death test count (" + StreamableToString(death_test_index) + ") somehow exceeded expected maximum (" + StreamableToString(flag->index()) + ")"); return false; } if (!(flag->file() == file && flag->line() == line && flag->index() == death_test_index)) { *test = NULL; return true; } } # if GTEST_OS_WINDOWS if (GTEST_FLAG(death_test_style) == "threadsafe" || GTEST_FLAG(death_test_style) == "fast") { *test = new WindowsDeathTest(statement, regex, file, line); } # else if (GTEST_FLAG(death_test_style) == "threadsafe") { *test = new ExecDeathTest(statement, regex, file, line); } else if (GTEST_FLAG(death_test_style) == "fast") { *test = new NoExecDeathTest(statement, regex); } # endif // GTEST_OS_WINDOWS else { // NOLINT - this is more readable than unbalanced brackets inside #if. DeathTest::set_last_death_test_message( "Unknown death test style \"" + GTEST_FLAG(death_test_style) + "\" encountered"); return false; } return true; } // Splits a given string on a given delimiter, populating a given // vector with the fields. GTEST_HAS_DEATH_TEST implies that we have // ::std::string, so we can use it here. static void SplitString(const ::std::string& str, char delimiter, ::std::vector< ::std::string>* dest) { ::std::vector< ::std::string> parsed; ::std::string::size_type pos = 0; while (::testing::internal::AlwaysTrue()) { const ::std::string::size_type colon = str.find(delimiter, pos); if (colon == ::std::string::npos) { parsed.push_back(str.substr(pos)); break; } else { parsed.push_back(str.substr(pos, colon - pos)); pos = colon + 1; } } dest->swap(parsed); } # if GTEST_OS_WINDOWS // Recreates the pipe and event handles from the provided parameters, // signals the event, and returns a file descriptor wrapped around the pipe // handle. This function is called in the child process only. int GetStatusFileDescriptor(unsigned int parent_process_id, size_t write_handle_as_size_t, size_t event_handle_as_size_t) { AutoHandle parent_process_handle(::OpenProcess(PROCESS_DUP_HANDLE, FALSE, // Non-inheritable. parent_process_id)); if (parent_process_handle.Get() == INVALID_HANDLE_VALUE) { DeathTestAbort("Unable to open parent process " + StreamableToString(parent_process_id)); } // TODO(vladl@google.com): Replace the following check with a // compile-time assertion when available. GTEST_CHECK_(sizeof(HANDLE) <= sizeof(size_t)); const HANDLE write_handle = reinterpret_cast(write_handle_as_size_t); HANDLE dup_write_handle; // The newly initialized handle is accessible only in in the parent // process. To obtain one accessible within the child, we need to use // DuplicateHandle. if (!::DuplicateHandle(parent_process_handle.Get(), write_handle, ::GetCurrentProcess(), &dup_write_handle, 0x0, // Requested privileges ignored since // DUPLICATE_SAME_ACCESS is used. FALSE, // Request non-inheritable handler. DUPLICATE_SAME_ACCESS)) { DeathTestAbort("Unable to duplicate the pipe handle " + StreamableToString(write_handle_as_size_t) + " from the parent process " + StreamableToString(parent_process_id)); } const HANDLE event_handle = reinterpret_cast(event_handle_as_size_t); HANDLE dup_event_handle; if (!::DuplicateHandle(parent_process_handle.Get(), event_handle, ::GetCurrentProcess(), &dup_event_handle, 0x0, FALSE, DUPLICATE_SAME_ACCESS)) { DeathTestAbort("Unable to duplicate the event handle " + StreamableToString(event_handle_as_size_t) + " from the parent process " + StreamableToString(parent_process_id)); } const int write_fd = ::_open_osfhandle(reinterpret_cast(dup_write_handle), O_APPEND); if (write_fd == -1) { DeathTestAbort("Unable to convert pipe handle " + StreamableToString(write_handle_as_size_t) + " to a file descriptor"); } // Signals the parent that the write end of the pipe has been acquired // so the parent can release its own write end. ::SetEvent(dup_event_handle); return write_fd; } # endif // GTEST_OS_WINDOWS // Returns a newly created InternalRunDeathTestFlag object with fields // initialized from the GTEST_FLAG(internal_run_death_test) flag if // the flag is specified; otherwise returns NULL. InternalRunDeathTestFlag* ParseInternalRunDeathTestFlag() { if (GTEST_FLAG(internal_run_death_test) == "") return NULL; // GTEST_HAS_DEATH_TEST implies that we have ::std::string, so we // can use it here. int line = -1; int index = -1; ::std::vector< ::std::string> fields; SplitString(GTEST_FLAG(internal_run_death_test).c_str(), '|', &fields); int write_fd = -1; # if GTEST_OS_WINDOWS unsigned int parent_process_id = 0; size_t write_handle_as_size_t = 0; size_t event_handle_as_size_t = 0; if (fields.size() != 6 || !ParseNaturalNumber(fields[1], &line) || !ParseNaturalNumber(fields[2], &index) || !ParseNaturalNumber(fields[3], &parent_process_id) || !ParseNaturalNumber(fields[4], &write_handle_as_size_t) || !ParseNaturalNumber(fields[5], &event_handle_as_size_t)) { DeathTestAbort("Bad --gtest_internal_run_death_test flag: " + GTEST_FLAG(internal_run_death_test)); } write_fd = GetStatusFileDescriptor(parent_process_id, write_handle_as_size_t, event_handle_as_size_t); # else if (fields.size() != 4 || !ParseNaturalNumber(fields[1], &line) || !ParseNaturalNumber(fields[2], &index) || !ParseNaturalNumber(fields[3], &write_fd)) { DeathTestAbort("Bad --gtest_internal_run_death_test flag: " + GTEST_FLAG(internal_run_death_test)); } # endif // GTEST_OS_WINDOWS return new InternalRunDeathTestFlag(fields[0], line, index, write_fd); } } // namespace internal #endif // GTEST_HAS_DEATH_TEST } // namespace testing // Copyright 2008, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // Authors: keith.ray@gmail.com (Keith Ray) #include #if GTEST_OS_WINDOWS_MOBILE # include #elif GTEST_OS_WINDOWS # include # include #elif GTEST_OS_SYMBIAN // Symbian OpenC has PATH_MAX in sys/syslimits.h # include #else # include # include // Some Linux distributions define PATH_MAX here. #endif // GTEST_OS_WINDOWS_MOBILE #if GTEST_OS_WINDOWS # define GTEST_PATH_MAX_ _MAX_PATH #elif defined(PATH_MAX) # define GTEST_PATH_MAX_ PATH_MAX #elif defined(_XOPEN_PATH_MAX) # define GTEST_PATH_MAX_ _XOPEN_PATH_MAX #else # define GTEST_PATH_MAX_ _POSIX_PATH_MAX #endif // GTEST_OS_WINDOWS namespace testing { namespace internal { #if GTEST_OS_WINDOWS // On Windows, '\\' is the standard path separator, but many tools and the // Windows API also accept '/' as an alternate path separator. Unless otherwise // noted, a file path can contain either kind of path separators, or a mixture // of them. const char kPathSeparator = '\\'; const char kAlternatePathSeparator = '/'; const char kPathSeparatorString[] = "\\"; const char kAlternatePathSeparatorString[] = "/"; # if GTEST_OS_WINDOWS_MOBILE // Windows CE doesn't have a current directory. You should not use // the current directory in tests on Windows CE, but this at least // provides a reasonable fallback. const char kCurrentDirectoryString[] = "\\"; // Windows CE doesn't define INVALID_FILE_ATTRIBUTES const DWORD kInvalidFileAttributes = 0xffffffff; # else const char kCurrentDirectoryString[] = ".\\"; # endif // GTEST_OS_WINDOWS_MOBILE #else const char kPathSeparator = '/'; const char kPathSeparatorString[] = "/"; const char kCurrentDirectoryString[] = "./"; #endif // GTEST_OS_WINDOWS // Returns whether the given character is a valid path separator. static bool IsPathSeparator(char c) { #if GTEST_HAS_ALT_PATH_SEP_ return (c == kPathSeparator) || (c == kAlternatePathSeparator); #else return c == kPathSeparator; #endif } // Returns the current working directory, or "" if unsuccessful. FilePath FilePath::GetCurrentDir() { #if GTEST_OS_WINDOWS_MOBILE // Windows CE doesn't have a current directory, so we just return // something reasonable. return FilePath(kCurrentDirectoryString); #elif GTEST_OS_WINDOWS char cwd[GTEST_PATH_MAX_ + 1] = { '\0' }; return FilePath(_getcwd(cwd, sizeof(cwd)) == NULL ? "" : cwd); #else char cwd[GTEST_PATH_MAX_ + 1] = { '\0' }; return FilePath(getcwd(cwd, sizeof(cwd)) == NULL ? "" : cwd); #endif // GTEST_OS_WINDOWS_MOBILE } // Returns a copy of the FilePath with the case-insensitive extension removed. // Example: FilePath("dir/file.exe").RemoveExtension("EXE") returns // FilePath("dir/file"). If a case-insensitive extension is not // found, returns a copy of the original FilePath. FilePath FilePath::RemoveExtension(const char* extension) const { const std::string dot_extension = std::string(".") + extension; if (String::EndsWithCaseInsensitive(pathname_, dot_extension)) { return FilePath(pathname_.substr( 0, pathname_.length() - dot_extension.length())); } return *this; } // Returns a pointer to the last occurence of a valid path separator in // the FilePath. On Windows, for example, both '/' and '\' are valid path // separators. Returns NULL if no path separator was found. const char* FilePath::FindLastPathSeparator() const { const char* const last_sep = strrchr(c_str(), kPathSeparator); #if GTEST_HAS_ALT_PATH_SEP_ const char* const last_alt_sep = strrchr(c_str(), kAlternatePathSeparator); // Comparing two pointers of which only one is NULL is undefined. if (last_alt_sep != NULL && (last_sep == NULL || last_alt_sep > last_sep)) { return last_alt_sep; } #endif return last_sep; } // Returns a copy of the FilePath with the directory part removed. // Example: FilePath("path/to/file").RemoveDirectoryName() returns // FilePath("file"). If there is no directory part ("just_a_file"), it returns // the FilePath unmodified. If there is no file part ("just_a_dir/") it // returns an empty FilePath (""). // On Windows platform, '\' is the path separator, otherwise it is '/'. FilePath FilePath::RemoveDirectoryName() const { const char* const last_sep = FindLastPathSeparator(); return last_sep ? FilePath(last_sep + 1) : *this; } // RemoveFileName returns the directory path with the filename removed. // Example: FilePath("path/to/file").RemoveFileName() returns "path/to/". // If the FilePath is "a_file" or "/a_file", RemoveFileName returns // FilePath("./") or, on Windows, FilePath(".\\"). If the filepath does // not have a file, like "just/a/dir/", it returns the FilePath unmodified. // On Windows platform, '\' is the path separator, otherwise it is '/'. FilePath FilePath::RemoveFileName() const { const char* const last_sep = FindLastPathSeparator(); std::string dir; if (last_sep) { dir = std::string(c_str(), last_sep + 1 - c_str()); } else { dir = kCurrentDirectoryString; } return FilePath(dir); } // Helper functions for naming files in a directory for xml output. // Given directory = "dir", base_name = "test", number = 0, // extension = "xml", returns "dir/test.xml". If number is greater // than zero (e.g., 12), returns "dir/test_12.xml". // On Windows platform, uses \ as the separator rather than /. FilePath FilePath::MakeFileName(const FilePath& directory, const FilePath& base_name, int number, const char* extension) { std::string file; if (number == 0) { file = base_name.string() + "." + extension; } else { file = base_name.string() + "_" + StreamableToString(number) + "." + extension; } return ConcatPaths(directory, FilePath(file)); } // Given directory = "dir", relative_path = "test.xml", returns "dir/test.xml". // On Windows, uses \ as the separator rather than /. FilePath FilePath::ConcatPaths(const FilePath& directory, const FilePath& relative_path) { if (directory.IsEmpty()) return relative_path; const FilePath dir(directory.RemoveTrailingPathSeparator()); return FilePath(dir.string() + kPathSeparator + relative_path.string()); } // Returns true if pathname describes something findable in the file-system, // either a file, directory, or whatever. bool FilePath::FileOrDirectoryExists() const { #if GTEST_OS_WINDOWS_MOBILE LPCWSTR unicode = String::AnsiToUtf16(pathname_.c_str()); const DWORD attributes = GetFileAttributes(unicode); delete[] unicode; return attributes != kInvalidFileAttributes; #else posix::StatStruct file_stat; return posix::Stat(pathname_.c_str(), &file_stat) == 0; #endif // GTEST_OS_WINDOWS_MOBILE } // Returns true if pathname describes a directory in the file-system // that exists. bool FilePath::DirectoryExists() const { bool result = false; #if GTEST_OS_WINDOWS // Don't strip off trailing separator if path is a root directory on // Windows (like "C:\\"). const FilePath& path(IsRootDirectory() ? *this : RemoveTrailingPathSeparator()); #else const FilePath& path(*this); #endif #if GTEST_OS_WINDOWS_MOBILE LPCWSTR unicode = String::AnsiToUtf16(path.c_str()); const DWORD attributes = GetFileAttributes(unicode); delete[] unicode; if ((attributes != kInvalidFileAttributes) && (attributes & FILE_ATTRIBUTE_DIRECTORY)) { result = true; } #else posix::StatStruct file_stat; result = posix::Stat(path.c_str(), &file_stat) == 0 && posix::IsDir(file_stat); #endif // GTEST_OS_WINDOWS_MOBILE return result; } // Returns true if pathname describes a root directory. (Windows has one // root directory per disk drive.) bool FilePath::IsRootDirectory() const { #if GTEST_OS_WINDOWS // TODO(wan@google.com): on Windows a network share like // \\server\share can be a root directory, although it cannot be the // current directory. Handle this properly. return pathname_.length() == 3 && IsAbsolutePath(); #else return pathname_.length() == 1 && IsPathSeparator(pathname_.c_str()[0]); #endif } // Returns true if pathname describes an absolute path. bool FilePath::IsAbsolutePath() const { const char* const name = pathname_.c_str(); #if GTEST_OS_WINDOWS return pathname_.length() >= 3 && ((name[0] >= 'a' && name[0] <= 'z') || (name[0] >= 'A' && name[0] <= 'Z')) && name[1] == ':' && IsPathSeparator(name[2]); #else return IsPathSeparator(name[0]); #endif } // Returns a pathname for a file that does not currently exist. The pathname // will be directory/base_name.extension or // directory/base_name_.extension if directory/base_name.extension // already exists. The number will be incremented until a pathname is found // that does not already exist. // Examples: 'dir/foo_test.xml' or 'dir/foo_test_1.xml'. // There could be a race condition if two or more processes are calling this // function at the same time -- they could both pick the same filename. FilePath FilePath::GenerateUniqueFileName(const FilePath& directory, const FilePath& base_name, const char* extension) { FilePath full_pathname; int number = 0; do { full_pathname.Set(MakeFileName(directory, base_name, number++, extension)); } while (full_pathname.FileOrDirectoryExists()); return full_pathname; } // Returns true if FilePath ends with a path separator, which indicates that // it is intended to represent a directory. Returns false otherwise. // This does NOT check that a directory (or file) actually exists. bool FilePath::IsDirectory() const { return !pathname_.empty() && IsPathSeparator(pathname_.c_str()[pathname_.length() - 1]); } // Create directories so that path exists. Returns true if successful or if // the directories already exist; returns false if unable to create directories // for any reason. bool FilePath::CreateDirectoriesRecursively() const { if (!this->IsDirectory()) { return false; } if (pathname_.length() == 0 || this->DirectoryExists()) { return true; } const FilePath parent(this->RemoveTrailingPathSeparator().RemoveFileName()); return parent.CreateDirectoriesRecursively() && this->CreateFolder(); } // Create the directory so that path exists. Returns true if successful or // if the directory already exists; returns false if unable to create the // directory for any reason, including if the parent directory does not // exist. Not named "CreateDirectory" because that's a macro on Windows. bool FilePath::CreateFolder() const { #if GTEST_OS_WINDOWS_MOBILE FilePath removed_sep(this->RemoveTrailingPathSeparator()); LPCWSTR unicode = String::AnsiToUtf16(removed_sep.c_str()); int result = CreateDirectory(unicode, NULL) ? 0 : -1; delete[] unicode; #elif GTEST_OS_WINDOWS int result = _mkdir(pathname_.c_str()); #else int result = mkdir(pathname_.c_str(), 0777); #endif // GTEST_OS_WINDOWS_MOBILE if (result == -1) { return this->DirectoryExists(); // An error is OK if the directory exists. } return true; // No error. } // If input name has a trailing separator character, remove it and return the // name, otherwise return the name string unmodified. // On Windows platform, uses \ as the separator, other platforms use /. FilePath FilePath::RemoveTrailingPathSeparator() const { return IsDirectory() ? FilePath(pathname_.substr(0, pathname_.length() - 1)) : *this; } // Removes any redundant separators that might be in the pathname. // For example, "bar///foo" becomes "bar/foo". Does not eliminate other // redundancies that might be in a pathname involving "." or "..". // TODO(wan@google.com): handle Windows network shares (e.g. \\server\share). void FilePath::Normalize() { if (pathname_.c_str() == NULL) { pathname_ = ""; return; } const char* src = pathname_.c_str(); char* const dest = new char[pathname_.length() + 1]; char* dest_ptr = dest; memset(dest_ptr, 0, pathname_.length() + 1); while (*src != '\0') { *dest_ptr = *src; if (!IsPathSeparator(*src)) { src++; } else { #if GTEST_HAS_ALT_PATH_SEP_ if (*dest_ptr == kAlternatePathSeparator) { *dest_ptr = kPathSeparator; } #endif while (IsPathSeparator(*src)) src++; } dest_ptr++; } *dest_ptr = '\0'; pathname_ = dest; delete[] dest; } } // namespace internal } // namespace testing // Copyright 2008, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // Author: wan@google.com (Zhanyong Wan) #include #include #include #include #if GTEST_OS_WINDOWS_MOBILE # include // For TerminateProcess() #elif GTEST_OS_WINDOWS # include # include #else # include #endif // GTEST_OS_WINDOWS_MOBILE #if GTEST_OS_MAC # include # include # include #endif // GTEST_OS_MAC #if GTEST_OS_QNX # include # include #endif // GTEST_OS_QNX // Indicates that this translation unit is part of Google Test's // implementation. It must come before gtest-internal-inl.h is // included, or there will be a compiler error. This trick is to // prevent a user from accidentally including gtest-internal-inl.h in // his code. #define GTEST_IMPLEMENTATION_ 1 #undef GTEST_IMPLEMENTATION_ namespace testing { namespace internal { #if defined(_MSC_VER) || defined(__BORLANDC__) // MSVC and C++Builder do not provide a definition of STDERR_FILENO. const int kStdOutFileno = 1; const int kStdErrFileno = 2; #else const int kStdOutFileno = STDOUT_FILENO; const int kStdErrFileno = STDERR_FILENO; #endif // _MSC_VER #if GTEST_OS_MAC // Returns the number of threads running in the process, or 0 to indicate that // we cannot detect it. size_t GetThreadCount() { const task_t task = mach_task_self(); mach_msg_type_number_t thread_count; thread_act_array_t thread_list; const kern_return_t status = task_threads(task, &thread_list, &thread_count); if (status == KERN_SUCCESS) { // task_threads allocates resources in thread_list and we need to free them // to avoid leaks. vm_deallocate(task, reinterpret_cast(thread_list), sizeof(thread_t) * thread_count); return static_cast(thread_count); } else { return 0; } } #elif GTEST_OS_QNX // Returns the number of threads running in the process, or 0 to indicate that // we cannot detect it. size_t GetThreadCount() { const int fd = open("/proc/self/as", O_RDONLY); if (fd < 0) { return 0; } procfs_info process_info; const int status = devctl(fd, DCMD_PROC_INFO, &process_info, sizeof(process_info), NULL); close(fd); if (status == EOK) { return static_cast(process_info.num_threads); } else { return 0; } } #else size_t GetThreadCount() { // There's no portable way to detect the number of threads, so we just // return 0 to indicate that we cannot detect it. return 0; } #endif // GTEST_OS_MAC #if GTEST_USES_POSIX_RE // Implements RE. Currently only needed for death tests. RE::~RE() { if (is_valid_) { // regfree'ing an invalid regex might crash because the content // of the regex is undefined. Since the regex's are essentially // the same, one cannot be valid (or invalid) without the other // being so too. regfree(&partial_regex_); regfree(&full_regex_); } free(const_cast(pattern_)); } // Returns true iff regular expression re matches the entire str. bool RE::FullMatch(const char* str, const RE& re) { if (!re.is_valid_) return false; regmatch_t match; return regexec(&re.full_regex_, str, 1, &match, 0) == 0; } // Returns true iff regular expression re matches a substring of str // (including str itself). bool RE::PartialMatch(const char* str, const RE& re) { if (!re.is_valid_) return false; regmatch_t match; return regexec(&re.partial_regex_, str, 1, &match, 0) == 0; } // Initializes an RE from its string representation. void RE::Init(const char* regex) { pattern_ = posix::StrDup(regex); // Reserves enough bytes to hold the regular expression used for a // full match. const size_t full_regex_len = strlen(regex) + 10; char* const full_pattern = new char[full_regex_len]; snprintf(full_pattern, full_regex_len, "^(%s)$", regex); is_valid_ = regcomp(&full_regex_, full_pattern, REG_EXTENDED) == 0; // We want to call regcomp(&partial_regex_, ...) even if the // previous expression returns false. Otherwise partial_regex_ may // not be properly initialized can may cause trouble when it's // freed. // // Some implementation of POSIX regex (e.g. on at least some // versions of Cygwin) doesn't accept the empty string as a valid // regex. We change it to an equivalent form "()" to be safe. if (is_valid_) { const char* const partial_regex = (*regex == '\0') ? "()" : regex; is_valid_ = regcomp(&partial_regex_, partial_regex, REG_EXTENDED) == 0; } EXPECT_TRUE(is_valid_) << "Regular expression \"" << regex << "\" is not a valid POSIX Extended regular expression."; delete[] full_pattern; } #elif GTEST_USES_SIMPLE_RE // Returns true iff ch appears anywhere in str (excluding the // terminating '\0' character). bool IsInSet(char ch, const char* str) { return ch != '\0' && strchr(str, ch) != NULL; } // Returns true iff ch belongs to the given classification. Unlike // similar functions in , these aren't affected by the // current locale. bool IsAsciiDigit(char ch) { return '0' <= ch && ch <= '9'; } bool IsAsciiPunct(char ch) { return IsInSet(ch, "^-!\"#$%&'()*+,./:;<=>?@[\\]_`{|}~"); } bool IsRepeat(char ch) { return IsInSet(ch, "?*+"); } bool IsAsciiWhiteSpace(char ch) { return IsInSet(ch, " \f\n\r\t\v"); } bool IsAsciiWordChar(char ch) { return ('a' <= ch && ch <= 'z') || ('A' <= ch && ch <= 'Z') || ('0' <= ch && ch <= '9') || ch == '_'; } // Returns true iff "\\c" is a supported escape sequence. bool IsValidEscape(char c) { return (IsAsciiPunct(c) || IsInSet(c, "dDfnrsStvwW")); } // Returns true iff the given atom (specified by escaped and pattern) // matches ch. The result is undefined if the atom is invalid. bool AtomMatchesChar(bool escaped, char pattern_char, char ch) { if (escaped) { // "\\p" where p is pattern_char. switch (pattern_char) { case 'd': return IsAsciiDigit(ch); case 'D': return !IsAsciiDigit(ch); case 'f': return ch == '\f'; case 'n': return ch == '\n'; case 'r': return ch == '\r'; case 's': return IsAsciiWhiteSpace(ch); case 'S': return !IsAsciiWhiteSpace(ch); case 't': return ch == '\t'; case 'v': return ch == '\v'; case 'w': return IsAsciiWordChar(ch); case 'W': return !IsAsciiWordChar(ch); } return IsAsciiPunct(pattern_char) && pattern_char == ch; } return (pattern_char == '.' && ch != '\n') || pattern_char == ch; } // Helper function used by ValidateRegex() to format error messages. std::string FormatRegexSyntaxError(const char* regex, int index) { return (Message() << "Syntax error at index " << index << " in simple regular expression \"" << regex << "\": ").GetString(); } // Generates non-fatal failures and returns false if regex is invalid; // otherwise returns true. bool ValidateRegex(const char* regex) { if (regex == NULL) { // TODO(wan@google.com): fix the source file location in the // assertion failures to match where the regex is used in user // code. ADD_FAILURE() << "NULL is not a valid simple regular expression."; return false; } bool is_valid = true; // True iff ?, *, or + can follow the previous atom. bool prev_repeatable = false; for (int i = 0; regex[i]; i++) { if (regex[i] == '\\') { // An escape sequence i++; if (regex[i] == '\0') { ADD_FAILURE() << FormatRegexSyntaxError(regex, i - 1) << "'\\' cannot appear at the end."; return false; } if (!IsValidEscape(regex[i])) { ADD_FAILURE() << FormatRegexSyntaxError(regex, i - 1) << "invalid escape sequence \"\\" << regex[i] << "\"."; is_valid = false; } prev_repeatable = true; } else { // Not an escape sequence. const char ch = regex[i]; if (ch == '^' && i > 0) { ADD_FAILURE() << FormatRegexSyntaxError(regex, i) << "'^' can only appear at the beginning."; is_valid = false; } else if (ch == '$' && regex[i + 1] != '\0') { ADD_FAILURE() << FormatRegexSyntaxError(regex, i) << "'$' can only appear at the end."; is_valid = false; } else if (IsInSet(ch, "()[]{}|")) { ADD_FAILURE() << FormatRegexSyntaxError(regex, i) << "'" << ch << "' is unsupported."; is_valid = false; } else if (IsRepeat(ch) && !prev_repeatable) { ADD_FAILURE() << FormatRegexSyntaxError(regex, i) << "'" << ch << "' can only follow a repeatable token."; is_valid = false; } prev_repeatable = !IsInSet(ch, "^$?*+"); } } return is_valid; } // Matches a repeated regex atom followed by a valid simple regular // expression. The regex atom is defined as c if escaped is false, // or \c otherwise. repeat is the repetition meta character (?, *, // or +). The behavior is undefined if str contains too many // characters to be indexable by size_t, in which case the test will // probably time out anyway. We are fine with this limitation as // std::string has it too. bool MatchRepetitionAndRegexAtHead( bool escaped, char c, char repeat, const char* regex, const char* str) { const size_t min_count = (repeat == '+') ? 1 : 0; const size_t max_count = (repeat == '?') ? 1 : static_cast(-1) - 1; // We cannot call numeric_limits::max() as it conflicts with the // max() macro on Windows. for (size_t i = 0; i <= max_count; ++i) { // We know that the atom matches each of the first i characters in str. if (i >= min_count && MatchRegexAtHead(regex, str + i)) { // We have enough matches at the head, and the tail matches too. // Since we only care about *whether* the pattern matches str // (as opposed to *how* it matches), there is no need to find a // greedy match. return true; } if (str[i] == '\0' || !AtomMatchesChar(escaped, c, str[i])) return false; } return false; } // Returns true iff regex matches a prefix of str. regex must be a // valid simple regular expression and not start with "^", or the // result is undefined. bool MatchRegexAtHead(const char* regex, const char* str) { if (*regex == '\0') // An empty regex matches a prefix of anything. return true; // "$" only matches the end of a string. Note that regex being // valid guarantees that there's nothing after "$" in it. if (*regex == '$') return *str == '\0'; // Is the first thing in regex an escape sequence? const bool escaped = *regex == '\\'; if (escaped) ++regex; if (IsRepeat(regex[1])) { // MatchRepetitionAndRegexAtHead() calls MatchRegexAtHead(), so // here's an indirect recursion. It terminates as the regex gets // shorter in each recursion. return MatchRepetitionAndRegexAtHead( escaped, regex[0], regex[1], regex + 2, str); } else { // regex isn't empty, isn't "$", and doesn't start with a // repetition. We match the first atom of regex with the first // character of str and recurse. return (*str != '\0') && AtomMatchesChar(escaped, *regex, *str) && MatchRegexAtHead(regex + 1, str + 1); } } // Returns true iff regex matches any substring of str. regex must be // a valid simple regular expression, or the result is undefined. // // The algorithm is recursive, but the recursion depth doesn't exceed // the regex length, so we won't need to worry about running out of // stack space normally. In rare cases the time complexity can be // exponential with respect to the regex length + the string length, // but usually it's must faster (often close to linear). bool MatchRegexAnywhere(const char* regex, const char* str) { if (regex == NULL || str == NULL) return false; if (*regex == '^') return MatchRegexAtHead(regex + 1, str); // A successful match can be anywhere in str. do { if (MatchRegexAtHead(regex, str)) return true; } while (*str++ != '\0'); return false; } // Implements the RE class. RE::~RE() { free(const_cast(pattern_)); free(const_cast(full_pattern_)); } // Returns true iff regular expression re matches the entire str. bool RE::FullMatch(const char* str, const RE& re) { return re.is_valid_ && MatchRegexAnywhere(re.full_pattern_, str); } // Returns true iff regular expression re matches a substring of str // (including str itself). bool RE::PartialMatch(const char* str, const RE& re) { return re.is_valid_ && MatchRegexAnywhere(re.pattern_, str); } // Initializes an RE from its string representation. void RE::Init(const char* regex) { pattern_ = full_pattern_ = NULL; if (regex != NULL) { pattern_ = posix::StrDup(regex); } is_valid_ = ValidateRegex(regex); if (!is_valid_) { // No need to calculate the full pattern when the regex is invalid. return; } const size_t len = strlen(regex); // Reserves enough bytes to hold the regular expression used for a // full match: we need space to prepend a '^', append a '$', and // terminate the string with '\0'. char* buffer = static_cast(malloc(len + 3)); full_pattern_ = buffer; if (*regex != '^') *buffer++ = '^'; // Makes sure full_pattern_ starts with '^'. // We don't use snprintf or strncpy, as they trigger a warning when // compiled with VC++ 8.0. memcpy(buffer, regex, len); buffer += len; if (len == 0 || regex[len - 1] != '$') *buffer++ = '$'; // Makes sure full_pattern_ ends with '$'. *buffer = '\0'; } #endif // GTEST_USES_POSIX_RE const char kUnknownFile[] = "unknown file"; // Formats a source file path and a line number as they would appear // in an error message from the compiler used to compile this code. GTEST_API_::std::string FormatFileLocation(const char* file, int line) { const std::string file_name(file == NULL ? kUnknownFile : file); if (line < 0) { return file_name + ":"; } #ifdef _MSC_VER return file_name + "(" + StreamableToString(line) + "):"; #else return file_name + ":" + StreamableToString(line) + ":"; #endif // _MSC_VER } // Formats a file location for compiler-independent XML output. // Although this function is not platform dependent, we put it next to // FormatFileLocation in order to contrast the two functions. // Note that FormatCompilerIndependentFileLocation() does NOT append colon // to the file location it produces, unlike FormatFileLocation(). GTEST_API_::std::string FormatCompilerIndependentFileLocation( const char* file, int line) { const std::string file_name(file == NULL ? kUnknownFile : file); if (line < 0) return file_name; else return file_name + ":" + StreamableToString(line); } GTestLog::GTestLog(GTestLogSeverity severity, const char* file, int line) : severity_(severity) { const char* const marker = severity == GTEST_INFO ? "[ INFO ]" : severity == GTEST_WARNING ? "[WARNING]" : severity == GTEST_ERROR ? "[ ERROR ]" : "[ FATAL ]"; GetStream() << ::std::endl << marker << " " << FormatFileLocation(file, line).c_str() << ": "; } // Flushes the buffers and, if severity is GTEST_FATAL, aborts the program. GTestLog::~GTestLog() { GetStream() << ::std::endl; if (severity_ == GTEST_FATAL) { fflush(stderr); posix::Abort(); } } // Disable Microsoft deprecation warnings for POSIX functions called from // this class (creat, dup, dup2, and close) #ifdef _MSC_VER # pragma warning(push) # pragma warning(disable: 4996) #endif // _MSC_VER #if GTEST_HAS_STREAM_REDIRECTION // Object that captures an output stream (stdout/stderr). class CapturedStream { public: // The ctor redirects the stream to a temporary file. explicit CapturedStream(int fd) : fd_(fd), uncaptured_fd_(dup(fd)) { # if GTEST_OS_WINDOWS char temp_dir_path[MAX_PATH + 1] = { '\0' }; // NOLINT char temp_file_path[MAX_PATH + 1] = { '\0' }; // NOLINT ::GetTempPathA(sizeof(temp_dir_path), temp_dir_path); const UINT success = ::GetTempFileNameA(temp_dir_path, "gtest_redir", 0, // Generate unique file name. temp_file_path); GTEST_CHECK_(success != 0) << "Unable to create a temporary file in " << temp_dir_path; const int captured_fd = creat(temp_file_path, _S_IREAD | _S_IWRITE); GTEST_CHECK_(captured_fd != -1) << "Unable to open temporary file " << temp_file_path; filename_ = temp_file_path; # else // There's no guarantee that a test has write access to the current // directory, so we create the temporary file in the /tmp directory // instead. We use /tmp on most systems, and /sdcard on Android. // That's because Android doesn't have /tmp. # if GTEST_OS_LINUX_ANDROID // Note: Android applications are expected to call the framework's // Context.getExternalStorageDirectory() method through JNI to get // the location of the world-writable SD Card directory. However, // this requires a Context handle, which cannot be retrieved // globally from native code. Doing so also precludes running the // code as part of a regular standalone executable, which doesn't // run in a Dalvik process (e.g. when running it through 'adb shell'). // // The location /sdcard is directly accessible from native code // and is the only location (unofficially) supported by the Android // team. It's generally a symlink to the real SD Card mount point // which can be /mnt/sdcard, /mnt/sdcard0, /system/media/sdcard, or // other OEM-customized locations. Never rely on these, and always // use /sdcard. char name_template[] = "/sdcard/gtest_captured_stream.XXXXXX"; # else char name_template[] = "/tmp/captured_stream.XXXXXX"; # endif // GTEST_OS_LINUX_ANDROID const int captured_fd = mkstemp(name_template); filename_ = name_template; # endif // GTEST_OS_WINDOWS fflush(NULL); dup2(captured_fd, fd_); close(captured_fd); } ~CapturedStream() { remove(filename_.c_str()); } std::string GetCapturedString() { if (uncaptured_fd_ != -1) { // Restores the original stream. fflush(NULL); dup2(uncaptured_fd_, fd_); close(uncaptured_fd_); uncaptured_fd_ = -1; } FILE* const file = posix::FOpen(filename_.c_str(), "r"); const std::string content = ReadEntireFile(file); posix::FClose(file); return content; } private: // Reads the entire content of a file as an std::string. static std::string ReadEntireFile(FILE* file); // Returns the size (in bytes) of a file. static size_t GetFileSize(FILE* file); const int fd_; // A stream to capture. int uncaptured_fd_; // Name of the temporary file holding the stderr output. ::std::string filename_; GTEST_DISALLOW_COPY_AND_ASSIGN_(CapturedStream); }; // Returns the size (in bytes) of a file. size_t CapturedStream::GetFileSize(FILE* file) { fseek(file, 0, SEEK_END); return static_cast(ftell(file)); } // Reads the entire content of a file as a string. std::string CapturedStream::ReadEntireFile(FILE* file) { const size_t file_size = GetFileSize(file); char* const buffer = new char[file_size]; size_t bytes_last_read = 0; // # of bytes read in the last fread() size_t bytes_read = 0; // # of bytes read so far fseek(file, 0, SEEK_SET); // Keeps reading the file until we cannot read further or the // pre-determined file size is reached. do { bytes_last_read = fread(buffer + bytes_read, 1, file_size - bytes_read, file); bytes_read += bytes_last_read; } while (bytes_last_read > 0 && bytes_read < file_size); const std::string content(buffer, bytes_read); delete[] buffer; return content; } # ifdef _MSC_VER # pragma warning(pop) # endif // _MSC_VER static CapturedStream* g_captured_stderr = NULL; static CapturedStream* g_captured_stdout = NULL; // Starts capturing an output stream (stdout/stderr). void CaptureStream(int fd, const char* stream_name, CapturedStream** stream) { if (*stream != NULL) { GTEST_LOG_(FATAL) << "Only one " << stream_name << " capturer can exist at a time."; } *stream = new CapturedStream(fd); } // Stops capturing the output stream and returns the captured string. std::string GetCapturedStream(CapturedStream** captured_stream) { const std::string content = (*captured_stream)->GetCapturedString(); delete *captured_stream; *captured_stream = NULL; return content; } // Starts capturing stdout. void CaptureStdout() { CaptureStream(kStdOutFileno, "stdout", &g_captured_stdout); } // Starts capturing stderr. void CaptureStderr() { CaptureStream(kStdErrFileno, "stderr", &g_captured_stderr); } // Stops capturing stdout and returns the captured string. std::string GetCapturedStdout() { return GetCapturedStream(&g_captured_stdout); } // Stops capturing stderr and returns the captured string. std::string GetCapturedStderr() { return GetCapturedStream(&g_captured_stderr); } #endif // GTEST_HAS_STREAM_REDIRECTION #if GTEST_HAS_DEATH_TEST // A copy of all command line arguments. Set by InitGoogleTest(). ::std::vector g_argvs; static const ::std::vector* g_injected_test_argvs = NULL; // Owned. void SetInjectableArgvs(const ::std::vector* argvs) { if (g_injected_test_argvs != argvs) delete g_injected_test_argvs; g_injected_test_argvs = argvs; } const ::std::vector& GetInjectableArgvs() { if (g_injected_test_argvs != NULL) { return *g_injected_test_argvs; } return g_argvs; } #endif // GTEST_HAS_DEATH_TEST #if GTEST_OS_WINDOWS_MOBILE namespace posix { void Abort() { DebugBreak(); TerminateProcess(GetCurrentProcess(), 1); } } // namespace posix #endif // GTEST_OS_WINDOWS_MOBILE // Returns the name of the environment variable corresponding to the // given flag. For example, FlagToEnvVar("foo") will return // "GTEST_FOO" in the open-source version. static std::string FlagToEnvVar(const char* flag) { const std::string full_flag = (Message() << GTEST_FLAG_PREFIX_ << flag).GetString(); Message env_var; for (size_t i = 0; i != full_flag.length(); i++) { env_var << ToUpper(full_flag.c_str()[i]); } return env_var.GetString(); } // Parses 'str' for a 32-bit signed integer. If successful, writes // the result to *value and returns true; otherwise leaves *value // unchanged and returns false. bool ParseInt32(const Message& src_text, const char* str, Int32* value) { // Parses the environment variable as a decimal integer. char* end = NULL; const long long_value = strtol(str, &end, 10); // NOLINT // Has strtol() consumed all characters in the string? if (*end != '\0') { // No - an invalid character was encountered. Message msg; msg << "WARNING: " << src_text << " is expected to be a 32-bit integer, but actually" << " has value \"" << str << "\".\n"; printf("%s", msg.GetString().c_str()); fflush(stdout); return false; } // Is the parsed value in the range of an Int32? const Int32 result = static_cast(long_value); if (long_value == LONG_MAX || long_value == LONG_MIN || // The parsed value overflows as a long. (strtol() returns // LONG_MAX or LONG_MIN when the input overflows.) result != long_value // The parsed value overflows as an Int32. ) { Message msg; msg << "WARNING: " << src_text << " is expected to be a 32-bit integer, but actually" << " has value " << str << ", which overflows.\n"; printf("%s", msg.GetString().c_str()); fflush(stdout); return false; } *value = result; return true; } // Reads and returns the Boolean environment variable corresponding to // the given flag; if it's not set, returns default_value. // // The value is considered true iff it's not "0". bool BoolFromGTestEnv(const char* flag, bool default_value) { const std::string env_var = FlagToEnvVar(flag); const char* const string_value = posix::GetEnv(env_var.c_str()); return string_value == NULL ? default_value : strcmp(string_value, "0") != 0; } // Reads and returns a 32-bit integer stored in the environment // variable corresponding to the given flag; if it isn't set or // doesn't represent a valid 32-bit integer, returns default_value. Int32 Int32FromGTestEnv(const char* flag, Int32 default_value) { const std::string env_var = FlagToEnvVar(flag); const char* const string_value = posix::GetEnv(env_var.c_str()); if (string_value == NULL) { // The environment variable is not set. return default_value; } Int32 result = default_value; if (!ParseInt32(Message() << "Environment variable " << env_var, string_value, &result)) { printf("The default value %s is used.\n", (Message() << default_value).GetString().c_str()); fflush(stdout); return default_value; } return result; } // Reads and returns the string environment variable corresponding to // the given flag; if it's not set, returns default_value. const char* StringFromGTestEnv(const char* flag, const char* default_value) { const std::string env_var = FlagToEnvVar(flag); const char* const value = posix::GetEnv(env_var.c_str()); return value == NULL ? default_value : value; } } // namespace internal } // namespace testing // Copyright 2007, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // Author: wan@google.com (Zhanyong Wan) // Google Test - The Google C++ Testing Framework // // This file implements a universal value printer that can print a // value of any type T: // // void ::testing::internal::UniversalPrinter::Print(value, ostream_ptr); // // It uses the << operator when possible, and prints the bytes in the // object otherwise. A user can override its behavior for a class // type Foo by defining either operator<<(::std::ostream&, const Foo&) // or void PrintTo(const Foo&, ::std::ostream*) in the namespace that // defines Foo. #include #include #include // NOLINT #include namespace testing { namespace { using ::std::ostream; // Prints a segment of bytes in the given object. void PrintByteSegmentInObjectTo(const unsigned char* obj_bytes, size_t start, size_t count, ostream* os) { char text[5] = ""; for (size_t i = 0; i != count; i++) { const size_t j = start + i; if (i != 0) { // Organizes the bytes into groups of 2 for easy parsing by // human. if ((j % 2) == 0) *os << ' '; else *os << '-'; } GTEST_SNPRINTF_(text, sizeof(text), "%02X", obj_bytes[j]); *os << text; } } // Prints the bytes in the given value to the given ostream. void PrintBytesInObjectToImpl(const unsigned char* obj_bytes, size_t count, ostream* os) { // Tells the user how big the object is. *os << count << "-byte object <"; const size_t kThreshold = 132; const size_t kChunkSize = 64; // If the object size is bigger than kThreshold, we'll have to omit // some details by printing only the first and the last kChunkSize // bytes. // TODO(wan): let the user control the threshold using a flag. if (count < kThreshold) { PrintByteSegmentInObjectTo(obj_bytes, 0, count, os); } else { PrintByteSegmentInObjectTo(obj_bytes, 0, kChunkSize, os); *os << " ... "; // Rounds up to 2-byte boundary. const size_t resume_pos = (count - kChunkSize + 1) / 2 * 2; PrintByteSegmentInObjectTo(obj_bytes, resume_pos, count - resume_pos, os); } *os << ">"; } } // namespace namespace internal2 { // Delegates to PrintBytesInObjectToImpl() to print the bytes in the // given object. The delegation simplifies the implementation, which // uses the << operator and thus is easier done outside of the // ::testing::internal namespace, which contains a << operator that // sometimes conflicts with the one in STL. void PrintBytesInObjectTo(const unsigned char* obj_bytes, size_t count, ostream* os) { PrintBytesInObjectToImpl(obj_bytes, count, os); } } // namespace internal2 namespace internal { // Depending on the value of a char (or wchar_t), we print it in one // of three formats: // - as is if it's a printable ASCII (e.g. 'a', '2', ' '), // - as a hexidecimal escape sequence (e.g. '\x7F'), or // - as a special escape sequence (e.g. '\r', '\n'). enum CharFormat { kAsIs, kHexEscape, kSpecialEscape }; // Returns true if c is a printable ASCII character. We test the // value of c directly instead of calling isprint(), which is buggy on // Windows Mobile. inline bool IsPrintableAscii(wchar_t c) { return 0x20 <= c && c <= 0x7E; } // Prints a wide or narrow char c as a character literal without the // quotes, escaping it when necessary; returns how c was formatted. // The template argument UnsignedChar is the unsigned version of Char, // which is the type of c. template static CharFormat PrintAsCharLiteralTo(Char c, ostream* os) { switch (static_cast(c)) { case L'\0': *os << "\\0"; break; case L'\'': *os << "\\'"; break; case L'\\': *os << "\\\\"; break; case L'\a': *os << "\\a"; break; case L'\b': *os << "\\b"; break; case L'\f': *os << "\\f"; break; case L'\n': *os << "\\n"; break; case L'\r': *os << "\\r"; break; case L'\t': *os << "\\t"; break; case L'\v': *os << "\\v"; break; default: if (IsPrintableAscii(c)) { *os << static_cast(c); return kAsIs; } else { *os << "\\x" + String::FormatHexInt(static_cast(c)); return kHexEscape; } } return kSpecialEscape; } // Prints a wchar_t c as if it's part of a string literal, escaping it when // necessary; returns how c was formatted. static CharFormat PrintAsStringLiteralTo(wchar_t c, ostream* os) { switch (c) { case L'\'': *os << "'"; return kAsIs; case L'"': *os << "\\\""; return kSpecialEscape; default: return PrintAsCharLiteralTo(c, os); } } // Prints a char c as if it's part of a string literal, escaping it when // necessary; returns how c was formatted. static CharFormat PrintAsStringLiteralTo(char c, ostream* os) { return PrintAsStringLiteralTo( static_cast(static_cast(c)), os); } // Prints a wide or narrow character c and its code. '\0' is printed // as "'\\0'", other unprintable characters are also properly escaped // using the standard C++ escape sequence. The template argument // UnsignedChar is the unsigned version of Char, which is the type of c. template void PrintCharAndCodeTo(Char c, ostream* os) { // First, print c as a literal in the most readable form we can find. *os << ((sizeof(c) > 1) ? "L'" : "'"); const CharFormat format = PrintAsCharLiteralTo(c, os); *os << "'"; // To aid user debugging, we also print c's code in decimal, unless // it's 0 (in which case c was printed as '\\0', making the code // obvious). if (c == 0) return; *os << " (" << static_cast(c); // For more convenience, we print c's code again in hexidecimal, // unless c was already printed in the form '\x##' or the code is in // [1, 9]. if (format == kHexEscape || (1 <= c && c <= 9)) { // Do nothing. } else { *os << ", 0x" << String::FormatHexInt(static_cast(c)); } *os << ")"; } void PrintTo(unsigned char c, ::std::ostream* os) { PrintCharAndCodeTo(c, os); } void PrintTo(signed char c, ::std::ostream* os) { PrintCharAndCodeTo(c, os); } // Prints a wchar_t as a symbol if it is printable or as its internal // code otherwise and also as its code. L'\0' is printed as "L'\\0'". void PrintTo(wchar_t wc, ostream* os) { PrintCharAndCodeTo(wc, os); } // Prints the given array of characters to the ostream. CharType must be either // char or wchar_t. // The array starts at begin, the length is len, it may include '\0' characters // and may not be NUL-terminated. template static void PrintCharsAsStringTo( const CharType* begin, size_t len, ostream* os) { const char* const kQuoteBegin = sizeof(CharType) == 1 ? "\"" : "L\""; *os << kQuoteBegin; bool is_previous_hex = false; for (size_t index = 0; index < len; ++index) { const CharType cur = begin[index]; if (is_previous_hex && IsXDigit(cur)) { // Previous character is of '\x..' form and this character can be // interpreted as another hexadecimal digit in its number. Break string to // disambiguate. *os << "\" " << kQuoteBegin; } is_previous_hex = PrintAsStringLiteralTo(cur, os) == kHexEscape; } *os << "\""; } // Prints a (const) char/wchar_t array of 'len' elements, starting at address // 'begin'. CharType must be either char or wchar_t. template static void UniversalPrintCharArray( const CharType* begin, size_t len, ostream* os) { // The code // const char kFoo[] = "foo"; // generates an array of 4, not 3, elements, with the last one being '\0'. // // Therefore when printing a char array, we don't print the last element if // it's '\0', such that the output matches the string literal as it's // written in the source code. if (len > 0 && begin[len - 1] == '\0') { PrintCharsAsStringTo(begin, len - 1, os); return; } // If, however, the last element in the array is not '\0', e.g. // const char kFoo[] = { 'f', 'o', 'o' }; // we must print the entire array. We also print a message to indicate // that the array is not NUL-terminated. PrintCharsAsStringTo(begin, len, os); *os << " (no terminating NUL)"; } // Prints a (const) char array of 'len' elements, starting at address 'begin'. void UniversalPrintArray(const char* begin, size_t len, ostream* os) { UniversalPrintCharArray(begin, len, os); } // Prints a (const) wchar_t array of 'len' elements, starting at address // 'begin'. void UniversalPrintArray(const wchar_t* begin, size_t len, ostream* os) { UniversalPrintCharArray(begin, len, os); } // Prints the given C string to the ostream. void PrintTo(const char* s, ostream* os) { if (s == NULL) { *os << "NULL"; } else { *os << ImplicitCast_(s) << " pointing to "; PrintCharsAsStringTo(s, strlen(s), os); } } // MSVC compiler can be configured to define whar_t as a typedef // of unsigned short. Defining an overload for const wchar_t* in that case // would cause pointers to unsigned shorts be printed as wide strings, // possibly accessing more memory than intended and causing invalid // memory accesses. MSVC defines _NATIVE_WCHAR_T_DEFINED symbol when // wchar_t is implemented as a native type. #if !defined(_MSC_VER) || defined(_NATIVE_WCHAR_T_DEFINED) // Prints the given wide C string to the ostream. void PrintTo(const wchar_t* s, ostream* os) { if (s == NULL) { *os << "NULL"; } else { *os << ImplicitCast_(s) << " pointing to "; PrintCharsAsStringTo(s, wcslen(s), os); } } #endif // wchar_t is native // Prints a ::string object. #if GTEST_HAS_GLOBAL_STRING void PrintStringTo(const ::string& s, ostream* os) { PrintCharsAsStringTo(s.data(), s.size(), os); } #endif // GTEST_HAS_GLOBAL_STRING void PrintStringTo(const ::std::string& s, ostream* os) { PrintCharsAsStringTo(s.data(), s.size(), os); } // Prints a ::wstring object. #if GTEST_HAS_GLOBAL_WSTRING void PrintWideStringTo(const ::wstring& s, ostream* os) { PrintCharsAsStringTo(s.data(), s.size(), os); } #endif // GTEST_HAS_GLOBAL_WSTRING #if GTEST_HAS_STD_WSTRING void PrintWideStringTo(const ::std::wstring& s, ostream* os) { PrintCharsAsStringTo(s.data(), s.size(), os); } #endif // GTEST_HAS_STD_WSTRING } // namespace internal } // namespace testing // Copyright 2008, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // Author: mheule@google.com (Markus Heule) // // The Google C++ Testing Framework (Google Test) // Indicates that this translation unit is part of Google Test's // implementation. It must come before gtest-internal-inl.h is // included, or there will be a compiler error. This trick is to // prevent a user from accidentally including gtest-internal-inl.h in // his code. #define GTEST_IMPLEMENTATION_ 1 #undef GTEST_IMPLEMENTATION_ namespace testing { using internal::GetUnitTestImpl; // Gets the summary of the failure message by omitting the stack trace // in it. std::string TestPartResult::ExtractSummary(const char* message) { const char* const stack_trace = strstr(message, internal::kStackTraceMarker); return stack_trace == NULL ? message : std::string(message, stack_trace); } // Prints a TestPartResult object. std::ostream& operator<<(std::ostream& os, const TestPartResult& result) { return os << result.file_name() << ":" << result.line_number() << ": " << (result.type() == TestPartResult::kSuccess ? "Success" : result.type() == TestPartResult::kFatalFailure ? "Fatal failure" : "Non-fatal failure") << ":\n" << result.message() << std::endl; } // Appends a TestPartResult to the array. void TestPartResultArray::Append(const TestPartResult& result) { array_.push_back(result); } // Returns the TestPartResult at the given index (0-based). const TestPartResult& TestPartResultArray::GetTestPartResult(int index) const { if (index < 0 || index >= size()) { printf("\nInvalid index (%d) into TestPartResultArray.\n", index); internal::posix::Abort(); } return array_[index]; } // Returns the number of TestPartResult objects in the array. int TestPartResultArray::size() const { return static_cast(array_.size()); } namespace internal { HasNewFatalFailureHelper::HasNewFatalFailureHelper() : has_new_fatal_failure_(false), original_reporter_(GetUnitTestImpl()-> GetTestPartResultReporterForCurrentThread()) { GetUnitTestImpl()->SetTestPartResultReporterForCurrentThread(this); } HasNewFatalFailureHelper::~HasNewFatalFailureHelper() { GetUnitTestImpl()->SetTestPartResultReporterForCurrentThread( original_reporter_); } void HasNewFatalFailureHelper::ReportTestPartResult( const TestPartResult& result) { if (result.fatally_failed()) has_new_fatal_failure_ = true; original_reporter_->ReportTestPartResult(result); } } // namespace internal } // namespace testing // Copyright 2008 Google Inc. // All Rights Reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // Author: wan@google.com (Zhanyong Wan) namespace testing { namespace internal { #if GTEST_HAS_TYPED_TEST_P // Skips to the first non-space char in str. Returns an empty string if str // contains only whitespace characters. static const char* SkipSpaces(const char* str) { while (IsSpace(*str)) str++; return str; } // Verifies that registered_tests match the test names in // defined_test_names_; returns registered_tests if successful, or // aborts the program otherwise. const char* TypedTestCasePState::VerifyRegisteredTestNames( const char* file, int line, const char* registered_tests) { typedef ::std::set::const_iterator DefinedTestIter; registered_ = true; // Skip initial whitespace in registered_tests since some // preprocessors prefix stringizied literals with whitespace. registered_tests = SkipSpaces(registered_tests); Message errors; ::std::set tests; for (const char* names = registered_tests; names != NULL; names = SkipComma(names)) { const std::string name = GetPrefixUntilComma(names); if (tests.count(name) != 0) { errors << "Test " << name << " is listed more than once.\n"; continue; } bool found = false; for (DefinedTestIter it = defined_test_names_.begin(); it != defined_test_names_.end(); ++it) { if (name == *it) { found = true; break; } } if (found) { tests.insert(name); } else { errors << "No test named " << name << " can be found in this test case.\n"; } } for (DefinedTestIter it = defined_test_names_.begin(); it != defined_test_names_.end(); ++it) { if (tests.count(*it) == 0) { errors << "You forgot to list test " << *it << ".\n"; } } const std::string& errors_str = errors.GetString(); if (errors_str != "") { fprintf(stderr, "%s %s", FormatFileLocation(file, line).c_str(), errors_str.c_str()); fflush(stderr); posix::Abort(); } return registered_tests; } #endif // GTEST_HAS_TYPED_TEST_P } // namespace internal } // namespace testing gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/ULT/stdafx.h000066400000000000000000000053121466655022700221620ustar00rootroot00000000000000/*============================================================================== Copyright(c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ============================================================================*/ //Abstract: include file for standard system include files, // or project specific include files that are used frequently #pragma once #ifndef _WIN32 #include "../../inc/portable_compiler.h" #endif #include "targetver.h" #include #include #ifdef _WIN32 #include #include #endif #include #include "gtest.h" #ifdef __cplusplus extern "C" { #endif #include "sharedata.h" #include "../../inc/common/igfxfmid.h" #include "../../inc/common/sku_wa.h" #include "../../inc/common/gfxmacro.h" #include "../inc/External/Common/GmmCommonExt.h" #include "../inc/External/Common/GmmPlatformExt.h" #include "../inc/External/Common/GmmCachePolicy.h" #include "../inc/External/Common/GmmTextureExt.h" #include "../inc/External/Common/GmmResourceInfoExt.h" #include "../inc/External/Common/GmmResourceInfo.h" #include "../inc/External/Common/GmmUtil.h" #include "../inc/External/Common/GmmInfoExt.h" #include "../inc/External/Common/GmmInfo.h" #include "../inc/External/Common/GmmClientContext.h" #include "../inc/External/Common/GmmPageTableMgr.h" #include "../inc/External/Common/GmmLibDll.h" #include "../inc/External/Common/GmmLibDllName.h" #ifdef __cplusplus } #endif #ifndef NT_SUCCESS #define NT_SUCCESS(Status) ((NTSTATUS)(Status) >= 0) #endif #ifndef STATUS_UNSUCCESSFUL #define STATUS_UNSUCCESSFUL ((NTSTATUS)0xC0000001L) #endif #ifndef STATUS_SUCCESS #define STATUS_SUCCESS ((NTSTATUS)0x00000000L) #endif extern int g_argc; extern char** g_argv; gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/ULT/targetver.h000066400000000000000000000030141466655022700226710ustar00rootroot00000000000000/*============================================================================== Copyright(c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ============================================================================*/ #pragma once // Including SDKDDKVer.h defines the highest available Windows platform. // If you wish to build your application for a previous Windows platform, include WinSDKVer.h and // set the _WIN32_WINNT macro to the platform you wish to support before including SDKDDKVer.h. #if _WIN32 #include #endif gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/Utility/000077500000000000000000000000001466655022700215165ustar00rootroot00000000000000gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/Utility/CpuSwizzleBlt/000077500000000000000000000000001466655022700242775ustar00rootroot00000000000000gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/Utility/CpuSwizzleBlt/CpuSwizzleBlt.c000066400000000000000000001676171466655022700272460ustar00rootroot00000000000000/*============================================================================== Copyright(c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ============================================================================*/ // clang-format off // CpuSwizzleBlt.c - Surface swizzling definitions and BLT functionality. // [!] File serves as its own header: // #define INCLUDE_CpuSwizzleBlt_c_AS_HEADER // #include "CpuSwizzleBlt.c" #define SUB_ELEMENT_SUPPORT // Support for Partial Element Transfer (e.g. separating/merging depth-stencil). #define INTEL_TILE_W_SUPPORT // Stencil Only; #ifndef CpuSwizzleBlt_INCLUDED #ifdef __cplusplus extern "C" { #endif // Background ################################################################## /* Pixel-based surfaces commonly stored in memory row-by-row. This convention has simple "y * Pitch + x" addressing but has spatial locality only in horizontal direction--i.e. horizontal pixel neighbors stored next to each other but vertical neighbors stored entire pitch away. Since many graphics operations involve multi-dimensional data access, to improve cache/memory access performance it is often more beneficial to use alternative storage conventions which have multi-dimensional spatial locality-- i.e. where pixels tend to be stored near both their horizontal and vertical neighbors. "Tiling/Swizzling" is storage convention that increases multi-dimensional spatial locality by treating surface as series of smaller regions/"tiles", laid out in row-major order across surface, with entire content of each tile stored contiguously. Data within each tile is stored in pattern that further maximizes the locality. */ // Swizzle Descriptors ######################################################### /* Tile sizes always powers of 2 and chosen to be architecturally convenient-- e.g. 4KB to match physical page size. Tile dimensions also powers of 2, usually chosen to produce square tiles for targeted pixel size--e.g. 4KB = 128 bytes x 32 rows = 32 x 32 pixels @ 4 bytes-per-pixel. Since tile size and dimensions all powers of two, the spatial-to-linear mapping required to store a tile can be trivial: spatial indexing bits can simply be mapped to linear offset bits--e.g. for a 4KB, 128x32 tile...each byte within tile can be referenced with a 7-bit X index and 5-bit Y index--and each of those 12 index bits can be individually mapped to a bit in the 12-bit offset of the tile's linear storage. The order in which spatial index bits are mapped to linear offset bits determines the spatial locality properties of the surface data. E.g. the following mapping... Linear[11:0] = Y4 Y3 Y2 Y1 Y0 X6 X5 X4 X3 X2 X1 X0 \-- Y[4:0] --/ \----- X[6:0] -----/ ...stores bytes of tile in row-major order, with horizontal neighbors stored contiguously and vertical neighbors stored 128 bytes away. If instead, Y index bits were mapped to the low-order... Linear[11:0] = X6 X5 X4 X3 X2 X1 X0 Y4 Y3 Y2 Y1 Y0 \----- X[6:0] -----/ \-- Y[4:0] --/ ...bytes of tile would be stored in column-major order, with vertical neighbors stored contiguously and horizontal neighbors stored 32 bytes away. Individual X and Y bits can be separated and interspersed in mapping to increase locality via sub-tiling--e.g... Linear[11:0] = Y4 Y3 Y2 X6 X5 X4 Y1 Y0 X3 X2 X1 X0 \-- Sub-Tile ---/ ...subdivies tile into 16x4 sub-tiles laid out in row-major order across tile, with sub-tile content further stored in row-major order, with horizontal byte neighbors within sub-tile stored contiguously and vertical neighbors only 16 bytes away. This means single 64-byte cache line contains 4x4 group of 32bpp pixels--which is powerful spatial locality for graphics processing. If mappings restricted to being "parallel" for index bits (i.e. bits of given index can change position but not relative order during mapping), then bit indexes need not be explicitly denoted--e.g. the previous sub-tiling mapping can be represented as... Linear[11:0] = Y Y Y X X X Y Y X X X X ...where X and Y index bits are implied to be zero-based-counted in order they are encountered. In software, spatial-to-linear mapping conveniently described with bit mask for each dimension, where a set bit indicates the next bit of that dimension's index is mapped to that position in the linear offset--e.g.... Linear[11:0] = Y Y Y X X X Y Y X X X X MaskX = 0 0 0 1 1 1 0 0 1 1 1 1 MaskY = 1 1 1 0 0 0 1 1 0 0 0 0 Such dimensional masks all that's needed to describe given tiling/swizzling convention, since tile size and dimensions can be derived from the masks: TileWidth = 2 ^ NumberOfSetBits(MaskX) TileHeight = 2 ^ NumberOfSetBits(MaskY) TileSize = 2 ^ NumberOfSetBits(MaskX OR MaskY) Tiling/swizzling is not limited to 2D. With addition of another tile dimension, spatial locality for 3D or MSAA sample neighbors can be controlled, also. */ typedef struct _SWIZZLE_DESCRIPTOR { struct _SWIZZLE_DESCRIPTOR_MASKS { int x, y, z; } Mask; } SWIZZLE_DESCRIPTOR; typedef enum _EXTERNAL_SWIZZLE_NAME { TILEX = 0, TILEY, TILEW, TILEYS, TILEYF }EXTERNAL_SWIZZLE_NAME; typedef enum _EXTERNAL_RES_TYPE{ Res_2D = 0, Res_3D = 1, MSAA_2X, MSAA_4X, MSAA_8X, MSAA_16X }EXTERNAL_RES_TYPE; // Definition Helper Macros... #define X ,'x' #define Y ,'y' #define Z ,'z' #define S ,'z' // S = MSAA Sample Index #define o ,0 // o = N/A Swizzle Bit #ifdef INCLUDE_CpuSwizzleBlt_c_AS_HEADER #define __SWIZZLE(Name, b15, b14, b13, b12, b11, b10, b9, b8, b7, b6, b5, b4, b3, b2, b1, b0) \ extern const SWIZZLE_DESCRIPTOR Name; #else // C Compile... #define __SWIZZLE(Name, b15, b14, b13, b12, b11, b10, b9, b8, b7, b6, b5, b4, b3, b2, b1, b0) \ const SWIZZLE_DESCRIPTOR Name = \ { (b15 == 'x' ? 0x8000 : 0) + (b14 == 'x' ? 0x4000 : 0) + (b13 == 'x' ? 0x2000 : 0) + (b12 == 'x' ? 0x1000 : 0) + (b11 == 'x' ? 0x0800 : 0) + (b10 == 'x' ? 0x0400 : 0) + (b9 == 'x' ? 0x0200 : 0) + (b8 == 'x' ? 0x0100 : 0) + (b7 == 'x' ? 0x0080 : 0) + (b6 == 'x' ? 0x0040 : 0) + (b5 == 'x' ? 0x0020 : 0) + (b4 == 'x' ? 0x0010 : 0) + (b3 == 'x' ? 0x0008 : 0) + (b2 == 'x' ? 0x0004 : 0) + (b1 == 'x' ? 0x0002 : 0) + (b0 == 'x' ? 0x0001 : 0), \ (b15 == 'y' ? 0x8000 : 0) + (b14 == 'y' ? 0x4000 : 0) + (b13 == 'y' ? 0x2000 : 0) + (b12 == 'y' ? 0x1000 : 0) + (b11 == 'y' ? 0x0800 : 0) + (b10 == 'y' ? 0x0400 : 0) + (b9 == 'y' ? 0x0200 : 0) + (b8 == 'y' ? 0x0100 : 0) + (b7 == 'y' ? 0x0080 : 0) + (b6 == 'y' ? 0x0040 : 0) + (b5 == 'y' ? 0x0020 : 0) + (b4 == 'y' ? 0x0010 : 0) + (b3 == 'y' ? 0x0008 : 0) + (b2 == 'y' ? 0x0004 : 0) + (b1 == 'y' ? 0x0002 : 0) + (b0 == 'y' ? 0x0001 : 0), \ (b15 == 'z' ? 0x8000 : 0) + (b14 == 'z' ? 0x4000 : 0) + (b13 == 'z' ? 0x2000 : 0) + (b12 == 'z' ? 0x1000 : 0) + (b11 == 'z' ? 0x0800 : 0) + (b10 == 'z' ? 0x0400 : 0) + (b9 == 'z' ? 0x0200 : 0) + (b8 == 'z' ? 0x0100 : 0) + (b7 == 'z' ? 0x0080 : 0) + (b6 == 'z' ? 0x0040 : 0) + (b5 == 'z' ? 0x0020 : 0) + (b4 == 'z' ? 0x0010 : 0) + (b3 == 'z' ? 0x0008 : 0) + (b2 == 'z' ? 0x0004 : 0) + (b1 == 'z' ? 0x0002 : 0) + (b0 == 'z' ? 0x0001 : 0) } #endif #define SWIZZLE(__SWIZZLE_Args) __SWIZZLE __SWIZZLE_Args // Legacy Intel Tiling Swizzles... SWIZZLE(( INTEL_TILE_X o o o o Y Y Y X X X X X X X X X )); SWIZZLE(( INTEL_TILE_Y o o o o X X X Y Y Y Y Y X X X X )); #ifdef INTEL_TILE_W_SUPPORT SWIZZLE(( INTEL_TILE_W o o o o X X X Y Y Y Y X Y X Y X )); #endif // Gen9 Swizzles... SWIZZLE(( INTEL_TILE_YF_128 o o o o X Y X Y X X Y Y X X X X )); SWIZZLE(( INTEL_TILE_YF_64 o o o o X Y X Y X X Y Y X X X X )); SWIZZLE(( INTEL_TILE_YF_32 o o o o X Y X Y X Y Y Y X X X X )); SWIZZLE(( INTEL_TILE_YF_16 o o o o X Y X Y X Y Y Y X X X X )); SWIZZLE(( INTEL_TILE_YF_8 o o o o X Y X Y Y Y Y Y X X X X )); SWIZZLE(( INTEL_TILE_YS_128 X Y X Y X Y X Y X X Y Y X X X X )); SWIZZLE(( INTEL_TILE_YS_64 X Y X Y X Y X Y X X Y Y X X X X )); SWIZZLE(( INTEL_TILE_YS_32 X Y X Y X Y X Y X Y Y Y X X X X )); SWIZZLE(( INTEL_TILE_YS_16 X Y X Y X Y X Y X Y Y Y X X X X )); SWIZZLE(( INTEL_TILE_YS_8 X Y X Y X Y X Y Y Y Y Y X X X X )); SWIZZLE(( INTEL_TILE_YF_MSAA2_128 o o o o S Y X Y X X Y Y X X X X )); SWIZZLE(( INTEL_TILE_YF_MSAA2_64 o o o o S Y X Y X X Y Y X X X X )); SWIZZLE(( INTEL_TILE_YF_MSAA2_32 o o o o S Y X Y X Y Y Y X X X X )); SWIZZLE(( INTEL_TILE_YF_MSAA2_16 o o o o S Y X Y X Y Y Y X X X X )); SWIZZLE(( INTEL_TILE_YF_MSAA2_8 o o o o S Y X Y Y Y Y Y X X X X )); SWIZZLE(( INTEL_TILE_YS_MSAA2_128 S Y X Y X Y X Y X X Y Y X X X X )); SWIZZLE(( INTEL_TILE_YS_MSAA2_64 S Y X Y X Y X Y X X Y Y X X X X )); SWIZZLE(( INTEL_TILE_YS_MSAA2_32 S Y X Y X Y X Y X Y Y Y X X X X )); SWIZZLE(( INTEL_TILE_YS_MSAA2_16 S Y X Y X Y X Y X Y Y Y X X X X )); SWIZZLE(( INTEL_TILE_YS_MSAA2_8 S Y X Y X Y X Y Y Y Y Y X X X X )); SWIZZLE(( INTEL_TILE_YF_MSAA4_128 o o o o S S X Y X X Y Y X X X X )); SWIZZLE(( INTEL_TILE_YF_MSAA4_64 o o o o S S X Y X X Y Y X X X X )); SWIZZLE(( INTEL_TILE_YF_MSAA4_32 o o o o S S X Y X Y Y Y X X X X )); SWIZZLE(( INTEL_TILE_YF_MSAA4_16 o o o o S S X Y X Y Y Y X X X X )); SWIZZLE(( INTEL_TILE_YF_MSAA4_8 o o o o S S X Y Y Y Y Y X X X X )); SWIZZLE(( INTEL_TILE_YS_MSAA4_128 S S X Y X Y X Y X X Y Y X X X X )); SWIZZLE(( INTEL_TILE_YS_MSAA4_64 S S X Y X Y X Y X X Y Y X X X X )); SWIZZLE(( INTEL_TILE_YS_MSAA4_32 S S X Y X Y X Y X Y Y Y X X X X )); SWIZZLE(( INTEL_TILE_YS_MSAA4_16 S S X Y X Y X Y X Y Y Y X X X X )); SWIZZLE(( INTEL_TILE_YS_MSAA4_8 S S X Y X Y X Y Y Y Y Y X X X X )); SWIZZLE(( INTEL_TILE_YF_MSAA8_128 o o o o S S S Y X X Y Y X X X X )); SWIZZLE(( INTEL_TILE_YF_MSAA8_64 o o o o S S S Y X X Y Y X X X X )); SWIZZLE(( INTEL_TILE_YF_MSAA8_32 o o o o S S S Y X Y Y Y X X X X )); SWIZZLE(( INTEL_TILE_YF_MSAA8_16 o o o o S S S Y X Y Y Y X X X X )); SWIZZLE(( INTEL_TILE_YF_MSAA8_8 o o o o S S S Y Y Y Y Y X X X X )); SWIZZLE(( INTEL_TILE_YS_MSAA8_128 S S S Y X Y X Y X X Y Y X X X X )); SWIZZLE(( INTEL_TILE_YS_MSAA8_64 S S S Y X Y X Y X X Y Y X X X X )); SWIZZLE(( INTEL_TILE_YS_MSAA8_32 S S S Y X Y X Y X Y Y Y X X X X )); SWIZZLE(( INTEL_TILE_YS_MSAA8_16 S S S Y X Y X Y X Y Y Y X X X X )); SWIZZLE(( INTEL_TILE_YS_MSAA8_8 S S S Y X Y X Y Y Y Y Y X X X X )); SWIZZLE(( INTEL_TILE_YF_MSAA16_128 o o o o S S S S X X Y Y X X X X )); SWIZZLE(( INTEL_TILE_YF_MSAA16_64 o o o o S S S S X X Y Y X X X X )); SWIZZLE(( INTEL_TILE_YF_MSAA16_32 o o o o S S S S X Y Y Y X X X X )); SWIZZLE(( INTEL_TILE_YF_MSAA16_16 o o o o S S S S X Y Y Y X X X X )); SWIZZLE(( INTEL_TILE_YF_MSAA16_8 o o o o S S S S Y Y Y Y X X X X )); SWIZZLE(( INTEL_TILE_YS_MSAA16_128 S S S S X Y X Y X X Y Y X X X X )); SWIZZLE(( INTEL_TILE_YS_MSAA16_64 S S S S X Y X Y X X Y Y X X X X )); SWIZZLE(( INTEL_TILE_YS_MSAA16_32 S S S S X Y X Y X Y Y Y X X X X )); SWIZZLE(( INTEL_TILE_YS_MSAA16_16 S S S S X Y X Y X Y Y Y X X X X )); SWIZZLE(( INTEL_TILE_YS_MSAA16_8 S S S S X Y X Y Y Y Y Y X X X X )); SWIZZLE(( INTEL_TILE_YF_3D_128 o o o o Y Z X X Z Z Y Y X X X X )); SWIZZLE(( INTEL_TILE_YF_3D_64 o o o o Y Z X X Z Z Y Y X X X X )); SWIZZLE(( INTEL_TILE_YF_3D_32 o o o o Y Z X Y Z Z Y Y X X X X )); SWIZZLE(( INTEL_TILE_YF_3D_16 o o o o Y Z Y Z Z Z Y Y X X X X )); SWIZZLE(( INTEL_TILE_YF_3D_8 o o o o Y Z Y Z Z Z Y Y X X X X )); SWIZZLE(( INTEL_TILE_YS_3D_128 X Y Z X Y Z X X Z Z Y Y X X X X )); SWIZZLE(( INTEL_TILE_YS_3D_64 X Y Z X Y Z X X Z Z Y Y X X X X )); SWIZZLE(( INTEL_TILE_YS_3D_32 X Y Z X Y Z X Y Z Z Y Y X X X X )); SWIZZLE(( INTEL_TILE_YS_3D_16 X Y Z X Y Z Y Z Z Z Y Y X X X X )); SWIZZLE(( INTEL_TILE_YS_3D_8 X Y Z X Y Z Y Z Z Z Y Y X X X X )); // XE_HP_SDV Swizzles... SWIZZLE(( INTEL_TILE_4 o o o o Y Y X Y X X Y Y X X X X )); SWIZZLE(( INTEL_TILE_64_128 Y X X X Y Y X Y X X Y Y X X X X )); SWIZZLE(( INTEL_TILE_64_64 Y X X X Y Y X Y X X Y Y X X X X )); SWIZZLE(( INTEL_TILE_64_32 Y Y X X Y Y X Y X X Y Y X X X X )); SWIZZLE(( INTEL_TILE_64_16 Y Y X X Y Y X Y X X Y Y X X X X )); SWIZZLE(( INTEL_TILE_64_8 Y Y Y X Y Y X Y X X Y Y X X X X )); SWIZZLE(( INTEL_TILE_64_MSAA2_128 Y X X X Y Y X Y S X Y Y X X X X )); SWIZZLE(( INTEL_TILE_64_MSAA2_64 Y X X X Y Y X Y S X Y Y X X X X )); SWIZZLE(( INTEL_TILE_64_MSAA2_32 Y Y X X Y Y X Y S X Y Y X X X X )); SWIZZLE(( INTEL_TILE_64_MSAA2_16 Y Y X X Y Y X Y S X Y Y X X X X )); SWIZZLE(( INTEL_TILE_64_MSAA2_8 Y Y Y X Y Y X Y S X Y Y X X X X )); SWIZZLE(( INTEL_TILE_64_MSAA_128 Y X X X Y Y X S S X Y Y X X X X )); SWIZZLE(( INTEL_TILE_64_MSAA_64 Y X X X Y Y X S S X Y Y X X X X )); SWIZZLE(( INTEL_TILE_64_MSAA_32 Y Y X X Y Y X S S X Y Y X X X X )); SWIZZLE(( INTEL_TILE_64_MSAA_16 Y Y X X Y Y X S S X Y Y X X X X )); SWIZZLE(( INTEL_TILE_64_MSAA_8 Y Y Y X Y Y X S S X Y Y X X X X )); SWIZZLE(( INTEL_TILE_64_3D_128 Z Z Y X X X Z Y Z X Y Y X X X X )); SWIZZLE(( INTEL_TILE_64_3D_64 Z Z Y X X X Z Y Z X Y Y X X X X )); SWIZZLE(( INTEL_TILE_64_3D_32 Z Z Y X Y X Z Y Z X Y Y X X X X )); SWIZZLE(( INTEL_TILE_64_3D_16 Z Z Z Y Y X Z Y Z X Y Y X X X X )); SWIZZLE(( INTEL_TILE_64_3D_8 Z Z Z X Y Y Z Y Z X Y Y X X X X )); //Tile64 updated layout for Render Compression 256B and Physical L3 SWIZZLE(( INTEL_TILE_64_V2_MSAA2_128 Y X X X Y Y X S X X Y Y X X X X )); SWIZZLE(( INTEL_TILE_64_V2_MSAA2_64 Y Y X X Y Y X S X X Y Y X X X X )); SWIZZLE(( INTEL_TILE_64_V2_MSAA2_32 Y Y Y X Y Y X S X X Y Y X X X X )); SWIZZLE(( INTEL_TILE_64_V2_MSAA2_16 Y Y Y X Y Y X S X X Y Y X X X X )); SWIZZLE(( INTEL_TILE_64_V2_MSAA2_8 Y Y Y Y Y Y X S X X Y Y X X X X )); SWIZZLE(( INTEL_TILE_64_V2_MSAA4_128 Y X X X Y Y S S X X Y Y X X X X )); SWIZZLE(( INTEL_TILE_64_V2_MSAA4_64 Y X X X Y Y S S X X Y Y X X X X )); SWIZZLE(( INTEL_TILE_64_V2_MSAA4_32 Y Y X X Y Y S S X X Y Y X X X X )); SWIZZLE(( INTEL_TILE_64_V2_MSAA4_16 Y Y X X Y Y S S X X Y Y X X X X )); SWIZZLE(( INTEL_TILE_64_V2_MSAA4_8 Y Y Y X Y Y S S X X Y Y X X X X )); SWIZZLE(( INTEL_TILE_64_V2_MSAA8_128 Y Y X X Y X S S S X Y Y X X X X )); SWIZZLE(( INTEL_TILE_64_V2_MSAA8_64 Y Y X X Y X S S S X Y Y X X X X )); SWIZZLE(( INTEL_TILE_64_V2_MSAA8_32 Y Y X X Y X S S S X Y Y X X X X )); SWIZZLE(( INTEL_TILE_64_V2_MSAA8_16 Y Y Y X Y X S S S X Y Y X X X X )); SWIZZLE(( INTEL_TILE_64_V2_MSAA8_8 Y Y Y X Y X S S S X Y Y X X X X )); SWIZZLE(( INTEL_TILE_64_V2_MSAA16_128 Y X X X Y X S S S S Y Y X X X X )); SWIZZLE(( INTEL_TILE_64_V2_MSAA16_64 Y Y X X Y X S S S S Y Y X X X X )); SWIZZLE(( INTEL_TILE_64_V2_MSAA16_32 Y Y X X Y X S S S S Y Y X X X X )); SWIZZLE(( INTEL_TILE_64_V2_MSAA16_16 Y Y X X Y X S S S S Y Y X X X X )); SWIZZLE(( INTEL_TILE_64_V2_MSAA16_8 Y Y Y X Y X S S S S Y Y X X X X )); SWIZZLE(( INTEL_TILE_64_V2_3D_128 Z Z Y X X Y Z Z X X Y Y X X X X )); SWIZZLE(( INTEL_TILE_64_V2_3D_64 Z Z Y X X Y Z Z X X Y Y X X X X )); SWIZZLE(( INTEL_TILE_64_V2_3D_32 Z Z Y X Y Y Z Z X X Y Y X X X X )); SWIZZLE(( INTEL_TILE_64_V2_3D_16 Z Z Z Y Y Y Z Z X X Y Y X X X X )); SWIZZLE(( INTEL_TILE_64_V2_3D_8 Z Z Z Y Y Y Z Z X X Y Y X X X X )); #undef X #undef Y #undef Z #undef S #undef o #undef __SWIZZLE #undef SWIZZLE // Accessing Swizzled Surface ################################################## /* While graphics hardware prefers to access surfaces stored in tiled/swizzled formats, logically accessing such surfaces with CPU-based software is non- trivial when high throughput is goal. This file implements (1) SwizzleOffset function to compute swizzled offset of dimensionally-specified surface byte, and (2) CpuSwizzleBlt function to BLT between linear ("y * pitch + x") and swizzled surfaces--with goal of providing high-performance, swizzling BLT implementation to be used both in production and as a guide for those seeking to understand swizzled access or implement functionality beyond the simple BLT. */ // Surface Descriptor for CpuSwizzleBlt function... typedef struct _CPU_SWIZZLE_BLT_SURFACE { void *pBase; // Pointer to surface base. int Pitch, Height; // Row-pitch in bytes, and height, of surface. const SWIZZLE_DESCRIPTOR *pSwizzle; // Pointer to surface's swizzle descriptor, or NULL if unswizzled. int OffsetX; // Horizontal offset into surface for BLT rectangle, in bytes. int OffsetY; // Vertical offset into surface for BLT rectangle, in physical/pitch rows. int OffsetZ; // Zero if N/A, or 3D offset into surface for BLT rectangle, in 3D slices or MSAA samples as appropriate. #ifdef SUB_ELEMENT_SUPPORT struct _CPU_SWIZZLE_BLT_SURFACE_ELEMENT { int Pitch, Size; // Zero if full-pixel BLT, or pitch and size, in bytes, of pixel element being BLT'ed. } Element; /* e.g. to BLT only stencil data from S8D24 surface to S8 surface... Dest.Element.Size = Src.Element.Size = sizeof(S8) = 1; Dest.Element.Pitch = sizeof(S8) = 1; Src.Element.Pitch = sizeof(S8D24) = 4; Src.OffsetX += BYTE_OFFSET_OF_S8_WITHIN_S8D24; */ #endif } CPU_SWIZZLE_BLT_SURFACE; extern int SwizzleOffset(const SWIZZLE_DESCRIPTOR *pSwizzle, int Pitch, int OffsetX, int OffsetY, int OffsetZ); extern void CpuSwizzleBlt(CPU_SWIZZLE_BLT_SURFACE *pDest, CPU_SWIZZLE_BLT_SURFACE *pSrc, int CopyWidthBytes, int CopyHeight); #ifdef __cplusplus } #endif #define CpuSwizzleBlt_INCLUDED #endif #ifndef INCLUDE_CpuSwizzleBlt_c_AS_HEADER //#define MINIMALIST // Use minimalist, unoptimized implementation. #include "assert.h" // Quoted to allow local-directory override. #if(_MSC_VER >= 1400) #include #elif defined(__ARM_ARCH) #include #elif((defined __clang__) ||(__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 5))) #include #include #else #error "Unexpected compiler!" #endif // POPCNT: Count Lit Bits... 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 static unsigned char PopCnt4[16] = {0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4}; #define POPCNT4(x) (PopCnt4[(x) & 0xf]) #define POPCNT16(x) (POPCNT4((x) >> 12) + POPCNT4((x) >> 8) + POPCNT4((x) >> 4) + POPCNT4(x)) int SwizzleOffset( // ########################################################## /* Return swizzled offset of dimensionally-specified surface byte. */ const SWIZZLE_DESCRIPTOR *pSwizzle, // Pointer to applicable swizzle descriptor. int Pitch, // Pointer to applicable surface row-pitch. int OffsetX, // Horizontal offset into surface of the target byte, in bytes. int OffsetY, // Vertical offset into surface of the target byte, in physical/pitch rows. int OffsetZ) // Zero if N/A, or 3D offset into surface of the target byte, in 3D slices or MSAA samples as appropriate. /* Given logically-specified (x, y, z) byte within swizzled surface, function returns byte's linear/memory offset from surface's base--i.e. it performs the swizzled, spatial-to-linear mapping. Function makes no real effort to perform optimally, since should only used outside loops in CpuSwizzleBlt and similar functions. If any of this functionality was needed in performance path, a custom implementation should be used that limits itself to functionality specifically needed (probably single-dimension, intra-tile offsets) and uses a fast computation (e.g. LUT's, hard-codings, PDEP). */ { // ########################################################################### char PDepSupported = -1; // AVX2/BMI2 PDEP (Parallel Deposit) Instruction int SwizzledOffset; // Return value being computed. int TileWidthBits = POPCNT16(pSwizzle->Mask.x); // Log2(Tile Width in Bytes) int TileHeightBits = POPCNT16(pSwizzle->Mask.y); // Log2(Tile Height) int TileDepthBits = POPCNT16(pSwizzle->Mask.z); // Log2(Tile Depth or MSAA Samples) int TileSizeBits = TileWidthBits + TileHeightBits + TileDepthBits; // Log2(Tile Size in Bytes) int TilesPerRow = Pitch >> TileWidthBits; // Surface Width in Tiles int Row, Col; // Tile grid position on surface, of tile containing specified byte. int x, y, z; // Position of specified byte within tile that contains it. if(PDepSupported == -1) { #if(_MSC_VER >= 1700) #define PDEP(Src, Mask) _pdep_u32((Src), (Mask)) int CpuInfo[4]; __cpuidex(CpuInfo, 7, 0); PDepSupported = ((CpuInfo[1] & (1 << 8)) != 0); // EBX[8] = BMI2 #elif ( defined (__BMI2__ )) #define PDEP(Src, Mask) _pdep_u32((Src), (Mask)) unsigned int eax, ebx, ecx, edx; __cpuid_count(7, 0, eax, ebx, ecx, edx); PDepSupported = ((ebx & (1 << 8)) != 0); // EBX[8] = BMI2 #else #define PDEP(Src, Mask) 0 PDepSupported = 0; #endif } assert( // Mutually Exclusive Swizzle Positions... (pSwizzle->Mask.x | pSwizzle->Mask.y | pSwizzle->Mask.z) == (pSwizzle->Mask.x + pSwizzle->Mask.y + pSwizzle->Mask.z)); assert( // Swizzle Limited to 16-bit (else expand POPCNT'ing)... (pSwizzle->Mask.x | pSwizzle->Mask.y | pSwizzle->Mask.z) < (1 << 16)); assert( // Pitch is Multiple of Tile Width... Pitch == ((Pitch >> TileWidthBits) << TileWidthBits)); { // Break Positioning into Tile-Granular and Intra-Tile Components... assert((OffsetZ >> TileDepthBits) == 0); // When dealing with 3D tiling, treat as separate single-tile-deep planes. z = OffsetZ & ((1 << TileDepthBits) - 1); Row = OffsetY >> TileHeightBits; y = OffsetY & ((1 << TileHeightBits) - 1); Col = OffsetX >> TileWidthBits; x = OffsetX & ((1 << TileWidthBits) - 1); } SwizzledOffset = // Start with surface offset of given tile... (Row * TilesPerRow + Col) << TileSizeBits; // <-- Tiles laid across surface in row-major order. // ...then OR swizzled offset of byte within tile... if(PDepSupported) { SwizzledOffset += PDEP(x, pSwizzle->Mask.x) + PDEP(y, pSwizzle->Mask.y) + PDEP(z, pSwizzle->Mask.z); } else // PDEP workalike... { int bitIndex = 0, bitMask = 1; int terminationMask = pSwizzle->Mask.x | pSwizzle->Mask.y | pSwizzle->Mask.z; while(bitMask < terminationMask) { int MaskQ; #define PROCESS(Q) { \ MaskQ = bitMask & pSwizzle->Mask.Q; \ SwizzledOffset += Q & MaskQ; \ Q <<= 1 ^ (MaskQ >> bitIndex); \ } PROCESS(x); PROCESS(y); PROCESS(z); bitIndex++; bitMask <<= 1; #undef PROCESS } } return(SwizzledOffset); } void CpuSwizzleBlt( // ######################################################### /* Performs specified swizzling BLT between two given surfaces. */ CPU_SWIZZLE_BLT_SURFACE *pDest, // Pointer to destination surface descriptor. CPU_SWIZZLE_BLT_SURFACE *pSrc, // Pointer to source surface descriptor. int CopyWidthBytes, // Width of BLT rectangle, in bytes. int CopyHeight) // Height of BLT rectangle, in physical/pitch rows. #ifdef SUB_ELEMENT_SUPPORT /* When copying between surfaces with different pixel pitches, specify CopyWidthBytes in terms of unswizzled surface's element-pitches: CopyWidthBytes = CopyWidthPixels * pLinearSurface.Element.Pitch; */ #endif { // ########################################################################### CPU_SWIZZLE_BLT_SURFACE *pLinearSurface, *pSwizzledSurface; int LinearToSwizzled; { // One surface swizzled, the other unswizzled (aka "linear")... assert((pDest->pSwizzle != NULL) ^ (pSrc->pSwizzle != NULL)); LinearToSwizzled = !pSrc->pSwizzle; if(LinearToSwizzled) { pSwizzledSurface = pDest; pLinearSurface = pSrc; } else // Swizzled-to-Linear... { pSwizzledSurface = pSrc; pLinearSurface = pDest; } } #ifdef SUB_ELEMENT_SUPPORT { assert( // Either both or neither specified... (pDest->Element.Pitch != 0) == (pSrc->Element.Pitch != 0)); assert( // Surfaces agree on transfer element size... pDest->Element.Size == pSrc->Element.Size); assert( // Element pitch not specified without element size... !(pDest->Element.Pitch && !pDest->Element.Size)); assert( // Legit element sizes... (pDest->Element.Size <= pDest->Element.Pitch) && (pSrc->Element.Size <= pSrc->Element.Pitch)); assert( // Sub-element CopyWidthBytes in terms of LinearSurface pitch... (pLinearSurface->Element.Pitch == 0) || ((CopyWidthBytes % pLinearSurface->Element.Pitch) == 0)); } #endif { // No surface overrun... int NoOverrun = #ifdef SUB_ELEMENT_SUPPORT ( // Sub-element transfer... ((pLinearSurface->Element.Size != pLinearSurface->Element.Pitch) || (pSwizzledSurface->Element.Size != pSwizzledSurface->Element.Pitch)) && // No overrun... ((pLinearSurface->OffsetX + CopyWidthBytes) <= (pLinearSurface->Pitch + // CopyWidthBytes's inclusion of uncopied bytes... (pLinearSurface->Element.Pitch - pLinearSurface->Element.Size))) && ((pLinearSurface->OffsetY + CopyHeight) <= pLinearSurface->Height) && ((pSwizzledSurface->OffsetX + // Adjust CopyWidthBytes from being in terms of LinearSurface pitch... (CopyWidthBytes / pLinearSurface->Element.Pitch * pSwizzledSurface->Element.Pitch) ) <= (pSwizzledSurface->Pitch + // CopyWidthBytes's inclusion of uncopied bytes... (pSwizzledSurface->Element.Pitch - pSwizzledSurface->Element.Size))) && ((pSwizzledSurface->OffsetY + CopyHeight) <= pSwizzledSurface->Height) ) || #endif ((pDest->OffsetX + CopyWidthBytes) <= pDest->Pitch) && ((pDest->OffsetY + CopyHeight) <= pDest->Height) && ((pSrc->OffsetX + CopyWidthBytes) <= pSrc->Pitch) && ((pSrc->OffsetY + CopyHeight) <= pSrc->Height); assert(NoOverrun); } { // No surface overlap... char *pDest0 = (char *) pDest->pBase; char *pDest1 = (char *) pDest->pBase + pDest->Pitch * CopyHeight; char *pSrc0 = (char *) pSrc->pBase; char *pSrc1 = (char *) pSrc->pBase + pSrc->Pitch * CopyHeight; assert(!( ((pDest0 >= pSrc0) && (pDest0 < pSrc1)) || ((pSrc0 >= pDest0) && (pSrc0 < pDest1)))); } { /* BLT will have pointer in each surface between which data will be copied from source to destination. Each pointer will be appropriately incremented/positioned through its surface, as BLT rectangle is traversed. */ char *pLinearAddress, *pSwizzledAddress; // Convenient to track traversal in swizzled surface offsets... int x0 = pSwizzledSurface->OffsetX; int x1 = x0 + CopyWidthBytes; int y0 = pSwizzledSurface->OffsetY; int y1 = y0 + CopyHeight; int x, y; // Start linear pointer at specified base... pLinearAddress = (char *) pLinearSurface->pBase + pLinearSurface->OffsetY * pLinearSurface->Pitch + pLinearSurface->OffsetX; #ifdef MINIMALIST // Simple implementation for functional understanding/testing/etc. { #ifdef SUB_ELEMENT_SUPPORT assert( // No Sub-Element Transfer... (pLinearSurface->Element.Size == pLinearSurface->Element.Pitch) && (pSwizzledSurface->Element.Size == pSwizzledSurface->Element.Pitch)); #endif for(y = y0; y < y1; y++) { for(x = x0; x < x1; x++) { pSwizzledAddress = (char *) pSwizzledSurface->pBase + SwizzleOffset( pSwizzledSurface->pSwizzle, pSwizzledSurface->Pitch, x, y, pSwizzledSurface->OffsetZ); if(LinearToSwizzled) { *pSwizzledAddress = *pLinearAddress; } else { *pLinearAddress = *pSwizzledAddress; } pLinearAddress++; } pLinearAddress += pLinearSurface->Pitch - CopyWidthBytes; } } #else // Production/Performance Implementation... { /* Key Performance Gains from... (1) Efficient Memory Transfers (Ordering + Instruction) (2) Minimizing Work in Inner Loops */ #if(_MSC_VER >= 1600) #include #pragma warning(push) #pragma warning(disable:4127) // Constant Conditional Expressions unsigned long LOW_BIT_Index; #define LOW_BIT(x) (_BitScanForward(&LOW_BIT_Index, (x)), LOW_BIT_Index) unsigned long HIGH_BIT_Index; #define HIGH_BIT(x) (_BitScanReverse(&HIGH_BIT_Index, (x)), HIGH_BIT_Index) #elif(__GNUC__ >= 4) #include #define LOW_BIT(x) __builtin_ctz(x) #define HIGH_BIT(x) ((sizeof(x) * CHAR_BIT - 1) - __builtin_clz(x)) #else #error "Unexpected compiler!" #endif typedef struct ___m24 { uint8_t byte[3]; } __m24; // 24-bit/3-byte memory element. // Macros intended to compile to various types of "load register from memory" instructions... #define MOVB_R( Reg, Src) (*(uint8_t *)&(Reg) = *(uint8_t *)(Src)) #define MOVW_R( Reg, Src) (*(uint16_t *)&(Reg) = *(uint16_t *)(Src)) #define MOV3_R( Reg, Src) (*(__m24 *)&(Reg) = *(__m24 *)(Src)) #define MOVD_R( Reg, Src) (*(uint32_t *)&(Reg) = *(uint32_t *)(Src)) #define MOVQ_R( Reg, Src) ((Reg) = _mm_loadl_epi64((__m128i *)(Src))) #define MOVDQ_R( Reg, Src) ((Reg) = _mm_load_si128( (__m128i *)(Src))) #define MOVDQU_R(Reg, Src) ((Reg) = _mm_loadu_si128((__m128i *)(Src))) // As above, but the other half: "store to memory from register"... #define MOVB_M( Dest, Reg)(*(uint8_t *)(Dest) = *(uint8_t *)&(Reg)) #define MOVW_M( Dest, Reg)(*(uint16_t *)(Dest) = *(uint16_t *)&(Reg)) #define MOV3_M( Dest, Reg)(*(__m24 *)(Dest) = *(__m24 *)&(Reg)) #define MOVD_M( Dest, Reg)(*(uint32_t *)(Dest) = *(uint32_t *)&(Reg)) #define MOVQ_M( Dest, Reg)(_mm_storel_epi64((__m128i *)(Dest), (Reg))) #define MOVDQ_M( Dest, Reg)(_mm_store_si128( (__m128i *)(Dest), (Reg))) #define MOVDQU_M( Dest, Reg)(_mm_storeu_si128((__m128i *)(Dest), (Reg))) #define MOVNTDQ_M( Dest, Reg)(_mm_stream_si128((__m128i *)(Dest), (Reg))) #define MIN_CONTAINED_POW2_BELOW_CAP(x, Cap) (1 << LOW_BIT((1 << LOW_BIT(x)) | (1 << HIGH_BIT(Cap)))) #define SWIZZLE_OFFSET(OffsetX, OffsetY, OffsetZ) \ SwizzleOffset(pSwizzledSurface->pSwizzle, pSwizzledSurface->Pitch, OffsetX, OffsetY, OffsetZ) #define MAX_XFER_WIDTH 16 // See "Compute Transfer Dimensions". #define MAX_XFER_HEIGHT 4 // " char StreamingLoadSupported = -1; // SSE4.1: MOVNTDQA int TileWidthBits = POPCNT16(pSwizzledSurface->pSwizzle->Mask.x); // Log2(Tile Width in Bytes) int TileHeightBits = POPCNT16(pSwizzledSurface->pSwizzle->Mask.y); // Log2(Tile Height) int TileDepthBits = POPCNT16(pSwizzledSurface->pSwizzle->Mask.z); // Log2(Tile Depth or MSAA Samples) int BytesPerRowOfTiles = pSwizzledSurface->Pitch << (TileDepthBits + TileHeightBits); struct { int LeftCrust, MainRun, RightCrust; } CopyWidth; int MaskX[MAX_XFER_WIDTH + 1], MaskY[MAX_XFER_HEIGHT + 1]; int SwizzledOffsetX0, SwizzledOffsetY; struct { int Width, Height; } SwizzleMaxXfer; char *pSwizzledAddressCopyBase = (char *) pSwizzledSurface->pBase + SWIZZLE_OFFSET(0, 0, pSwizzledSurface->OffsetZ); assert(sizeof(__m24) == 3); if(StreamingLoadSupported == -1) { #if(_MSC_VER >= 1500) #define MOVNTDQA_R(Reg, Src) ((Reg) = _mm_stream_load_si128((__m128i *)(Src))) int CpuInfo[4]; __cpuid(CpuInfo, 1); StreamingLoadSupported = ((CpuInfo[2] & (1 << 19)) != 0); // ECX[19] = SSE4.1 #elif(defined(__ARM_ARCH)) #define MOVNTDQA_R(Reg, Src) ((Reg) = (Reg)) StreamingLoadSupported = 0; #elif((defined __clang__) || (__GNUC__ > 4) || (__GNUC__ == 4) && (__GNUC_MINOR__ >= 5)) #define MOVNTDQA_R(Reg, Src) ((Reg) = _mm_stream_load_si128((__m128i *)(Src))) unsigned int eax, ebx, ecx, edx; __cpuid(1, eax, ebx, ecx, edx); StreamingLoadSupported = ((ecx & (1 << 19)) != 0); // ECX[19] = SSE4.1 #else #define MOVNTDQA_R(Reg, Src) ((Reg) = (Reg)) StreamingLoadSupported = 0; #endif } { // Compute Transfer Dimensions... /* When transferring between linear and swizzled surfaces, we can't traverse linearly through memory of both since they have drastically different memory orderings--Moving linearly through one means bouncing around the other. Moving linearly through linear surface is more programmatically convenient--especially when BLT rectangles not constrained to tile boundaries. But moving linearly through swizzled surface memory is often more performance-friendly--especially when that memory is CPU-mapped as WC (Write Combining), which is often the case for graphics memory. Fortunately, we can avoid shortcomings of both extremes by using hybrid traversal: Traverse mostly linearly through linear surface, but have innermost loop transfer small 2D chunks sized to use critical runs of linearity in the swizzled memory. The "critical runs of linearity" that we want to hit in the sizzled memory are aligned, cache-line-sized memory chunks. If we bounce around with finer granularity we'll incur penalties of partial WC buffer use (whether from WC memory use or non- temporal stores). The size of 2D chunks with cache-line-sized linearity in swizzled memory is determined by swizzle mapping's low-order six bits (for 64-byte cache lines). Most swizzles use "Y Y X X X X" in their low-order bits, which means their cache lines store 16x4 chunks--So our implementation will use those dimensions as our target/maximum 2D transfer chunk. If we had any 8x8 (or taller) swizzles, we should add such support and increase our maximum chunk height. If we had any 32x2 swizzles, we should add such support and increase our maximum chunk width. Our implementation only bothers optimizing for 2D transfer chunks stored in row-major order--i.e. those whose swizzle mapping bits have a series of X's in the low-order, followed by Y's in the higher-order. Where a swizzle mapping inflection from Y back to X occurs, contiguous row-ordering is lost, and we would use that smaller, row-ordered chunk size. */ int TargetMask; // Narrow optimized transfer Width by looking for inflection from X's... SwizzleMaxXfer.Width = MAX_XFER_WIDTH; while( (TargetMask = SwizzleMaxXfer.Width - 1) && ((pSwizzledSurface->pSwizzle->Mask.x & TargetMask) != TargetMask)) { SwizzleMaxXfer.Width >>= 1; } // Narrow optimized transfer height by looking for inflection from Y's... SwizzleMaxXfer.Height = MAX_XFER_HEIGHT; while( (TargetMask = (SwizzleMaxXfer.Height - 1) * SwizzleMaxXfer.Width) && ((pSwizzledSurface->pSwizzle->Mask.y & TargetMask) != TargetMask)) { SwizzleMaxXfer.Height >>= 1; } } { // Separate CopyWidthBytes into unaligned left/right "crust" and aligned "MainRun"... int MaxXferWidth = MIN_CONTAINED_POW2_BELOW_CAP(SwizzleMaxXfer.Width, CopyWidthBytes); CopyWidth.LeftCrust = // i.e. "bytes to xfer-aligned boundary" (MaxXferWidth - x0) & (MaxXferWidth - 1); // Simplification of ((MaxXferWidth - (x0 % MaxXferWidth)) % MaxXferWidth) CopyWidth.MainRun = (CopyWidthBytes - CopyWidth.LeftCrust) & ~(SwizzleMaxXfer.Width - 1); // MainRun is of SwizzleMaxXfer.Width's--not MaxXferWidth's. CopyWidth.RightCrust = CopyWidthBytes - (CopyWidth.LeftCrust + CopyWidth.MainRun); #ifdef SUB_ELEMENT_SUPPORT { // For partial-pixel transfers, there is no crust and MainRun is done pixel-by-pixel... if( (pLinearSurface->Element.Size != pLinearSurface->Element.Pitch) || (pSwizzledSurface->Element.Size != pSwizzledSurface->Element.Pitch)) { CopyWidth.LeftCrust = CopyWidth.RightCrust = 0; CopyWidth.MainRun = CopyWidthBytes; } } #endif } /* Unlike in MINIMALIST implementation, which fully computes swizzled offset for each transfer element, we want to minimize work done in our inner loops. One way we'll reduce work is to separate pSwizzledAddress into dimensional components--e.g. so Y-swizzling doesn't have to be recomputed in X-loop. But a more powerful way we'll reduce work is...Instead of linearly incrementing spatial offsets and then converting to their swizzled counterparts, we'll compute swizzled bases outside the loops and keep them swizzled using swizzled incrementing inside the loops-- since swizzled incrementing can be much cheaper than repeatedly swizzling spatial offsets. Intra-tile swizzled incrementing can be done by using the inverse of a spatial component's swizzle mask to ripple-carry a +1 to and across the bits of a currently swizzled value--e.g. with... SwizzledOffsetY: Y X Y X Y Y X X X X ~MaskY: 0 1 0 1 0 0 1 1 1 1 + 1 ----------------------- ...set low-order ~MaskY bits will always ripple-carry the incrementing +1 to wherever Y0 happens to be, and wherever there is an arithmetic carry out of one Y position, set ~MaskY bits will carry it across any gaps to the next Y position. The above algorithm only works for adding one, but the mask used can be modified to deliver the +1 to any bit location, so any power of two increment can be achieved. After swizzled increment, residue from mask addition and undesired carries outside targeted fields must be removed using the natural mask--So the final intra-tile swizzled increment is... SwizzledOffsetQ = (SwizzledOffsetQ + ~MaskQ + 1) & MaskQ ...where Q is the applicable X/Y/Z dimensional component. Or since in two's compliment, (~MaskQ + 1) = -MaskQ... SwizzledOffsetQ = (SwizzledOffsetQ - MaskQ) & MaskQ Since tile sizes are powers of two and tiles laid out in row-major order across surface, the above swizzled incrementing can additionally be used for inter-tile incrementing of X component by extending applicable mask to include offset bits beyond the tile-- so arithmetic carries out of intra-tile X component will ripple to advance swizzled inter-tile X offset to next tile. Same is not true of inter-tile Y incrementing since surface pitches not restricted to powers of two. */ { // Compute Mask[IncSize] for Needed Increment Values... int ExtendedMaskX = // Bits beyond the tile (so X incrementing can operate inter-tile)... ~(pSwizzledSurface->pSwizzle->Mask.x | pSwizzledSurface->pSwizzle->Mask.y | pSwizzledSurface->pSwizzle->Mask.z); /* Subtraction below delivers natural mask for +1 increment, and appropriately altered mask to deliver +1 to higher bit positions for +2/4/8/etc. increments. */ for(x = SwizzleMaxXfer.Width; x >= 1; x >>= 1) { MaskX[x] = SWIZZLE_OFFSET((1 << TileWidthBits) - x, 0, 0) | ExtendedMaskX; } for(y = SwizzleMaxXfer.Height; y >= 1; y >>= 1) { MaskY[y] = SWIZZLE_OFFSET(0, (1 << TileHeightBits) - y, 0); } } { // Base Dimensional Swizzled Offsets... int IntraTileY = y0 & ((1 << TileHeightBits) - 1); int TileAlignedY = y0 - IntraTileY; SwizzledOffsetY = SWIZZLE_OFFSET(0, IntraTileY, 0); SwizzledOffsetX0 = SWIZZLE_OFFSET( x0, TileAlignedY, // <-- Since SwizzledOffsetX will include "bits beyond the tile". 0); } // BLT Loops /////////////////////////////////////////////////////// /* Traverse BLT rectangle, transferring small, optimally-aligned 2D chunks, as appropriate for given swizzle format. Use swizzled incrementing of dimensional swizzled components. */ for(y = y0; y < y1; ) { char *pSwizzledAddressLine = pSwizzledAddressCopyBase + SwizzledOffsetY; int xferHeight = // Largest pow2 xfer height that alignment, MaxXfer, and lines left will permit... MIN_CONTAINED_POW2_BELOW_CAP(y | SwizzleMaxXfer.Height, y1 - y); int SwizzledOffsetX = SwizzledOffsetX0; __m128i xmm[MAX_XFER_HEIGHT]; char *pLinearAddressEnd; int _MaskX; // XFER Macros ///////////////////////////////////////////////// /* We'll define "XFER" macro to contain BLT X-loop work. In simple implementation, XFER would be WHILE loop that does SSE transfer and performs pointer and swizzled offset incrementing. ...but we have multiple conditions to handle... - Transfer Direction (Linear <--> Swizzled) - Optimal 2D Transfer Chunk Size - Available/Desired CPU Transfer Instructions - Unaligned Crust Don't want X-loop to have conditional logic to handle variations since would retard performance--but neither do we want messy multitude of slightly different, copy-pasted code paths. So instead, XFER macro will provide common code template allowing instantiation of multiple X-loop variations--i.e. XFER calls from conditional Y-loop code will expand into separate, conditional-free, "lean and mean" X-loops. Some conditional logic remains in XFER chain--but only outside X-loop. The two IF statements that remain in X-loop (i.e. those in XFER_LOAD/STORE) expand to compile-time constant conditional expressions, so with optimizing compiler, no runtime- conditional code will be generated--i.e. constant conditionals will simply decide whether given instantiation has that code or not. */ #define XFER(XFER_Store, XFER_Load, XFER_Pitch_Swizzled, XFER_Pitch_Linear, XFER_pDest, XFER_DestPitch, XFER_pSrc, XFER_SrcPitch, XFER_Crust) \ { \ XFER_LINES(4, XFER_Store, XFER_Load, XFER_Pitch_Swizzled, XFER_Pitch_Linear, XFER_pDest, XFER_DestPitch, XFER_pSrc, XFER_SrcPitch, XFER_Crust) \ else XFER_LINES(2, XFER_Store, XFER_Load, XFER_Pitch_Swizzled, XFER_Pitch_Linear, XFER_pDest, XFER_DestPitch, XFER_pSrc, XFER_SrcPitch, XFER_Crust) \ else XFER_LINES(1, XFER_Store, XFER_Load, XFER_Pitch_Swizzled, XFER_Pitch_Linear, XFER_pDest, XFER_DestPitch, XFER_pSrc, XFER_SrcPitch, XFER_Crust);\ } #define XFER_LINES(XFER_LINES_Lines, XFER_Store, XFER_Load, XFER_Pitch_Swizzled, XFER_Pitch_Linear, XFER_pDest, XFER_DestPitch, XFER_pSrc, XFER_SrcPitch, XFER_Crust) \ if(xferHeight == (XFER_LINES_Lines)) \ { \ if(XFER_Crust) \ { \ XFER_SPAN(MOVB_M, MOVB_R, CopyWidth.LeftCrust & 1, 1, 1, XFER_LINES_Lines, XFER_pDest, XFER_DestPitch, XFER_pSrc, XFER_SrcPitch); \ XFER_SPAN(MOVW_M, MOVW_R, CopyWidth.LeftCrust & 2, 2, 2, XFER_LINES_Lines, XFER_pDest, XFER_DestPitch, XFER_pSrc, XFER_SrcPitch); \ XFER_SPAN(MOVD_M, MOVD_R, CopyWidth.LeftCrust & 4, 4, 4, XFER_LINES_Lines, XFER_pDest, XFER_DestPitch, XFER_pSrc, XFER_SrcPitch); \ XFER_SPAN(MOVQ_M, MOVQ_R, CopyWidth.LeftCrust & 8, 8, 8, XFER_LINES_Lines, XFER_pDest, XFER_DestPitch, XFER_pSrc, XFER_SrcPitch); \ } \ \ XFER_SPAN(XFER_Store, XFER_Load, CopyWidth.MainRun, XFER_Pitch_Swizzled, XFER_Pitch_Linear, XFER_LINES_Lines, XFER_pDest, XFER_DestPitch, XFER_pSrc, XFER_SrcPitch);\ \ if(XFER_Crust) \ { \ XFER_SPAN(MOVQ_M, MOVQ_R, CopyWidth.RightCrust & 8, 8, 8, XFER_LINES_Lines, XFER_pDest, XFER_DestPitch, XFER_pSrc, XFER_SrcPitch); \ XFER_SPAN(MOVD_M, MOVD_R, CopyWidth.RightCrust & 4, 4, 4, XFER_LINES_Lines, XFER_pDest, XFER_DestPitch, XFER_pSrc, XFER_SrcPitch); \ XFER_SPAN(MOVW_M, MOVW_R, CopyWidth.RightCrust & 2, 2, 2, XFER_LINES_Lines, XFER_pDest, XFER_DestPitch, XFER_pSrc, XFER_SrcPitch); \ XFER_SPAN(MOVB_M, MOVB_R, CopyWidth.RightCrust & 1, 1, 1, XFER_LINES_Lines, XFER_pDest, XFER_DestPitch, XFER_pSrc, XFER_SrcPitch); \ } \ } #define XFER_SPAN(XFER_Store, XFER_Load, XFER_CopyWidthBytes, XFER_Pitch_Swizzled, XFER_Pitch_Linear, XFER_Height, XFER_pDest, XFER_DestPitch, XFER_pSrc, XFER_SrcPitch) \ { \ pLinearAddressEnd = pLinearAddress + (XFER_CopyWidthBytes); \ _MaskX = MaskX[XFER_Pitch_Swizzled]; \ while(pLinearAddress < pLinearAddressEnd) \ { \ pSwizzledAddress = pSwizzledAddressLine + SwizzledOffsetX; \ \ XFER_LOAD(0, XFER_Load, XFER_pSrc, XFER_SrcPitch, XFER_Height); \ XFER_LOAD(1, XFER_Load, XFER_pSrc, XFER_SrcPitch, XFER_Height); \ XFER_LOAD(2, XFER_Load, XFER_pSrc, XFER_SrcPitch, XFER_Height); \ XFER_LOAD(3, XFER_Load, XFER_pSrc, XFER_SrcPitch, XFER_Height); \ XFER_STORE(0, XFER_Store, XFER_pDest, XFER_DestPitch, XFER_Height); \ XFER_STORE(1, XFER_Store, XFER_pDest, XFER_DestPitch, XFER_Height); \ XFER_STORE(2, XFER_Store, XFER_pDest, XFER_DestPitch, XFER_Height); \ XFER_STORE(3, XFER_Store, XFER_pDest, XFER_DestPitch, XFER_Height); \ \ SwizzledOffsetX = (SwizzledOffsetX - _MaskX) & _MaskX; \ pLinearAddress += (XFER_Pitch_Linear); \ } \ } #define XFER_LOAD(XFER_Line, XFER_Load, XFER_pSrc, XFER_SrcPitch, XFER_Height) \ { \ if((XFER_Line) < (XFER_Height)) \ { \ XFER_Load( \ xmm[XFER_Line], \ (XFER_pSrc) + (XFER_Line) * (XFER_SrcPitch)); \ } \ } #define XFER_STORE(XFER_Line, XFER_Store, XFER_pDest, XFER_DestPitch, XFER_Height) \ { \ if((XFER_Line) < (XFER_Height)) \ { \ XFER_Store( \ (XFER_pDest) + (XFER_Line) * (XFER_DestPitch), \ xmm[XFER_Line]); \ } \ } // Perform Applicable Transfer ///////////////////////////////// assert( // DQ Alignment... ((intptr_t) pSwizzledSurface->pBase % 16 == 0) && (pSwizzledSurface->Pitch % 16 == 0)); #ifdef SUB_ELEMENT_SUPPORT if( (pLinearSurface->Element.Size != pLinearSurface->Element.Pitch) || (pSwizzledSurface->Element.Size != pSwizzledSurface->Element.Pitch)) { if(LinearToSwizzled) { switch(pLinearSurface->Element.Size) { case 16: XFER(MOVNTDQ_M, MOVDQU_R, pSwizzledSurface->Element.Pitch, pLinearSurface->Element.Pitch, pSwizzledAddress, SwizzleMaxXfer.Width, pLinearAddress, pLinearSurface->Pitch, 0); break; case 8: XFER( MOVQ_M, MOVQ_R, pSwizzledSurface->Element.Pitch, pLinearSurface->Element.Pitch, pSwizzledAddress, SwizzleMaxXfer.Width, pLinearAddress, pLinearSurface->Pitch, 0); break; case 4: XFER( MOVD_M, MOVD_R, pSwizzledSurface->Element.Pitch, pLinearSurface->Element.Pitch, pSwizzledAddress, SwizzleMaxXfer.Width, pLinearAddress, pLinearSurface->Pitch, 0); break; case 3: XFER( MOV3_M, MOV3_R, pSwizzledSurface->Element.Pitch, pLinearSurface->Element.Pitch, pSwizzledAddress, SwizzleMaxXfer.Width, pLinearAddress, pLinearSurface->Pitch, 0); break; case 2: XFER( MOVW_M, MOVW_R, pSwizzledSurface->Element.Pitch, pLinearSurface->Element.Pitch, pSwizzledAddress, SwizzleMaxXfer.Width, pLinearAddress, pLinearSurface->Pitch, 0); break; case 1: XFER( MOVB_M, MOVB_R, pSwizzledSurface->Element.Pitch, pLinearSurface->Element.Pitch, pSwizzledAddress, SwizzleMaxXfer.Width, pLinearAddress, pLinearSurface->Pitch, 0); break; default: assert(0); } } else { switch(pLinearSurface->Element.Size) { case 16: { if(StreamingLoadSupported) { XFER(MOVDQU_M, MOVNTDQA_R, pSwizzledSurface->Element.Pitch, pLinearSurface->Element.Pitch, pLinearAddress, pLinearSurface->Pitch, pSwizzledAddress, SwizzleMaxXfer.Width, 0); } else { XFER(MOVDQU_M, MOVDQ_R, pSwizzledSurface->Element.Pitch, pLinearSurface->Element.Pitch, pLinearAddress, pLinearSurface->Pitch, pSwizzledAddress, SwizzleMaxXfer.Width, 0); } break; } case 8: XFER( MOVQ_M, MOVQ_R, pSwizzledSurface->Element.Pitch, pLinearSurface->Element.Pitch, pLinearAddress, pLinearSurface->Pitch, pSwizzledAddress, SwizzleMaxXfer.Width, 0); break; case 4: XFER( MOVD_M, MOVD_R, pSwizzledSurface->Element.Pitch, pLinearSurface->Element.Pitch, pLinearAddress, pLinearSurface->Pitch, pSwizzledAddress, SwizzleMaxXfer.Width, 0); break; case 3: XFER( MOV3_M, MOV3_R, pSwizzledSurface->Element.Pitch, pLinearSurface->Element.Pitch, pLinearAddress, pLinearSurface->Pitch, pSwizzledAddress, SwizzleMaxXfer.Width, 0); break; case 2: XFER( MOVW_M, MOVW_R, pSwizzledSurface->Element.Pitch, pLinearSurface->Element.Pitch, pLinearAddress, pLinearSurface->Pitch, pSwizzledAddress, SwizzleMaxXfer.Width, 0); break; case 1: XFER( MOVB_M, MOVB_R, pSwizzledSurface->Element.Pitch, pLinearSurface->Element.Pitch, pLinearAddress, pLinearSurface->Pitch, pSwizzledAddress, SwizzleMaxXfer.Width, 0); break; default: assert(0); } } } else #endif // SUB_ELEMENT_SUPPORT if(LinearToSwizzled) { switch(SwizzleMaxXfer.Width) { case 16: XFER(MOVNTDQ_M, MOVDQU_R, 16, 16, pSwizzledAddress, 16, pLinearAddress, pLinearSurface->Pitch, 1); break; #ifdef INTEL_TILE_W_SUPPORT case 2: XFER(MOVW_M, MOVW_R, 2, 2, pSwizzledAddress, 2, pLinearAddress, pLinearSurface->Pitch, 1); break; #endif default: assert(0); // Unexpected cases excluded to save compile time/size of multiplying instantiations. } } else { switch(SwizzleMaxXfer.Width) { case 16: { if(StreamingLoadSupported) { XFER(MOVDQU_M, MOVNTDQA_R, 16, 16, pLinearAddress, pLinearSurface->Pitch, pSwizzledAddress, 16, 1); } else { XFER(MOVDQU_M, MOVDQ_R, 16, 16, pLinearAddress, pLinearSurface->Pitch, pSwizzledAddress, 16, 1); } break; } #ifdef INTEL_TILE_W_SUPPORT case 2: XFER(MOVW_M, MOVW_R, 2, 2, pLinearAddress, pLinearSurface->Pitch, pSwizzledAddress, 2, 1); break; #endif default: assert(0); } } // Swizzled inc of SwizzledOffsetY... SwizzledOffsetY = (SwizzledOffsetY - MaskY[xferHeight]) & MaskY[xferHeight]; if(!SwizzledOffsetY) SwizzledOffsetX0 += BytesPerRowOfTiles; // Wraps advance SwizzledOffsetX0, since that includes "bits beyond the tile". y += xferHeight; /* X-loop only advanced pLinearAddress by CopyWidthBytes--even when transferred multiple lines. Advance rest of way: */ pLinearAddress += xferHeight * pLinearSurface->Pitch - CopyWidthBytes; } // foreach(y) _mm_sfence(); // Flush Non-Temporal Writes #if(_MSC_VER) #pragma warning(pop) #endif } #endif } } // CpuSwizzleBlt #endif // #ifndef INCLUDE_CpuSwizzleBlt_c_AS_HEADER // clang-format on gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/Utility/CpuSwizzleBlt/assert.h000066400000000000000000000027071466655022700257570ustar00rootroot00000000000000/*============================================================================== Copyright(c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ============================================================================*/ // File intended for same-folder-inclusion by CpuSwizzleBlt.c to reroute // standard asserts when compiled in GMM. #pragma once #ifdef __GMM #include "External/Common/GmmInternal.h" #define assert __GMM_ASSERT #else #include #endif gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/Utility/GmmLog/000077500000000000000000000000001466655022700227005ustar00rootroot00000000000000gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/Utility/GmmLog/GmmLog.cpp000066400000000000000000000234331466655022700245730ustar00rootroot00000000000000/*============================================================================== Copyright(c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ============================================================================*/ #include "GmmLog.h" #if GMM_LOG_AVAILABLE #include "Internal/Common/GmmLibInc.h" #include "Internal/Common/GmmLogger.h" #if _WIN32 #include #include #else #include #include #include #include #include #endif /// Logger instance shared by all of GmmLib within a process #if(_DEBUG || _RELEASE_INTERNAL) GmmLib::Logger &GmmLoggerPerProc = GmmLib::Logger::CreateGmmLogSingleton(); #endif #if _WIN32 namespace spdlog { namespace sinks { ///////////////////////////////////////////////////////////////////////////////////// /// class defines a sink which prints the messages to the debugger ///////////////////////////////////////////////////////////////////////////////////// class Debugger : public sink { void log(const details::log_msg &msg) override { OutputDebugString(GMM_PREFIX_STR); OutputDebugString(msg.formatted.str().c_str()); } void flush() { } }; } } #endif ///////////////////////////////////////////////////////////////////////////////////// /// Initializes Gmm Logger /// /// @return true if initialized successfully. false otherwise ///////////////////////////////////////////////////////////////////////////////////// bool GmmLib::Logger::GmmLogInit() { std::string LogFilePath; std::string ProcPath; std::string ProcName; int Pid = 0; // Get logging method #if _WIN32 uint32_t regkeyVal = 0; if(Utility::GmmUMDReadRegistryFullPath(GMM_LOG_REG_KEY_SUB_PATH, GMM_LOG_TO_FILE, ®keyVal)) { LogMethod = regkeyVal ? ToFile : ToOSLog; } if(Utility::GmmUMDReadRegistryFullPath(GMM_LOG_REG_KEY_SUB_PATH, GMM_LOG_LEVEL_REGKEY, ®keyVal)) { switch(static_cast(regkeyVal)) { case Trace: LogLevel = spdlog::level::trace; break; case Info: LogLevel = spdlog::level::info; break; case Error: LogLevel = spdlog::level::err; break; case Critical: LogLevel = spdlog::level::critical; break; case Off: default: LogLevel = spdlog::level::off; break; } } #endif if(LogLevel == spdlog::level::off) { return false; } try { if(LogMethod == ToFile) { // Get process name #if _WIN32 TCHAR ProcPathTChar[MAX_PATH]; GetModuleFileName(NULL, ProcPathTChar, MAX_PATH); ProcPath = std::string(ProcPathTChar); size_t PosOfLastSlash = ProcPath.find_last_of("\\") + 1; size_t PosOfLastDot = ProcPath.find_last_of("."); if(PosOfLastDot <= PosOfLastSlash || PosOfLastDot >= ProcPath.length() || PosOfLastSlash >= ProcPath.length()) { ProcName = GMM_UNKNOWN_PROCESS; } else { ProcName = ProcPath.substr(PosOfLastSlash, PosOfLastDot - PosOfLastSlash); } #else ProcPath = "Unknown_Proc_Path"; ProcName = GMM_UNKNOWN_PROCESS; std::ifstream file; file.open("/proc/self/cmdline"); if(file.is_open()) { // Get process name getline(file, ProcPath); size_t PosOfLastSlash = ProcPath.find_last_of("/") + 1; if(PosOfLastSlash >= ProcPath.length()) { ProcName = GMM_UNKNOWN_PROCESS; } else { // "length-1" to remove null character ProcName = ProcPath.substr(PosOfLastSlash, ProcPath.length() - 1); } file.close(); } #endif // Get process ID #if _WIN32 Pid = _getpid(); #else Pid = getpid(); #endif std::string PidStr = std::to_string(Pid); // TODO: Multiple GmmLib instance can be running in the same process. In that case, the file name will be // the same for two instances. Figure out a way to differentiate between the two instances. #if _WIN32 LogFilePath = std::string("c:\\") + std::string(GMM_LOG_FILENAME) + "_" + ProcName + "_" + PidStr; #else LogFilePath = std::string(".//") + std::string(GMM_LOG_FILENAME) + "" + ProcName + "_" + PidStr; #endif // Create logger SpdLogger = spdlog::rotating_logger_mt(GMM_LOGGER_NAME, LogFilePath, GMM_LOG_FILE_SIZE, GMM_ROTATE_FILE_NUMBER); // Log process path SpdLogger->set_pattern("Process path: %v"); SpdLogger->info(ProcPath.c_str()); } else { #if defined(_WIN32) // Log to debugger auto debugger_sink = std::make_shared(); SpdLogger = std::make_shared(GMM_LOGGER_NAME, debugger_sink); #elif defined(__ANDROID__) // Log to logcat SpdLogger = spdlog::android_logger(GMM_LOGGER_NAME, GMM_LOG_TAG); #elif defined(__linux__) // Log to syslog SpdLogger = spdlog::syslog_logger(GMM_LOGGER_NAME, GMM_LOG_TAG, 1 /*Log Pid*/); #else __GMM_ASSERT(0); return false; #endif } } catch(const spdlog::spdlog_ex &ex) { __GMM_ASSERT(0); return false; } // Set log level SpdLogger->set_level(LogLevel); // Set log pattern SpdLogger->set_pattern("[%T.%e] [Thread %t] [%l] %v"); // [Time] [Thread id] [Log Level] [Text to Log] return true; } ///////////////////////////////////////////////////////////////////////////////////// /// Gmm Logger constructor ///////////////////////////////////////////////////////////////////////////////////// GmmLib::Logger::Logger() : LogMethod(ToOSLog), LogLevel(spdlog::level::off) { if(!GmmLogInit()) { spdlog::set_level(spdlog::level::off); } } ///////////////////////////////////////////////////////////////////////////////////// /// Gmm Logger Destructor ///////////////////////////////////////////////////////////////////////////////////// GmmLib::Logger::~Logger() { if(SpdLogger) { SpdLogger->flush(); } } ///////////////////////////////////////////////////////////////////////////////////// /// Gmm Logger C wrappers ///////////////////////////////////////////////////////////////////////////////////// #if !_WIN32 // Linux/Android replacement for MS version of _vscprintf inline int vscprintf_lin(const char *msg, va_list args) { char c; va_list args_cpy; // Copy `args' to prevent internal pointer modification from vsnprintf va_copy(args_cpy, args); int len = vsnprintf(&c, 1, msg, args_cpy); va_end(args_cpy); return len; } #endif ///////////////////////////////////////////////////////////////////////////////////// /// Gmm Logger C wrapper for GMM_LOG_* Macros ///////////////////////////////////////////////////////////////////////////////////// extern "C" void GMM_STDCALL GmmLibLogging(GmmLogLevel Level, const char *str, ...) { va_list args; if(GmmLoggerPerProc.SpdLogger) { va_start(args, str); #if _WIN32 const size_t length = _vscprintf(str, args); #else const size_t length = vscprintf_lin(str, args); #endif char *temp = new char[length + 1]; if(temp) { #if _WIN32 vsprintf_s(temp, length + 1, str, args); #else vsnprintf(temp, length + 1, str, args); #endif switch(Level) { case Trace: // Set log level to trace if we want trace msges to be printed //GmmLoggerPerProc.SpdLogger->set_level(spdlog::level::trace); GmmLoggerPerProc.SpdLogger->trace(temp); break; case Info: // Set log level to info if we want info msges to be printed //GmmLoggerPerProc.SpdLogger->set_level(spdlog::level::info); GmmLoggerPerProc.SpdLogger->info(temp); break; case Error: GmmLoggerPerProc.SpdLogger->critical(temp); break; default: break; } delete[] temp; } } va_end(args); } #endif //#if GMM_LOG_AVAILABLE gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/Utility/GmmLog/GmmLog.h000066400000000000000000000166651466655022700242510ustar00rootroot00000000000000/*============================================================================== Copyright(c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ============================================================================*/ #pragma once #if (_DEBUG || _RELEASE_INTERNAL) && !__GMM_KMD__ // Not doing #if__cplusplus >= 201103L check because partial C++11 support may // work for this. We also want to catch C++11 unavailability due to not setting // compiler options. #if (_MSC_VER >= 1800) // VS 2013+ #define GMM_LOG_AVAILABLE 1 #elif((__clang_major__ > 3) || ((__clang_major__ == 3) && (__clang_minor__ >= 5))) // clang 3.5+ #define GMM_LOG_AVAILABLE 1 #elif((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 8))) // g++ 4.8+ #define GMM_LOG_AVAILABLE 1 #else #define GMM_LOG_AVAILABLE 0 // Print out messages if GmmLog was disabled due to compiler issues #define STRING2(x) #x #define STRING(x) STRING2(x) #if (defined __GNUC__) #pragma message "Detected g++ " STRING(__GNUC__) "." STRING(__GNUC_MINOR__) ". Minimum compiler version required for GmmLog is GCC 4.8.1. Disabling GmmLog." #elif (defined __clang__) #pragma message "Detected clang " STRING(__clang_major__) "." STRING(__clang_minor__) ". Minimum compiler version required for GmmLog is clang 3.5. Disabling GmmLog." #elif (defined _MSC_VER) #pragma message("Detected MSVC++ version " STRING(_MSC_VER) ". Minimum compiler version required for GmmLog is MSVC++ 1800. Disabling GmmLog") #else #pragma message "Unknown compiler. Disabling GmmLog." #endif #undef STRING2 #undef STRING #endif #elif (_DEBUG || _RELEASE_INTERNAL) && __GMM_KMD__ && _WIN32 #define GMM_KMD_LOG_AVAILABLE 1 ///////////////////////////////////////////////////////////////////////////////////// /// GMM_KMD_LOG /// Gmm logging macro to log a message in KMD mode. Exmaple: /// GMM_KMD_LOG("Math Addition: %d + %d = %d \r\n", 1, 1, 2); ///////////////////////////////////////////////////////////////////////////////////// #define GMM_KMD_LOG(message, ...) \ { \ DWORD CurrentProcessId = (DWORD) (ULONG_PTR)PsGetCurrentProcessId(); \ const WCHAR *format = L"%s%d.txt"; \ WCHAR FileName[] = L"C:\\Intel\\IGfx\\GmmKmd_Proc_"; \ WCHAR FullFileName[KM_FILENAME_LENGTH]; \ \ KmGenerateLogFileName(&FullFileName[0], format, FileName, CurrentProcessId); \ \ KM_FILE_IO_OBJ *pGmmKmdLog = KmFileOpen(pHwDevExt, FullFileName, false, false, true); \ if (pGmmKmdLog != NULL) \ { \ KmFilePrintf(pGmmKmdLog, message, __VA_ARGS__); \ KmFileClose(pGmmKmdLog, false); \ } \ } \ #else // else if Release driver || KMD #define GMM_LOG_AVAILABLE 0 #endif #if GMM_LOG_AVAILABLE typedef enum GmmLogLevel { Off = 0, Trace, Info, Error, // default Critical, }GmmLogLevel; #ifdef __cplusplus #include #define GMM_LOG_FILE_SIZE 1024 * 1024 * 5 // Once log reaches this size, it will start in new file #define GMM_ROTATE_FILE_NUMBER 3 // Once log is full, it'll save old log with .1/.2/.3 in name, and then start with .1 #define GMM_LOG_MASSAGE_MAX_SIZE 1024 #define GMM_LOGGER_NAME "gmm_logger" #define GMM_LOG_FILENAME "gmm_log" #define GMM_LOG_TAG "GmmLib" #define GMM_UNKNOWN_PROCESS "Unknown_Proc" #define GMM_PREFIX_STR "INTC GMM SPD: " #if _WIN32 #define GMM_LOG_REG_KEY_SUB_PATH "SOFTWARE\\Intel\\IGFX\\GMMLOG\\" #define GMM_LOG_TO_FILE "LogToFile" #define GMM_LOG_LEVEL_REGKEY "LogLevel" // GmmLogLevel #endif //#if _WIN32 extern "C" void GmmLibLogging(GmmLogLevel Level, const char* str, ...); #define GMM_LOG_TRACE(message, ...) GmmLibLogging(Trace, message, ##__VA_ARGS__) #define GMM_LOG_TRACE_IF(expression, message, ...) if(expression) { GmmLibLogging(Trace, message, ##__VA_ARGS__);} #define GMM_LOG_INFO(message, ...) GmmLibLogging(Info, message, ##__VA_ARGS__) #define GMM_LOG_INFO_IF(expression, message, ...) if(expression) { GmmLibLogging(Info, message, ##__VA_ARGS__);} #define GMM_LOG_ERROR(message, ...) GmmLibLogging(Error, message, ##__VA_ARGS__) #define GMM_LOG_ERROR_IF(expression, message, ...) if(expression) { GmmLibLogging(Error, message, ##__VA_ARGS__);} #else // else C // Fwd Declarations of C-wrapper functions used for Logging void GmmLibLogging(GmmLogLevel Level, const char* str, ...); #define GMM_LOG_TRACE(message, ...) GmmLibLogging(Trace, message, ##__VA_ARGS__) #define GMM_LOG_TRACE_IF(expression, message, ...) if(expression) { GmmLibLogging(Trace, message, ##__VA_ARGS__);} #define GMM_LOG_INFO(message, ...) GmmLibLogging(Info, message, ##__VA_ARGS__) #define GMM_LOG_INFO_IF(expression, message, ...) if(expression) { GmmLibLogging(Info, message, ##__VA_ARGS__);} #define GMM_LOG_ERROR(message, ...) GmmLibLogging(Error, message, ##__VA_ARGS__) #define GMM_LOG_ERROR_IF(expression, message, ...) if(expression) { GmmLibLogging(Error, message, ##__VA_ARGS__);} #endif //#ifdef __cplusplus #else // else Gmm Log not available #define GMM_LOG_TRACE(message, ...) #define GMM_LOG_TRACE_IF(expression, message, ...) #define GMM_LOG_INFO(message, ...) #define GMM_LOG_INFO_IF(expression, message, ...) #define GMM_LOG_ERROR(message, ...) #define GMM_LOG_ERROR_IF(expression, message, ...) #endif //#if _WIN32 #if GMM_KMD_LOG_AVAILABLE #else #define GMM_KMD_LOG(message, ...) #endif gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/Utility/GmmLog/spdlog/000077500000000000000000000000001466655022700241705ustar00rootroot00000000000000gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/Utility/GmmLog/spdlog/README.md000066400000000000000000000004461466655022700254530ustar00rootroot00000000000000This library has been taken from https://github.com/gabime/spdlog under MIT license. GmmLib is using this library for logging to a file, log to debugger (Windows), log to logcat (Android) and log to syslog (Linux) with format similar to python print() under Debug and Release Internal modes. gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/Utility/GmmLog/spdlog/async_logger.h000066400000000000000000000056021466655022700270200ustar00rootroot00000000000000// // Copyright(c) 2015 Gabi Melman. // Distributed under the MIT License (http://opensource.org/licenses/MIT) // #pragma once // Very fast asynchronous logger (millions of logs per second on an average desktop) // Uses pre allocated lockfree queue for maximum throughput even under large number of threads. // Creates a single back thread to pop messages from the queue and log them. // // Upon each log write the logger: // 1. Checks if its log level is enough to log the message // 2. Push a new copy of the message to a queue (or block the caller until space is available in the queue) // 3. will throw spdlog_ex upon log exceptions // Upon destruction, logs all remaining messages in the queue before destructing.. #include #include #include #include #include #include namespace spdlog { namespace details { class async_log_helper; } class async_logger :public logger { public: template async_logger(const std::string& name, const It& begin, const It& end, size_t queue_size, const async_overflow_policy overflow_policy = async_overflow_policy::block_retry, const std::function& worker_warmup_cb = nullptr, const std::chrono::milliseconds& flush_interval_ms = std::chrono::milliseconds::zero(), const std::function& worker_teardown_cb = nullptr); async_logger(const std::string& logger_name, sinks_init_list sinks, size_t queue_size, const async_overflow_policy overflow_policy = async_overflow_policy::block_retry, const std::function& worker_warmup_cb = nullptr, const std::chrono::milliseconds& flush_interval_ms = std::chrono::milliseconds::zero(), const std::function& worker_teardown_cb = nullptr); async_logger(const std::string& logger_name, sink_ptr single_sink, size_t queue_size, const async_overflow_policy overflow_policy = async_overflow_policy::block_retry, const std::function& worker_warmup_cb = nullptr, const std::chrono::milliseconds& flush_interval_ms = std::chrono::milliseconds::zero(), const std::function& worker_teardown_cb = nullptr); //Wait for the queue to be empty, and flush synchronously //Warning: this can potentialy last forever as we wait it to complete void flush() override; protected: void _sink_it(details::log_msg& msg) override; void _set_formatter(spdlog::formatter_ptr msg_formatter) override; void _set_pattern(const std::string& pattern) override; private: std::unique_ptr _async_log_helper; }; } #include gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/Utility/GmmLog/spdlog/common.h000066400000000000000000000054171466655022700256400ustar00rootroot00000000000000// // Copyright(c) 2015 Gabi Melman. // Distributed under the MIT License (http://opensource.org/licenses/MIT) // #pragma once #include #include #include #include #include #include #include #if defined(_WIN32) && defined(SPDLOG_WCHAR_FILENAMES) #include #include #endif #include //visual studio upto 2013 does not support noexcept nor constexpr #if defined(_MSC_VER) && (_MSC_VER < 1900) #define SPDLOG_NOEXCEPT throw() #define SPDLOG_CONSTEXPR #else #define SPDLOG_NOEXCEPT noexcept #define SPDLOG_CONSTEXPR constexpr #endif #if defined(__GNUC__) || defined(__clang__) #define DEPRECATED __attribute__((deprecated)) #elif defined(_MSC_VER) #define DEPRECATED __declspec(deprecated) #else #define DEPRECATED #endif #include namespace spdlog { class formatter; namespace sinks { class sink; } using log_clock = std::chrono::system_clock; using sink_ptr = std::shared_ptr < sinks::sink >; using sinks_init_list = std::initializer_list < sink_ptr >; using formatter_ptr = std::shared_ptr; #if defined(SPDLOG_NO_ATOMIC_LEVELS) using level_t = details::null_atomic_int; #else using level_t = std::atomic; #endif using log_err_handler = std::function; //Log level enum namespace level { typedef enum { trace = 0, debug = 1, info = 2, warn = 3, err = 4, critical = 5, off = 6 } level_enum; static const char* level_names[] { "trace", "debug", "info", "warning", "error", "critical", "off" }; static const char* short_level_names[] { "T", "D", "I", "W", "E", "C", "O" }; inline const char* to_str(spdlog::level::level_enum l) { return level_names[l]; } inline const char* to_short_str(spdlog::level::level_enum l) { return short_level_names[l]; } } //level // // Async overflow policy - block by default. // enum class async_overflow_policy { block_retry, // Block / yield / sleep until message can be enqueued discard_log_msg // Discard the message it enqueue fails }; // // Log exception // namespace details { namespace os { std::string errno_str(int err_num); } } class spdlog_ex: public std::exception { public: spdlog_ex(const std::string& msg):_msg(msg) {} spdlog_ex(const std::string& msg, int last_errno) { _msg = msg + ": " + details::os::errno_str(last_errno); } const char* what() const SPDLOG_NOEXCEPT override { return _msg.c_str(); } private: std::string _msg; }; // // wchar support for windows file names (SPDLOG_WCHAR_FILENAMES must be defined) // #if defined(_WIN32) && defined(SPDLOG_WCHAR_FILENAMES) using filename_t = std::wstring; #else using filename_t = std::string; #endif } //spdlog gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/Utility/GmmLog/spdlog/details/000077500000000000000000000000001466655022700256155ustar00rootroot00000000000000gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/Utility/GmmLog/spdlog/details/async_log_helper.h000066400000000000000000000254341466655022700313130ustar00rootroot00000000000000// // Copyright(c) 2015 Gabi Melman. // Distributed under the MIT License (http://opensource.org/licenses/MIT) // // async log helper : // Process logs asynchronously using a back thread. // // If the internal queue of log messages reaches its max size, // then the client call will block until there is more room. // // If the back thread throws during logging, a spdlog::spdlog_ex exception // will be thrown in client's thread when tries to log the next message #pragma once #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace spdlog { namespace details { class async_log_helper { // Async msg to move to/from the queue // Movable only. should never be copied enum class async_msg_type { log, flush, terminate }; struct async_msg { std::string logger_name; level::level_enum level; log_clock::time_point time; size_t thread_id; std::string txt; async_msg_type msg_type; async_msg() = default; ~async_msg() = default; async_msg(async_msg&& other) SPDLOG_NOEXCEPT: logger_name(std::move(other.logger_name)), level(std::move(other.level)), time(std::move(other.time)), txt(std::move(other.txt)), msg_type(std::move(other.msg_type)) {} async_msg(async_msg_type m_type) :msg_type(m_type) {} async_msg& operator=(async_msg&& other) SPDLOG_NOEXCEPT { logger_name = std::move(other.logger_name); level = other.level; time = std::move(other.time); thread_id = other.thread_id; txt = std::move(other.txt); msg_type = other.msg_type; return *this; } // never copy or assign. should only be moved.. async_msg(const async_msg&) = delete; async_msg& operator=(async_msg& other) = delete; // construct from log_msg async_msg(const details::log_msg& m) : level(m.level), time(m.time), thread_id(m.thread_id), txt(m.raw.data(), m.raw.size()), msg_type(async_msg_type::log) { #ifndef SPDLOG_NO_NAME logger_name = *m.logger_name; #endif } // copy into log_msg void fill_log_msg(log_msg &msg) { msg.logger_name = &logger_name; msg.level = level; msg.time = time; msg.thread_id = thread_id; msg.raw << txt; } }; public: using item_type = async_msg; using q_type = details::mpmc_bounded_queue; using clock = std::chrono::steady_clock; async_log_helper(formatter_ptr formatter, const std::vector& sinks, size_t queue_size, const log_err_handler err_handler, const async_overflow_policy overflow_policy = async_overflow_policy::block_retry, const std::function& worker_warmup_cb = nullptr, const std::chrono::milliseconds& flush_interval_ms = std::chrono::milliseconds::zero(), const std::function& worker_teardown_cb = nullptr); void log(const details::log_msg& msg); // stop logging and join the back thread ~async_log_helper(); void set_formatter(formatter_ptr); void flush(bool wait_for_q); private: formatter_ptr _formatter; std::vector> _sinks; // queue of messages to log q_type _q; log_err_handler _err_handler; bool _flush_requested; bool _terminate_requested; // overflow policy const async_overflow_policy _overflow_policy; // worker thread warmup callback - one can set thread priority, affinity, etc const std::function _worker_warmup_cb; // auto periodic sink flush parameter const std::chrono::milliseconds _flush_interval_ms; // worker thread teardown callback const std::function _worker_teardown_cb; // worker thread std::thread _worker_thread; void push_msg(async_msg&& new_msg); // worker thread main loop void worker_loop(); // pop next message from the queue and process it. will set the last_pop to the pop time // return false if termination of the queue is required bool process_next_msg(log_clock::time_point& last_pop, log_clock::time_point& last_flush); void handle_flush_interval(log_clock::time_point& now, log_clock::time_point& last_flush); // sleep,yield or return immediatly using the time passed since last message as a hint static void sleep_or_yield(const spdlog::log_clock::time_point& now, const log_clock::time_point& last_op_time); // wait until the queue is empty void wait_empty_q(); }; } } /////////////////////////////////////////////////////////////////////////////// // async_sink class implementation /////////////////////////////////////////////////////////////////////////////// inline spdlog::details::async_log_helper::async_log_helper( formatter_ptr formatter, const std::vector& sinks, size_t queue_size, log_err_handler err_handler, const async_overflow_policy overflow_policy, const std::function& worker_warmup_cb, const std::chrono::milliseconds& flush_interval_ms, const std::function& worker_teardown_cb): _formatter(formatter), _sinks(sinks), _q(queue_size), _err_handler(err_handler), _flush_requested(false), _terminate_requested(false), _overflow_policy(overflow_policy), _worker_warmup_cb(worker_warmup_cb), _flush_interval_ms(flush_interval_ms), _worker_teardown_cb(worker_teardown_cb), _worker_thread(&async_log_helper::worker_loop, this) {} // Send to the worker thread termination message(level=off) // and wait for it to finish gracefully inline spdlog::details::async_log_helper::~async_log_helper() { try { push_msg(async_msg(async_msg_type::terminate)); _worker_thread.join(); } catch (...) // don't crash in destructor {} } //Try to push and block until succeeded (if the policy is not to discard when the queue is full) inline void spdlog::details::async_log_helper::log(const details::log_msg& msg) { push_msg(async_msg(msg)); } inline void spdlog::details::async_log_helper::push_msg(details::async_log_helper::async_msg&& new_msg) { if (!_q.enqueue(std::move(new_msg)) && _overflow_policy != async_overflow_policy::discard_log_msg) { auto last_op_time = details::os::now(); auto now = last_op_time; do { now = details::os::now(); sleep_or_yield(now, last_op_time); } while (!_q.enqueue(std::move(new_msg))); } } // optionally wait for the queue be empty and request flush from the sinks inline void spdlog::details::async_log_helper::flush(bool wait_for_q) { push_msg(async_msg(async_msg_type::flush)); if(wait_for_q) wait_empty_q(); //return only make after the above flush message was processed } inline void spdlog::details::async_log_helper::worker_loop() { try { if (_worker_warmup_cb) _worker_warmup_cb(); auto last_pop = details::os::now(); auto last_flush = last_pop; while(process_next_msg(last_pop, last_flush)); if (_worker_teardown_cb) _worker_teardown_cb(); } catch (const std::exception &ex) { _err_handler(ex.what()); } catch (...) { _err_handler("Unknown exception"); } } // process next message in the queue // return true if this thread should still be active (while no terminate msg was received) inline bool spdlog::details::async_log_helper::process_next_msg(log_clock::time_point& last_pop, log_clock::time_point& last_flush) { async_msg incoming_async_msg; if (_q.dequeue(incoming_async_msg)) { last_pop = details::os::now(); switch (incoming_async_msg.msg_type) { case async_msg_type::flush: _flush_requested = true; break; case async_msg_type::terminate: _flush_requested = true; _terminate_requested = true; break; default: log_msg incoming_log_msg; incoming_async_msg.fill_log_msg(incoming_log_msg); _formatter->format(incoming_log_msg); for (auto &s : _sinks) { if(s->should_log( incoming_log_msg.level)) { s->log(incoming_log_msg); } } } return true; } // Handle empty queue.. // This is the only place where the queue can terminate or flush to avoid losing messages already in the queue else { auto now = details::os::now(); handle_flush_interval(now, last_flush); sleep_or_yield(now, last_pop); return !_terminate_requested; } } // flush all sinks if _flush_interval_ms has expired inline void spdlog::details::async_log_helper::handle_flush_interval(log_clock::time_point& now, log_clock::time_point& last_flush) { auto should_flush = _flush_requested || (_flush_interval_ms != std::chrono::milliseconds::zero() && now - last_flush >= _flush_interval_ms); if (should_flush) { for (auto &s : _sinks) s->flush(); now = last_flush = details::os::now(); _flush_requested = false; } } inline void spdlog::details::async_log_helper::set_formatter(formatter_ptr msg_formatter) { _formatter = msg_formatter; } // spin, yield or sleep. use the time passed since last message as a hint inline void spdlog::details::async_log_helper::sleep_or_yield(const spdlog::log_clock::time_point& now, const spdlog::log_clock::time_point& last_op_time) { using namespace std::this_thread; using std::chrono::milliseconds; using std::chrono::microseconds; auto time_since_op = now - last_op_time; // spin upto 50 micros if (time_since_op <= microseconds(50)) return; // yield upto 150 micros if (time_since_op <= microseconds(100)) return yield(); // sleep for 20 ms upto 200 ms if (time_since_op <= milliseconds(200)) return sleep_for(milliseconds(20)); // sleep for 200 ms return sleep_for(milliseconds(200)); } // wait for the queue to be empty inline void spdlog::details::async_log_helper::wait_empty_q() { auto last_op = details::os::now(); while (_q.approx_size() > 0) { sleep_or_yield(details::os::now(), last_op); } } gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/Utility/GmmLog/spdlog/details/async_logger_impl.h000066400000000000000000000054561466655022700314750ustar00rootroot00000000000000// // Copyright(c) 2015 Gabi Melman. // Distributed under the MIT License (http://opensource.org/licenses/MIT) // #pragma once // Async Logger implementation // Use an async_sink (queue per logger) to perform the logging in a worker thread #include #include #include #include #include #include template inline spdlog::async_logger::async_logger(const std::string& logger_name, const It& begin, const It& end, size_t queue_size, const async_overflow_policy overflow_policy, const std::function& worker_warmup_cb, const std::chrono::milliseconds& flush_interval_ms, const std::function& worker_teardown_cb) : logger(logger_name, begin, end), _async_log_helper(new details::async_log_helper(_formatter, _sinks, queue_size, _err_handler, overflow_policy, worker_warmup_cb, flush_interval_ms, worker_teardown_cb)) { } inline spdlog::async_logger::async_logger(const std::string& logger_name, sinks_init_list sinks_list, size_t queue_size, const async_overflow_policy overflow_policy, const std::function& worker_warmup_cb, const std::chrono::milliseconds& flush_interval_ms, const std::function& worker_teardown_cb) : async_logger(logger_name, sinks_list.begin(), sinks_list.end(), queue_size, overflow_policy, worker_warmup_cb, flush_interval_ms, worker_teardown_cb) {} inline spdlog::async_logger::async_logger(const std::string& logger_name, sink_ptr single_sink, size_t queue_size, const async_overflow_policy overflow_policy, const std::function& worker_warmup_cb, const std::chrono::milliseconds& flush_interval_ms, const std::function& worker_teardown_cb) : async_logger(logger_name, { single_sink }, queue_size, overflow_policy, worker_warmup_cb, flush_interval_ms, worker_teardown_cb) {} inline void spdlog::async_logger::flush() { _async_log_helper->flush(true); } inline void spdlog::async_logger::_set_formatter(spdlog::formatter_ptr msg_formatter) { _formatter = msg_formatter; _async_log_helper->set_formatter(_formatter); } inline void spdlog::async_logger::_set_pattern(const std::string& pattern) { _formatter = std::make_shared(pattern); _async_log_helper->set_formatter(_formatter); } inline void spdlog::async_logger::_sink_it(details::log_msg& msg) { try { _async_log_helper->log(msg); if (_should_flush_on(msg)) _async_log_helper->flush(false); // do async flush } catch (const std::exception &ex) { _err_handler(ex.what()); } catch (...) { _err_handler("Unknown exception"); } } gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/Utility/GmmLog/spdlog/details/file_helper.h000066400000000000000000000046521466655022700302530ustar00rootroot00000000000000// // Copyright(c) 2015 Gabi Melman. // Distributed under the MIT License (http://opensource.org/licenses/MIT) // #pragma once // Helper class for file sink // When failing to open a file, retry several times(5) with small delay between the tries(10 ms) // Can be set to auto flush on every line // Throw spdlog_ex exception on errors #include #include #include #include #include #include #include namespace spdlog { namespace details { class file_helper { public: const int open_tries = 5; const int open_interval = 10; explicit file_helper() : _fd(nullptr) {} file_helper(const file_helper&) = delete; file_helper& operator=(const file_helper&) = delete; ~file_helper() { close(); } void open(const filename_t& fname, bool truncate = false) { close(); auto *mode = truncate ? SPDLOG_FILENAME_T("wb") : SPDLOG_FILENAME_T("ab"); _filename = fname; for (int tries = 0; tries < open_tries; ++tries) { if (!os::fopen_s(&_fd, fname, mode)) return; std::this_thread::sleep_for(std::chrono::milliseconds(open_interval)); } throw spdlog_ex("Failed opening file " + os::filename_to_str(_filename) + " for writing", errno); } void reopen(bool truncate) { if (_filename.empty()) throw spdlog_ex("Failed re opening file - was not opened before"); open(_filename, truncate); } void flush() { std::fflush(_fd); } void close() { if (_fd) { std::fclose(_fd); _fd = nullptr; } } void write(const log_msg& msg) { size_t msg_size = msg.formatted.size(); auto data = msg.formatted.data(); if (std::fwrite(data, 1, msg_size, _fd) != msg_size) throw spdlog_ex("Failed writing to file " + os::filename_to_str(_filename), errno); } size_t size() { if (!_fd) throw spdlog_ex("Cannot use size() on closed file " + os::filename_to_str(_filename)); return os::filesize(_fd); } const filename_t& filename() const { return _filename; } static bool file_exists(const filename_t& name) { return os::file_exists(name); } private: FILE* _fd; filename_t _filename; }; } } gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/Utility/GmmLog/spdlog/details/format.cc000066400000000000000000000702661466655022700274270ustar00rootroot00000000000000/* Formatting library for C++ Copyright (c) 2012 - 2015, Victor Zverovich All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "format.h" #include #include #include #include #include #include #include // for std::ptrdiff_t #if defined(_WIN32) && defined(__MINGW32__) # include #endif #if FMT_USE_WINDOWS_H # if defined(NOMINMAX) || defined(FMT_WIN_MINMAX) # include # else # define NOMINMAX # include # undef NOMINMAX # endif #endif using fmt::internal::Arg; #if FMT_EXCEPTIONS # define FMT_TRY try # define FMT_CATCH(x) catch (x) #else # define FMT_TRY if (true) # define FMT_CATCH(x) if (false) #endif #ifdef FMT_HEADER_ONLY # define FMT_FUNC inline #else # define FMT_FUNC #endif #ifdef _MSC_VER # pragma warning(push) # pragma warning(disable: 4127) // conditional expression is constant # pragma warning(disable: 4702) // unreachable code // Disable deprecation warning for strerror. The latter is not called but // MSVC fails to detect it. # pragma warning(disable: 4996) #endif // Dummy implementations of strerror_r and strerror_s called if corresponding // system functions are not available. static inline fmt::internal::Null<> strerror_r(int, char *, ...) { return fmt::internal::Null<>(); } static inline fmt::internal::Null<> strerror_s(char *, std::size_t, ...) { return fmt::internal::Null<>(); } namespace fmt { namespace { #ifndef _MSC_VER # define FMT_SNPRINTF snprintf #else // _MSC_VER inline int fmt_snprintf(char *buffer, size_t size, const char *format, ...) { va_list args; va_start(args, format); int result = vsnprintf_s(buffer, size, _TRUNCATE, format, args); va_end(args); return result; } # define FMT_SNPRINTF fmt_snprintf #endif // _MSC_VER #if defined(_WIN32) && defined(__MINGW32__) && !defined(__NO_ISOCEXT) # define FMT_SWPRINTF snwprintf #else # define FMT_SWPRINTF swprintf #endif // defined(_WIN32) && defined(__MINGW32__) && !defined(__NO_ISOCEXT) // Checks if a value fits in int - used to avoid warnings about comparing // signed and unsigned integers. template struct IntChecker { template static bool fits_in_int(T value) { unsigned max = INT_MAX; return value <= max; } static bool fits_in_int(bool) { return true; } }; template <> struct IntChecker { template static bool fits_in_int(T value) { return value >= INT_MIN && value <= INT_MAX; } static bool fits_in_int(int) { return true; } }; const char RESET_COLOR[] = "\x1b[0m"; typedef void(*FormatFunc)(fmt::Writer &, int, fmt::StringRef); // Portable thread-safe version of strerror. // Sets buffer to point to a string describing the error code. // This can be either a pointer to a string stored in buffer, // or a pointer to some static immutable string. // Returns one of the following values: // 0 - success // ERANGE - buffer is not large enough to store the error message // other - failure // Buffer should be at least of size 1. int safe_strerror( int error_code, char *&buffer, std::size_t buffer_size) FMT_NOEXCEPT { FMT_ASSERT(buffer != 0 && buffer_size != 0, "invalid buffer"); class StrError { private: int error_code_; char *&buffer_; std::size_t buffer_size_; // A noop assignment operator to avoid bogus warnings. void operator=(const StrError &) {} // Handle the result of XSI-compliant version of strerror_r. int handle(int result) { // glibc versions before 2.13 return result in errno. return result == -1 ? errno : result; } // Handle the result of GNU-specific version of strerror_r. int handle(char *message) { // If the buffer is full then the message is probably truncated. if (message == buffer_ && strlen(buffer_) == buffer_size_ - 1) return ERANGE; buffer_ = message; return 0; } // Handle the case when strerror_r is not available. int handle(fmt::internal::Null<>) { return fallback(strerror_s(buffer_, buffer_size_, error_code_)); } // Fallback to strerror_s when strerror_r is not available. int fallback(int result) { // If the buffer is full then the message is probably truncated. return result == 0 && strlen(buffer_) == buffer_size_ - 1 ? ERANGE : result; } // Fallback to strerror if strerror_r and strerror_s are not available. int fallback(fmt::internal::Null<>) { errno = 0; buffer_ = strerror(error_code_); return errno; } public: StrError(int err_code, char *&buf, std::size_t buf_size) : error_code_(err_code), buffer_(buf), buffer_size_(buf_size) {} int run() { strerror_r(0, 0, ""); // Suppress a warning about unused strerror_r. return handle(strerror_r(error_code_, buffer_, buffer_size_)); } }; return StrError(error_code, buffer, buffer_size).run(); } void format_error_code(fmt::Writer &out, int error_code, fmt::StringRef message) FMT_NOEXCEPT { // Report error code making sure that the output fits into // INLINE_BUFFER_SIZE to avoid dynamic memory allocation and potential // bad_alloc. out.clear(); static const char SEP[] = ": "; static const char ERROR_STR[] = "error "; // Subtract 2 to account for terminating null characters in SEP and ERROR_STR. std::size_t error_code_size = sizeof(SEP) + sizeof(ERROR_STR) - 2; typedef fmt::internal::IntTraits::MainType MainType; MainType abs_value = static_cast(error_code); if (internal::is_negative(error_code)) { abs_value = 0 - abs_value; ++error_code_size; } error_code_size += fmt::internal::count_digits(abs_value); if (message.size() <= fmt::internal::INLINE_BUFFER_SIZE - error_code_size) out << message << SEP; out << ERROR_STR << error_code; assert(out.size() <= fmt::internal::INLINE_BUFFER_SIZE); } void report_error(FormatFunc func, int error_code, fmt::StringRef message) FMT_NOEXCEPT { fmt::MemoryWriter full_message; func(full_message, error_code, message); // Use Writer::data instead of Writer::c_str to avoid potential memory // allocation. std::fwrite(full_message.data(), full_message.size(), 1, stderr); std::fputc('\n', stderr); } // IsZeroInt::visit(arg) returns true iff arg is a zero integer. class IsZeroInt: public fmt::internal::ArgVisitor { public: template bool visit_any_int(T value) { return value == 0; } }; // Checks if an argument is a valid printf width specifier and sets // left alignment if it is negative. class WidthHandler: public fmt::internal::ArgVisitor { private: fmt::FormatSpec &spec_; FMT_DISALLOW_COPY_AND_ASSIGN(WidthHandler); public: explicit WidthHandler(fmt::FormatSpec &spec): spec_(spec) {} void report_unhandled_arg() { FMT_THROW(fmt::FormatError("width is not integer")); } template unsigned visit_any_int(T value) { typedef typename fmt::internal::IntTraits::MainType UnsignedType; UnsignedType width = static_cast(value); if (fmt::internal::is_negative(value)) { spec_.align_ = fmt::ALIGN_LEFT; width = 0 - width; } if (width > INT_MAX) FMT_THROW(fmt::FormatError("number is too big")); return static_cast(width); } }; class PrecisionHandler: public fmt::internal::ArgVisitor { public: void report_unhandled_arg() { FMT_THROW(fmt::FormatError("precision is not integer")); } template int visit_any_int(T value) { if (!IntChecker::is_signed>::fits_in_int(value)) FMT_THROW(fmt::FormatError("number is too big")); return static_cast(value); } }; template struct is_same { enum { value = 0 }; }; template struct is_same { enum { value = 1 }; }; // An argument visitor that converts an integer argument to T for printf, // if T is an integral type. If T is void, the argument is converted to // corresponding signed or unsigned type depending on the type specifier: // 'd' and 'i' - signed, other - unsigned) template class ArgConverter: public fmt::internal::ArgVisitor, void> { private: fmt::internal::Arg &arg_; wchar_t type_; FMT_DISALLOW_COPY_AND_ASSIGN(ArgConverter); public: ArgConverter(fmt::internal::Arg &arg, wchar_t type) : arg_(arg), type_(type) {} void visit_bool(bool value) { if (type_ != 's') visit_any_int(value); } template void visit_any_int(U value) { bool is_signed = type_ == 'd' || type_ == 'i'; using fmt::internal::Arg; typedef typename fmt::internal::Conditional< is_same::value, U, T>::type TargetType; if (sizeof(TargetType) <= sizeof(int)) { // Extra casts are used to silence warnings. if (is_signed) { arg_.type = Arg::INT; arg_.int_value = static_cast(static_cast(value)); } else { arg_.type = Arg::UINT; typedef typename fmt::internal::MakeUnsigned::Type Unsigned; arg_.uint_value = static_cast(static_cast(value)); } } else { if (is_signed) { arg_.type = Arg::LONG_LONG; // glibc's printf doesn't sign extend arguments of smaller types: // std::printf("%lld", -42); // prints "4294967254" // but we don't have to do the same because it's a UB. arg_.long_long_value = static_cast(value); } else { arg_.type = Arg::ULONG_LONG; arg_.ulong_long_value = static_cast::Type>(value); } } } }; // Converts an integer argument to char for printf. class CharConverter: public fmt::internal::ArgVisitor { private: fmt::internal::Arg &arg_; FMT_DISALLOW_COPY_AND_ASSIGN(CharConverter); public: explicit CharConverter(fmt::internal::Arg &arg): arg_(arg) {} template void visit_any_int(T value) { arg_.type = Arg::CHAR; arg_.int_value = static_cast(value); } }; // Write the content of w to os. void write(std::ostream &os, fmt::Writer &w) { const char *data = w.data(); typedef internal::MakeUnsigned::Type UnsignedStreamSize; UnsignedStreamSize size = w.size(); UnsignedStreamSize max_size = internal::to_unsigned((std::numeric_limits::max)()); do { UnsignedStreamSize n = size <= max_size ? size : max_size; os.write(data, static_cast(n)); data += n; size -= n; } while (size != 0); } } // namespace namespace internal { template class PrintfArgFormatter: public ArgFormatterBase, Char> { void write_null_pointer() { this->spec().type_ = 0; this->write("(nil)"); } typedef ArgFormatterBase, Char> Base; public: PrintfArgFormatter(BasicWriter &w, FormatSpec &s) : ArgFormatterBase, Char>(w, s) {} void visit_bool(bool value) { FormatSpec &fmt_spec = this->spec(); if (fmt_spec.type_ != 's') return this->visit_any_int(value); fmt_spec.type_ = 0; this->write(value); } void visit_char(int value) { const FormatSpec &fmt_spec = this->spec(); BasicWriter &w = this->writer(); if (fmt_spec.type_ && fmt_spec.type_ != 'c') w.write_int(value, fmt_spec); typedef typename BasicWriter::CharPtr CharPtr; CharPtr out = CharPtr(); if (fmt_spec.width_ > 1) { Char fill = ' '; out = w.grow_buffer(fmt_spec.width_); if (fmt_spec.align_ != ALIGN_LEFT) { std::fill_n(out, fmt_spec.width_ - 1, fill); out += fmt_spec.width_ - 1; } else { std::fill_n(out + 1, fmt_spec.width_ - 1, fill); } } else { out = w.grow_buffer(1); } *out = static_cast(value); } void visit_cstring(const char *value) { if (value) Base::visit_cstring(value); else if (this->spec().type_ == 'p') write_null_pointer(); else this->write("(null)"); } void visit_pointer(const void *value) { if (value) return Base::visit_pointer(value); this->spec().type_ = 0; write_null_pointer(); } void visit_custom(Arg::CustomValue c) { BasicFormatter formatter(ArgList(), this->writer()); const Char format_str[] = { '}', 0 }; const Char *format = format_str; c.format(&formatter, c.value, &format); } }; } // namespace internal } // namespace fmt FMT_FUNC void fmt::SystemError::init( int err_code, CStringRef format_str, ArgList args) { error_code_ = err_code; MemoryWriter w; internal::format_system_error(w, err_code, format(format_str, args)); std::runtime_error &base = *this; base = std::runtime_error(w.str()); } template int fmt::internal::CharTraits::format_float( char *buffer, std::size_t size, const char *format, unsigned width, int precision, T value) { if (width == 0) { return precision < 0 ? FMT_SNPRINTF(buffer, size, format, value) : FMT_SNPRINTF(buffer, size, format, precision, value); } return precision < 0 ? FMT_SNPRINTF(buffer, size, format, width, value) : FMT_SNPRINTF(buffer, size, format, width, precision, value); } template int fmt::internal::CharTraits::format_float( wchar_t *buffer, std::size_t size, const wchar_t *format, unsigned width, int precision, T value) { if (width == 0) { return precision < 0 ? FMT_SWPRINTF(buffer, size, format, value) : FMT_SWPRINTF(buffer, size, format, precision, value); } return precision < 0 ? FMT_SWPRINTF(buffer, size, format, width, value) : FMT_SWPRINTF(buffer, size, format, width, precision, value); } template const char fmt::internal::BasicData::DIGITS[] = "0001020304050607080910111213141516171819" "2021222324252627282930313233343536373839" "4041424344454647484950515253545556575859" "6061626364656667686970717273747576777879" "8081828384858687888990919293949596979899"; #define FMT_POWERS_OF_10(factor) \ factor * 10, \ factor * 100, \ factor * 1000, \ factor * 10000, \ factor * 100000, \ factor * 1000000, \ factor * 10000000, \ factor * 100000000, \ factor * 1000000000 template const uint32_t fmt::internal::BasicData::POWERS_OF_10_32[] = { 0, FMT_POWERS_OF_10(1) }; template const uint64_t fmt::internal::BasicData::POWERS_OF_10_64[] = { 0, FMT_POWERS_OF_10(1), FMT_POWERS_OF_10(fmt::ULongLong(1000000000)), // Multiply several constants instead of using a single long long constant // to avoid warnings about C++98 not supporting long long. fmt::ULongLong(1000000000) * fmt::ULongLong(1000000000) * 10 }; FMT_FUNC void fmt::internal::report_unknown_type(char code, const char *type) { (void)type; if (std::isprint(static_cast(code))) { FMT_THROW(fmt::FormatError( fmt::format("unknown format code '{}' for {}", code, type))); } FMT_THROW(fmt::FormatError( fmt::format("unknown format code '\\x{:02x}' for {}", static_cast(code), type))); } #if FMT_USE_WINDOWS_H FMT_FUNC fmt::internal::UTF8ToUTF16::UTF8ToUTF16(fmt::StringRef s) { static const char ERROR_MSG[] = "cannot convert string from UTF-8 to UTF-16"; if (s.size() > INT_MAX) FMT_THROW(WindowsError(ERROR_INVALID_PARAMETER, ERROR_MSG)); int s_size = static_cast(s.size()); int length = MultiByteToWideChar( CP_UTF8, MB_ERR_INVALID_CHARS, s.data(), s_size, 0, 0); if (length == 0) FMT_THROW(WindowsError(GetLastError(), ERROR_MSG)); buffer_.resize(length + 1); length = MultiByteToWideChar( CP_UTF8, MB_ERR_INVALID_CHARS, s.data(), s_size, &buffer_[0], length); if (length == 0) FMT_THROW(WindowsError(GetLastError(), ERROR_MSG)); buffer_[length] = 0; } FMT_FUNC fmt::internal::UTF16ToUTF8::UTF16ToUTF8(fmt::WStringRef s) { if (int error_code = convert(s)) { FMT_THROW(WindowsError(error_code, "cannot convert string from UTF-16 to UTF-8")); } } FMT_FUNC int fmt::internal::UTF16ToUTF8::convert(fmt::WStringRef s) { if (s.size() > INT_MAX) return ERROR_INVALID_PARAMETER; int s_size = static_cast(s.size()); int length = WideCharToMultiByte(CP_UTF8, 0, s.data(), s_size, 0, 0, 0, 0); if (length == 0) return GetLastError(); buffer_.resize(length + 1); length = WideCharToMultiByte( CP_UTF8, 0, s.data(), s_size, &buffer_[0], length, 0, 0); if (length == 0) return GetLastError(); buffer_[length] = 0; return 0; } FMT_FUNC void fmt::WindowsError::init( int err_code, CStringRef format_str, ArgList args) { error_code_ = err_code; MemoryWriter w; internal::format_windows_error(w, err_code, format(format_str, args)); std::runtime_error &base = *this; base = std::runtime_error(w.str()); } FMT_FUNC void fmt::internal::format_windows_error( fmt::Writer &out, int error_code, fmt::StringRef message) FMT_NOEXCEPT { FMT_TRY{ MemoryBuffer buffer; buffer.resize(INLINE_BUFFER_SIZE); for (;;) { wchar_t *system_message = &buffer[0]; int result = FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, 0, error_code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), system_message, static_cast(buffer.size()), 0); if (result != 0) { UTF16ToUTF8 utf8_message; if (utf8_message.convert(system_message) == ERROR_SUCCESS) { out << message << ": " << utf8_message; return; } break; } if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) break; // Can't get error message, report error code instead. buffer.resize(buffer.size() * 2); } } FMT_CATCH(...) {} fmt::format_error_code(out, error_code, message); // 'fmt::' is for bcc32. } #endif // FMT_USE_WINDOWS_H FMT_FUNC void fmt::internal::format_system_error( fmt::Writer &out, int error_code, fmt::StringRef message) FMT_NOEXCEPT { FMT_TRY{ MemoryBuffer buffer; buffer.resize(INLINE_BUFFER_SIZE); for (;;) { char *system_message = &buffer[0]; int result = safe_strerror(error_code, system_message, buffer.size()); if (result == 0) { out << message << ": " << system_message; return; } if (result != ERANGE) break; // Can't get error message, report error code instead. buffer.resize(buffer.size() * 2); } } FMT_CATCH(...) {} fmt::format_error_code(out, error_code, message); // 'fmt::' is for bcc32. } template void fmt::internal::ArgMap::init(const ArgList &args) { if (!map_.empty()) return; typedef internal::NamedArg NamedArg; const NamedArg *named_arg = 0; bool use_values = args.type(ArgList::MAX_PACKED_ARGS - 1) == internal::Arg::NONE; if (use_values) { for (unsigned i = 0;/*nothing*/; ++i) { internal::Arg::Type arg_type = args.type(i); switch (arg_type) { case internal::Arg::NONE: return; case internal::Arg::NAMED_ARG: named_arg = static_cast(args.values_[i].pointer); map_.push_back(Pair(named_arg->name, *named_arg)); break; default: /*nothing*/; } } return; } for (unsigned i = 0; i != ArgList::MAX_PACKED_ARGS; ++i) { internal::Arg::Type arg_type = args.type(i); if (arg_type == internal::Arg::NAMED_ARG) { named_arg = static_cast(args.args_[i].pointer); map_.push_back(Pair(named_arg->name, *named_arg)); } } for (unsigned i = ArgList::MAX_PACKED_ARGS;/*nothing*/; ++i) { switch (args.args_[i].type) { case internal::Arg::NONE: return; case internal::Arg::NAMED_ARG: named_arg = static_cast(args.args_[i].pointer); map_.push_back(Pair(named_arg->name, *named_arg)); break; default: /*nothing*/; } } } template void fmt::internal::FixedBuffer::grow(std::size_t) { FMT_THROW(std::runtime_error("buffer overflow")); } FMT_FUNC Arg fmt::internal::FormatterBase::do_get_arg( unsigned arg_index, const char *&error) { Arg arg = args_[arg_index]; switch (arg.type) { case Arg::NONE: error = "argument index out of range"; break; case Arg::NAMED_ARG: arg = *static_cast(arg.pointer); break; default: /*nothing*/; } return arg; } template void fmt::internal::PrintfFormatter::parse_flags( FormatSpec &spec, const Char *&s) { for (;;) { switch (*s++) { case '-': spec.align_ = ALIGN_LEFT; break; case '+': spec.flags_ |= SIGN_FLAG | PLUS_FLAG; break; case '0': spec.fill_ = '0'; break; case ' ': spec.flags_ |= SIGN_FLAG; break; case '#': spec.flags_ |= HASH_FLAG; break; default: --s; return; } } } template Arg fmt::internal::PrintfFormatter::get_arg( const Char *s, unsigned arg_index) { (void)s; const char *error = 0; Arg arg = arg_index == UINT_MAX ? next_arg(error) : FormatterBase::get_arg(arg_index - 1, error); if (error) FMT_THROW(FormatError(!*s ? "invalid format string" : error)); return arg; } template unsigned fmt::internal::PrintfFormatter::parse_header( const Char *&s, FormatSpec &spec) { unsigned arg_index = UINT_MAX; Char c = *s; if (c >= '0' && c <= '9') { // Parse an argument index (if followed by '$') or a width possibly // preceded with '0' flag(s). unsigned value = parse_nonnegative_int(s); if (*s == '$') { // value is an argument index ++s; arg_index = value; } else { if (c == '0') spec.fill_ = '0'; if (value != 0) { // Nonzero value means that we parsed width and don't need to // parse it or flags again, so return now. spec.width_ = value; return arg_index; } } } parse_flags(spec, s); // Parse width. if (*s >= '0' && *s <= '9') { spec.width_ = parse_nonnegative_int(s); } else if (*s == '*') { ++s; spec.width_ = WidthHandler(spec).visit(get_arg(s)); } return arg_index; } template void fmt::internal::PrintfFormatter::format( BasicWriter &writer, BasicCStringRef format_str) { const Char *start = format_str.c_str(); const Char *s = start; while (*s) { Char c = *s++; if (c != '%') continue; if (*s == c) { write(writer, start, s); start = ++s; continue; } write(writer, start, s - 1); FormatSpec spec; spec.align_ = ALIGN_RIGHT; // Parse argument index, flags and width. unsigned arg_index = parse_header(s, spec); // Parse precision. if (*s == '.') { ++s; if ('0' <= *s && *s <= '9') { spec.precision_ = static_cast(parse_nonnegative_int(s)); } else if (*s == '*') { ++s; spec.precision_ = PrecisionHandler().visit(get_arg(s)); } } Arg arg = get_arg(s, arg_index); if (spec.flag(HASH_FLAG) && IsZeroInt().visit(arg)) spec.flags_ &= ~to_unsigned(HASH_FLAG); if (spec.fill_ == '0') { if (arg.type <= Arg::LAST_NUMERIC_TYPE) spec.align_ = ALIGN_NUMERIC; else spec.fill_ = ' '; // Ignore '0' flag for non-numeric types. } // Parse length and convert the argument to the required type. switch (*s++) { case 'h': if (*s == 'h') ArgConverter(arg, *++s).visit(arg); else ArgConverter(arg, *s).visit(arg); break; case 'l': if (*s == 'l') ArgConverter(arg, *++s).visit(arg); else ArgConverter(arg, *s).visit(arg); break; case 'j': ArgConverter(arg, *s).visit(arg); break; case 'z': ArgConverter(arg, *s).visit(arg); break; case 't': ArgConverter(arg, *s).visit(arg); break; case 'L': // printf produces garbage when 'L' is omitted for long double, no // need to do the same. break; default: --s; ArgConverter(arg, *s).visit(arg); } // Parse type. if (!*s) FMT_THROW(FormatError("invalid format string")); spec.type_ = static_cast(*s++); if (arg.type <= Arg::LAST_INTEGER_TYPE) { // Normalize type. switch (spec.type_) { case 'i': case 'u': spec.type_ = 'd'; break; case 'c': // TODO: handle wchar_t CharConverter(arg).visit(arg); break; } } start = s; // Format argument. internal::PrintfArgFormatter(writer, spec).visit(arg); } write(writer, start, s); } FMT_FUNC void fmt::report_system_error( int error_code, fmt::StringRef message) FMT_NOEXCEPT { // 'fmt::' is for bcc32. fmt::report_error(internal::format_system_error, error_code, message); } #if FMT_USE_WINDOWS_H FMT_FUNC void fmt::report_windows_error( int error_code, fmt::StringRef message) FMT_NOEXCEPT { // 'fmt::' is for bcc32. fmt::report_error(internal::format_windows_error, error_code, message); } #endif FMT_FUNC void fmt::print(std::FILE *f, CStringRef format_str, ArgList args) { MemoryWriter w; w.write(format_str, args); std::fwrite(w.data(), 1, w.size(), f); } FMT_FUNC void fmt::print(CStringRef format_str, ArgList args) { print(stdout, format_str, args); } FMT_FUNC void fmt::print(std::ostream &os, CStringRef format_str, ArgList args) { MemoryWriter w; w.write(format_str, args); write(os, w); } FMT_FUNC void fmt::print_colored(Color c, CStringRef format, ArgList args) { char escape[] = "\x1b[30m"; escape[3] = static_cast('0' + c); std::fputs(escape, stdout); print(format, args); std::fputs(RESET_COLOR, stdout); } FMT_FUNC int fmt::fprintf(std::FILE *f, CStringRef format, ArgList args) { MemoryWriter w; printf(w, format, args); std::size_t size = w.size(); return std::fwrite(w.data(), 1, size, f) < size ? -1 : static_cast(size); } FMT_FUNC int fmt::fprintf(std::ostream &os, CStringRef format, ArgList args) { MemoryWriter w; printf(w, format, args); write(os, w); return static_cast(w.size()); } #ifndef FMT_HEADER_ONLY template struct fmt::internal::BasicData; // Explicit instantiations for char. template void fmt::internal::FixedBuffer::grow(std::size_t); template void fmt::internal::ArgMap::init(const fmt::ArgList &args); template void fmt::internal::PrintfFormatter::format( BasicWriter &writer, CStringRef format); template int fmt::internal::CharTraits::format_float( char *buffer, std::size_t size, const char *format, unsigned width, int precision, double value); template int fmt::internal::CharTraits::format_float( char *buffer, std::size_t size, const char *format, unsigned width, int precision, long double value); // Explicit instantiations for wchar_t. template void fmt::internal::FixedBuffer::grow(std::size_t); template void fmt::internal::ArgMap::init(const fmt::ArgList &args); template void fmt::internal::PrintfFormatter::format( BasicWriter &writer, WCStringRef format); template int fmt::internal::CharTraits::format_float( wchar_t *buffer, std::size_t size, const wchar_t *format, unsigned width, int precision, double value); template int fmt::internal::CharTraits::format_float( wchar_t *buffer, std::size_t size, const wchar_t *format, unsigned width, int precision, long double value); #endif // FMT_HEADER_ONLY #ifdef _MSC_VER # pragma warning(pop) #endifgmmlib-intel-gmmlib-22.5.2/Source/GmmLib/Utility/GmmLog/spdlog/details/format.h000066400000000000000000003566371466655022700273020ustar00rootroot00000000000000/* Formatting library for C++ Copyright (c) 2012 - 2015, Victor Zverovich All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef FMT_FORMAT_H_ #define FMT_FORMAT_H_ //Added to spdlog version for header only usage #define FMT_HEADER_ONLY //Added to spdlog version in order to avoid including windows.h #if !defined (FMT_USE_WINDOWS_H) #define FMT_USE_WINDOWS_H 0 #endif #include #include #include #include #include #include #include #include #include #include #ifndef FMT_USE_IOSTREAMS # define FMT_USE_IOSTREAMS 1 #endif #if FMT_USE_IOSTREAMS # include #endif #ifdef _SECURE_SCL # define FMT_SECURE_SCL _SECURE_SCL #else # define FMT_SECURE_SCL 0 #endif #if FMT_SECURE_SCL # include #endif #if defined(_MSC_VER) && _MSC_VER <= 1500 typedef unsigned __int32 uint32_t; typedef unsigned __int64 uint64_t; typedef __int64 intmax_t; #else #include #endif #if !defined(FMT_HEADER_ONLY) && defined(_WIN32) # ifdef FMT_EXPORT # define FMT_API __declspec(dllexport) # elif defined(FMT_SHARED) # define FMT_API __declspec(dllimport) # endif #endif #ifndef FMT_API # define FMT_API #endif #ifdef __GNUC__ # define FMT_GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__) # define FMT_GCC_EXTENSION __extension__ # if FMT_GCC_VERSION >= 406 # pragma GCC diagnostic push // Disable the warning about "long long" which is sometimes reported even // when using __extension__. # pragma GCC diagnostic ignored "-Wlong-long" // Disable the warning about declaration shadowing because it affects too // many valid cases. # pragma GCC diagnostic ignored "-Wshadow" // Disable the warning about implicit conversions that may change the sign of // an integer; silencing it otherwise would require many explicit casts. # pragma GCC diagnostic ignored "-Wsign-conversion" # endif # if __cplusplus >= 201103L || defined __GXX_EXPERIMENTAL_CXX0X__ # define FMT_HAS_GXX_CXX11 1 # endif #else # define FMT_GCC_EXTENSION #endif #if defined(__clang__) && !defined(__INTEL_COMPILER) # pragma clang diagnostic push # pragma clang diagnostic ignored "-Wdocumentation" #endif #ifdef __GNUC_LIBSTD__ # define FMT_GNUC_LIBSTD_VERSION (__GNUC_LIBSTD__ * 100 + __GNUC_LIBSTD_MINOR__) #endif #ifdef __has_feature # define FMT_HAS_FEATURE(x) __has_feature(x) #else # define FMT_HAS_FEATURE(x) 0 #endif #ifdef __has_builtin # define FMT_HAS_BUILTIN(x) __has_builtin(x) #else # define FMT_HAS_BUILTIN(x) 0 #endif #ifdef __has_cpp_attribute # define FMT_HAS_CPP_ATTRIBUTE(x) __has_cpp_attribute(x) #else # define FMT_HAS_CPP_ATTRIBUTE(x) 0 #endif #ifndef FMT_USE_VARIADIC_TEMPLATES // Variadic templates are available in GCC since version 4.4 // (http://gcc.gnu.org/projects/cxx0x.html) and in Visual C++ // since version 2013. # define FMT_USE_VARIADIC_TEMPLATES \ (FMT_HAS_FEATURE(cxx_variadic_templates) || \ (FMT_GCC_VERSION >= 404 && FMT_HAS_GXX_CXX11) || _MSC_VER >= 1800) #endif #ifndef FMT_USE_RVALUE_REFERENCES // Don't use rvalue references when compiling with clang and an old libstdc++ // as the latter doesn't provide std::move. # if defined(FMT_GNUC_LIBSTD_VERSION) && FMT_GNUC_LIBSTD_VERSION <= 402 # define FMT_USE_RVALUE_REFERENCES 0 # else # define FMT_USE_RVALUE_REFERENCES \ (FMT_HAS_FEATURE(cxx_rvalue_references) || \ (FMT_GCC_VERSION >= 403 && FMT_HAS_GXX_CXX11) || _MSC_VER >= 1600) # endif #endif #if FMT_USE_RVALUE_REFERENCES # include // for std::move #endif // Check if exceptions are disabled. #if defined(__GNUC__) && !defined(__EXCEPTIONS) # define FMT_EXCEPTIONS 0 #endif #if defined(_MSC_VER) && !_HAS_EXCEPTIONS # define FMT_EXCEPTIONS 0 #endif #ifndef FMT_EXCEPTIONS # define FMT_EXCEPTIONS 1 #endif #ifndef FMT_THROW # if FMT_EXCEPTIONS # define FMT_THROW(x) throw x # else # define FMT_THROW(x) assert(false) # endif #endif // Define FMT_USE_NOEXCEPT to make C++ Format use noexcept (C++11 feature). #ifndef FMT_USE_NOEXCEPT # define FMT_USE_NOEXCEPT 0 #endif #ifndef FMT_NOEXCEPT # if FMT_EXCEPTIONS # if FMT_USE_NOEXCEPT || FMT_HAS_FEATURE(cxx_noexcept) || \ (FMT_GCC_VERSION >= 408 && FMT_HAS_GXX_CXX11) || \ _MSC_VER >= 1900 # define FMT_NOEXCEPT noexcept # else # define FMT_NOEXCEPT throw() # endif # else # define FMT_NOEXCEPT # endif #endif // A macro to disallow the copy constructor and operator= functions // This should be used in the private: declarations for a class #ifndef FMT_USE_DELETED_FUNCTIONS # define FMT_USE_DELETED_FUNCTIONS 0 #endif #if FMT_USE_DELETED_FUNCTIONS || FMT_HAS_FEATURE(cxx_deleted_functions) || \ (FMT_GCC_VERSION >= 404 && FMT_HAS_GXX_CXX11) || _MSC_VER >= 1800 # define FMT_DELETED_OR_UNDEFINED = delete # define FMT_DISALLOW_COPY_AND_ASSIGN(TypeName) \ TypeName(const TypeName&) = delete; \ TypeName& operator=(const TypeName&) = delete #else # define FMT_DELETED_OR_UNDEFINED # define FMT_DISALLOW_COPY_AND_ASSIGN(TypeName) \ TypeName(const TypeName&); \ TypeName& operator=(const TypeName&) #endif #ifndef FMT_USE_USER_DEFINED_LITERALS // All compilers which support UDLs also support variadic templates. This // makes the fmt::literals implementation easier. However, an explicit check // for variadic templates is added here just in case. # define FMT_USE_USER_DEFINED_LITERALS \ FMT_USE_VARIADIC_TEMPLATES && FMT_USE_RVALUE_REFERENCES && \ (FMT_HAS_FEATURE(cxx_user_literals) || \ (FMT_GCC_VERSION >= 407 && FMT_HAS_GXX_CXX11) || _MSC_VER >= 1900) #endif #ifndef FMT_ASSERT # define FMT_ASSERT(condition, message) assert((condition) && message) #endif #if FMT_GCC_VERSION >= 400 || FMT_HAS_BUILTIN(__builtin_clz) # define FMT_BUILTIN_CLZ(n) __builtin_clz(n) #endif #if FMT_GCC_VERSION >= 400 || FMT_HAS_BUILTIN(__builtin_clzll) # define FMT_BUILTIN_CLZLL(n) __builtin_clzll(n) #endif // Some compilers masquerade as both MSVC and GCC-likes or // otherwise support __builtin_clz and __builtin_clzll, so // only define FMT_BUILTIN_CLZ using the MSVC intrinsics // if the clz and clzll builtins are not available. #if defined(_MSC_VER) && !defined(FMT_BUILTIN_CLZLL) # include // _BitScanReverse, _BitScanReverse64 namespace fmt { namespace internal { # pragma intrinsic(_BitScanReverse) inline uint32_t clz(uint32_t x) { unsigned long r = 0; _BitScanReverse(&r, x); assert(x != 0); // Static analysis complains about using uninitialized data // "r", but the only way that can happen is if "x" is 0, // which the callers guarantee to not happen. # pragma warning(suppress: 6102) return 31 - r; } # define FMT_BUILTIN_CLZ(n) fmt::internal::clz(n) # ifdef _WIN64 # pragma intrinsic(_BitScanReverse64) # endif inline uint32_t clzll(uint64_t x) { unsigned long r = 0; # ifdef _WIN64 _BitScanReverse64(&r, x); # else // Scan the high 32 bits. if (_BitScanReverse(&r, static_cast(x >> 32))) return 63 - (r + 32); // Scan the low 32 bits. _BitScanReverse(&r, static_cast(x)); # endif assert(x != 0); // Static analysis complains about using uninitialized data // "r", but the only way that can happen is if "x" is 0, // which the callers guarantee to not happen. # pragma warning(suppress: 6102) return 63 - r; } # define FMT_BUILTIN_CLZLL(n) fmt::internal::clzll(n) } } #endif namespace fmt { namespace internal { struct DummyInt { int data[2]; operator int() const { return 0; } }; typedef std::numeric_limits FPUtil; // Dummy implementations of system functions such as signbit and ecvt called // if the latter are not available. inline DummyInt signbit(...) { return DummyInt(); } inline DummyInt _ecvt_s(...) { return DummyInt(); } inline DummyInt isinf(...) { return DummyInt(); } inline DummyInt _finite(...) { return DummyInt(); } inline DummyInt isnan(...) { return DummyInt(); } inline DummyInt _isnan(...) { return DummyInt(); } // A helper function to suppress bogus "conditional expression is constant" // warnings. template inline T check(T value) { return value; } } } // namespace fmt namespace std { // Standard permits specialization of std::numeric_limits. This specialization // is used to resolve ambiguity between isinf and std::isinf in glibc: // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=48891 // and the same for isnan and signbit. template <> class numeric_limits: public std::numeric_limits { public: // Portable version of isinf. template static bool isinfinity(T x) { using namespace fmt::internal; // The resolution "priority" is: // isinf macro > std::isinf > ::isinf > fmt::internal::isinf if (check(sizeof(isinf(x)) == sizeof(bool) || sizeof(isinf(x)) == sizeof(int))) { return isinf(x) != 0; } return !_finite(static_cast(x)); } // Portable version of isnan. template static bool isnotanumber(T x) { using namespace fmt::internal; if (check(sizeof(isnan(x)) == sizeof(bool) || sizeof(isnan(x)) == sizeof(int))) { return isnan(x) != 0; } return _isnan(static_cast(x)) != 0; } // Portable version of signbit. static bool isnegative(double x) { using namespace fmt::internal; if (check(sizeof(signbit(x)) == sizeof(int))) return signbit(x) != 0; if (x < 0) return true; if (!isnotanumber(x)) return false; int dec = 0, sign = 0; char buffer[2]; // The buffer size must be >= 2 or _ecvt_s will fail. _ecvt_s(buffer, sizeof(buffer), x, 0, &dec, &sign); return sign != 0; } }; } // namespace std namespace fmt { // Fix the warning about long long on older versions of GCC // that don't support the diagnostic pragma. FMT_GCC_EXTENSION typedef long long LongLong; FMT_GCC_EXTENSION typedef unsigned long long ULongLong; #if FMT_USE_RVALUE_REFERENCES using std::move; #endif template class BasicWriter; typedef BasicWriter Writer; typedef BasicWriter WWriter; namespace internal { template class BasicArgFormatter; } template > class BasicFormatter; template void format(BasicFormatter &f, const Char *&format_str, const T &value); /** \rst A string reference. It can be constructed from a C string or ``std::string``. You can use one of the following typedefs for common character types: +------------+-------------------------+ | Type | Definition | +============+=========================+ | StringRef | BasicStringRef | +------------+-------------------------+ | WStringRef | BasicStringRef | +------------+-------------------------+ This class is most useful as a parameter type to allow passing different types of strings to a function, for example:: template std::string format(StringRef format_str, const Args & ... args); format("{}", 42); format(std::string("{}"), 42); \endrst */ template class BasicStringRef { private: const Char *data_; std::size_t size_; public: /** Constructs a string reference object from a C string and a size. */ BasicStringRef(const Char *s, std::size_t size): data_(s), size_(size) {} /** \rst Constructs a string reference object from a C string computing the size with ``std::char_traits::length``. \endrst */ BasicStringRef(const Char *s) : data_(s), size_(std::char_traits::length(s)) {} /** \rst Constructs a string reference from an ``std::string`` object. \endrst */ BasicStringRef(const std::basic_string &s) : data_(s.c_str()), size_(s.size()) {} /** \rst Converts a string reference to an ``std::string`` object. \endrst */ std::basic_string to_string() const { return std::basic_string(data_, size_); } /** Returns a pointer to the string data. */ const Char *data() const { return data_; } /** Returns the string size. */ std::size_t size() const { return size_; } // Lexicographically compare this string reference to other. int compare(BasicStringRef other) const { std::size_t size = size_ < other.size_ ? size_ : other.size_; int result = std::char_traits::compare(data_, other.data_, size); if (result == 0) result = size_ == other.size_ ? 0 : (size_ < other.size_ ? -1 : 1); return result; } friend bool operator==(BasicStringRef lhs, BasicStringRef rhs) { return lhs.compare(rhs) == 0; } friend bool operator!=(BasicStringRef lhs, BasicStringRef rhs) { return lhs.compare(rhs) != 0; } friend bool operator<(BasicStringRef lhs, BasicStringRef rhs) { return lhs.compare(rhs) < 0; } friend bool operator<=(BasicStringRef lhs, BasicStringRef rhs) { return lhs.compare(rhs) <= 0; } friend bool operator>(BasicStringRef lhs, BasicStringRef rhs) { return lhs.compare(rhs) > 0; } friend bool operator>=(BasicStringRef lhs, BasicStringRef rhs) { return lhs.compare(rhs) >= 0; } }; typedef BasicStringRef StringRef; typedef BasicStringRef WStringRef; /** \rst A reference to a null terminated string. It can be constructed from a C string or ``std::string``. You can use one of the following typedefs for common character types: +-------------+--------------------------+ | Type | Definition | +=============+==========================+ | CStringRef | BasicCStringRef | +-------------+--------------------------+ | WCStringRef | BasicCStringRef | +-------------+--------------------------+ This class is most useful as a parameter type to allow passing different types of strings to a function, for example:: template std::string format(CStringRef format_str, const Args & ... args); format("{}", 42); format(std::string("{}"), 42); \endrst */ template class BasicCStringRef { private: const Char *data_; public: /** Constructs a string reference object from a C string. */ BasicCStringRef(const Char *s): data_(s) {} /** \rst Constructs a string reference from an ``std::string`` object. \endrst */ BasicCStringRef(const std::basic_string &s): data_(s.c_str()) {} /** Returns the pointer to a C string. */ const Char *c_str() const { return data_; } }; typedef BasicCStringRef CStringRef; typedef BasicCStringRef WCStringRef; /** A formatting error such as invalid format string. */ class FormatError: public std::runtime_error { public: explicit FormatError(CStringRef message) : std::runtime_error(message.c_str()) {} }; namespace internal { // MakeUnsigned::Type gives an unsigned type corresponding to integer type T. template struct MakeUnsigned { typedef T Type; }; #define FMT_SPECIALIZE_MAKE_UNSIGNED(T, U) \ template <> \ struct MakeUnsigned { typedef U Type; } FMT_SPECIALIZE_MAKE_UNSIGNED(char, unsigned char); FMT_SPECIALIZE_MAKE_UNSIGNED(signed char, unsigned char); FMT_SPECIALIZE_MAKE_UNSIGNED(short, unsigned short); FMT_SPECIALIZE_MAKE_UNSIGNED(int, unsigned); FMT_SPECIALIZE_MAKE_UNSIGNED(long, unsigned long); FMT_SPECIALIZE_MAKE_UNSIGNED(LongLong, ULongLong); // Casts nonnegative integer to unsigned. template inline typename MakeUnsigned::Type to_unsigned(Int value) { FMT_ASSERT(value >= 0, "negative value"); return static_cast::Type>(value); } // The number of characters to store in the MemoryBuffer object itself // to avoid dynamic memory allocation. enum { INLINE_BUFFER_SIZE = 500 }; #if FMT_SECURE_SCL // Use checked iterator to avoid warnings on MSVC. template inline stdext::checked_array_iterator make_ptr(T *ptr, std::size_t size) { return stdext::checked_array_iterator(ptr, size); } #else template inline T *make_ptr(T *ptr, std::size_t) { return ptr; } #endif } // namespace internal /** \rst A buffer supporting a subset of ``std::vector``'s operations. \endrst */ template class Buffer { private: FMT_DISALLOW_COPY_AND_ASSIGN(Buffer); protected: T *ptr_; std::size_t size_; std::size_t capacity_; Buffer(T *ptr = 0, std::size_t capacity = 0) : ptr_(ptr), size_(0), capacity_(capacity) {} /** \rst Increases the buffer capacity to hold at least *size* elements updating ``ptr_`` and ``capacity_``. \endrst */ virtual void grow(std::size_t size) = 0; public: virtual ~Buffer() {} /** Returns the size of this buffer. */ std::size_t size() const { return size_; } /** Returns the capacity of this buffer. */ std::size_t capacity() const { return capacity_; } /** Resizes the buffer. If T is a POD type new elements may not be initialized. */ void resize(std::size_t new_size) { if (new_size > capacity_) grow(new_size); size_ = new_size; } /** \rst Reserves space to store at least *capacity* elements. \endrst */ void reserve(std::size_t capacity) { if (capacity > capacity_) grow(capacity); } void clear() FMT_NOEXCEPT { size_ = 0; } void push_back(const T &value) { if (size_ == capacity_) grow(size_ + 1); ptr_[size_++] = value; } /** Appends data to the end of the buffer. */ template void append(const U *begin, const U *end); T &operator[](std::size_t index) { return ptr_[index]; } const T &operator[](std::size_t index) const { return ptr_[index]; } }; template template void Buffer::append(const U *begin, const U *end) { std::size_t new_size = size_ + internal::to_unsigned(end - begin); if (new_size > capacity_) grow(new_size); std::uninitialized_copy(begin, end, internal::make_ptr(ptr_, capacity_) + size_); size_ = new_size; } namespace internal { // A memory buffer for trivially copyable/constructible types with the first SIZE // elements stored in the object itself. template > class MemoryBuffer: private Allocator, public Buffer { private: T data_[SIZE]; // Deallocate memory allocated by the buffer. void deallocate() { if (this->ptr_ != data_) Allocator::deallocate(this->ptr_, this->capacity_); } protected: void grow(std::size_t size); public: explicit MemoryBuffer(const Allocator &alloc = Allocator()) : Allocator(alloc), Buffer(data_, SIZE) {} ~MemoryBuffer() { deallocate(); } #if FMT_USE_RVALUE_REFERENCES private: // Move data from other to this buffer. void move(MemoryBuffer &other) { Allocator &this_alloc = *this, &other_alloc = other; this_alloc = std::move(other_alloc); this->size_ = other.size_; this->capacity_ = other.capacity_; if (other.ptr_ == other.data_) { this->ptr_ = data_; std::uninitialized_copy(other.data_, other.data_ + this->size_, make_ptr(data_, this->capacity_)); } else { this->ptr_ = other.ptr_; // Set pointer to the inline array so that delete is not called // when deallocating. other.ptr_ = other.data_; } } public: MemoryBuffer(MemoryBuffer &&other) { move(other); } MemoryBuffer &operator=(MemoryBuffer &&other) { assert(this != &other); deallocate(); move(other); return *this; } #endif // Returns a copy of the allocator associated with this buffer. Allocator get_allocator() const { return *this; } }; template void MemoryBuffer::grow(std::size_t size) { std::size_t new_capacity = this->capacity_ + this->capacity_ / 2; if (size > new_capacity) new_capacity = size; T *new_ptr = this->allocate(new_capacity); // The following code doesn't throw, so the raw pointer above doesn't leak. std::uninitialized_copy(this->ptr_, this->ptr_ + this->size_, make_ptr(new_ptr, new_capacity)); std::size_t old_capacity = this->capacity_; T *old_ptr = this->ptr_; this->capacity_ = new_capacity; this->ptr_ = new_ptr; // deallocate may throw (at least in principle), but it doesn't matter since // the buffer already uses the new storage and will deallocate it in case // of exception. if (old_ptr != data_) Allocator::deallocate(old_ptr, old_capacity); } // A fixed-size buffer. template class FixedBuffer: public fmt::Buffer { public: FixedBuffer(Char *array, std::size_t size): fmt::Buffer(array, size) {} protected: FMT_API void grow(std::size_t size); }; template class BasicCharTraits { public: #if FMT_SECURE_SCL typedef stdext::checked_array_iterator CharPtr; #else typedef Char *CharPtr; #endif static Char cast(int value) { return static_cast(value); } }; template class CharTraits; template <> class CharTraits: public BasicCharTraits { private: // Conversion from wchar_t to char is not allowed. static char convert(wchar_t); public: static char convert(char value) { return value; } // Formats a floating-point number. template FMT_API static int format_float(char *buffer, std::size_t size, const char *format, unsigned width, int precision, T value); }; template <> class CharTraits: public BasicCharTraits { public: static wchar_t convert(char value) { return value; } static wchar_t convert(wchar_t value) { return value; } template FMT_API static int format_float(wchar_t *buffer, std::size_t size, const wchar_t *format, unsigned width, int precision, T value); }; // Checks if a number is negative - used to avoid warnings. template struct SignChecker { template static bool is_negative(T value) { return value < 0; } }; template <> struct SignChecker { template static bool is_negative(T) { return false; } }; // Returns true if value is negative, false otherwise. // Same as (value < 0) but doesn't produce warnings if T is an unsigned type. template inline bool is_negative(T value) { return SignChecker::is_signed>::is_negative(value); } // Selects uint32_t if FitsIn32Bits is true, uint64_t otherwise. template struct TypeSelector { typedef uint32_t Type; }; template <> struct TypeSelector { typedef uint64_t Type; }; template struct IntTraits { // Smallest of uint32_t and uint64_t that is large enough to represent // all values of T. typedef typename TypeSelector::digits <= 32>::Type MainType; }; FMT_API void report_unknown_type(char code, const char *type); // Static data is placed in this class template to allow header-only // configuration. template struct FMT_API BasicData { static const uint32_t POWERS_OF_10_32[]; static const uint64_t POWERS_OF_10_64[]; static const char DIGITS[]; }; typedef BasicData<> Data; #ifdef FMT_BUILTIN_CLZLL // Returns the number of decimal digits in n. Leading zeros are not counted // except for n == 0 in which case count_digits returns 1. inline unsigned count_digits(uint64_t n) { // Based on http://graphics.stanford.edu/~seander/bithacks.html#IntegerLog10 // and the benchmark https://github.com/localvoid/cxx-benchmark-count-digits. int t = (64 - FMT_BUILTIN_CLZLL(n | 1)) * 1233 >> 12; return to_unsigned(t) - (n < Data::POWERS_OF_10_64[t]) + 1; } #else // Fallback version of count_digits used when __builtin_clz is not available. inline unsigned count_digits(uint64_t n) { unsigned count = 1; for (;;) { // Integer division is slow so do it for a group of four digits instead // of for every digit. The idea comes from the talk by Alexandrescu // "Three Optimization Tips for C++". See speed-test for a comparison. if (n < 10) return count; if (n < 100) return count + 1; if (n < 1000) return count + 2; if (n < 10000) return count + 3; n /= 10000u; count += 4; } } #endif #ifdef FMT_BUILTIN_CLZ // Optional version of count_digits for better performance on 32-bit platforms. inline unsigned count_digits(uint32_t n) { int t = (32 - FMT_BUILTIN_CLZ(n | 1)) * 1233 >> 12; return to_unsigned(t) - (n < Data::POWERS_OF_10_32[t]) + 1; } #endif // Formats a decimal unsigned integer value writing into buffer. template inline void format_decimal(Char *buffer, UInt value, unsigned num_digits) { buffer += num_digits; while (value >= 100) { // Integer division is slow so do it for a group of two digits instead // of for every digit. The idea comes from the talk by Alexandrescu // "Three Optimization Tips for C++". See speed-test for a comparison. unsigned index = static_cast((value % 100) * 2); value /= 100; *--buffer = Data::DIGITS[index + 1]; *--buffer = Data::DIGITS[index]; } if (value < 10) { *--buffer = static_cast('0' + value); return; } unsigned index = static_cast(value * 2); *--buffer = Data::DIGITS[index + 1]; *--buffer = Data::DIGITS[index]; } #ifndef _WIN32 # define FMT_USE_WINDOWS_H 0 #elif !defined(FMT_USE_WINDOWS_H) # define FMT_USE_WINDOWS_H 1 #endif // Define FMT_USE_WINDOWS_H to 0 to disable use of windows.h. // All the functionality that relies on it will be disabled too. #if FMT_USE_WINDOWS_H // A converter from UTF-8 to UTF-16. // It is only provided for Windows since other systems support UTF-8 natively. class UTF8ToUTF16 { private: MemoryBuffer buffer_; public: FMT_API explicit UTF8ToUTF16(StringRef s); operator WStringRef() const { return WStringRef(&buffer_[0], size()); } size_t size() const { return buffer_.size() - 1; } const wchar_t *c_str() const { return &buffer_[0]; } std::wstring str() const { return std::wstring(&buffer_[0], size()); } }; // A converter from UTF-16 to UTF-8. // It is only provided for Windows since other systems support UTF-8 natively. class UTF16ToUTF8 { private: MemoryBuffer buffer_; public: UTF16ToUTF8() {} FMT_API explicit UTF16ToUTF8(WStringRef s); operator StringRef() const { return StringRef(&buffer_[0], size()); } size_t size() const { return buffer_.size() - 1; } const char *c_str() const { return &buffer_[0]; } std::string str() const { return std::string(&buffer_[0], size()); } // Performs conversion returning a system error code instead of // throwing exception on conversion error. This method may still throw // in case of memory allocation error. FMT_API int convert(WStringRef s); }; FMT_API void format_windows_error(fmt::Writer &out, int error_code, fmt::StringRef message) FMT_NOEXCEPT; #endif FMT_API void format_system_error(fmt::Writer &out, int error_code, fmt::StringRef message) FMT_NOEXCEPT; // A formatting argument value. struct Value { template struct StringValue { const Char *value; std::size_t size; }; typedef void(*FormatFunc)( void *formatter, const void *arg, void *format_str_ptr); struct CustomValue { const void *value; FormatFunc format; }; union { int int_value; unsigned uint_value; LongLong long_long_value; ULongLong ulong_long_value; double double_value; long double long_double_value; const void *pointer; StringValue string; StringValue sstring; StringValue ustring; StringValue wstring; CustomValue custom; }; enum Type { NONE, NAMED_ARG, // Integer types should go first, INT, UINT, LONG_LONG, ULONG_LONG, BOOL, CHAR, LAST_INTEGER_TYPE = CHAR, // followed by floating-point types. DOUBLE, LONG_DOUBLE, LAST_NUMERIC_TYPE = LONG_DOUBLE, CSTRING, STRING, WSTRING, POINTER, CUSTOM }; }; // A formatting argument. It is a trivially copyable/constructible type to // allow storage in internal::MemoryBuffer. struct Arg: Value { Type type; }; template struct NamedArg; template struct Null {}; // A helper class template to enable or disable overloads taking wide // characters and strings in MakeValue. template struct WCharHelper { typedef Null Supported; typedef T Unsupported; }; template struct WCharHelper { typedef T Supported; typedef Null Unsupported; }; typedef char Yes[1]; typedef char No[2]; // These are non-members to workaround an overload resolution bug in bcc32. Yes &convert(fmt::ULongLong); Yes &convert(std::ostream &); No &convert(...); template T &get(); struct DummyStream: std::ostream { DummyStream(); // Suppress a bogus warning in MSVC. // Hide all operator<< overloads from std::ostream. void operator<<(Null<>); }; No &operator<<(std::ostream &, int); template struct ConvertToIntImpl { enum { value = false }; }; template struct ConvertToIntImpl { // Convert to int only if T doesn't have an overloaded operator<<. enum { value = sizeof(convert(get() << get())) == sizeof(No) }; }; template struct ConvertToIntImpl2 { enum { value = false }; }; template struct ConvertToIntImpl2 { enum { // Don't convert numeric types. value = ConvertToIntImpl::is_specialized>::value }; }; template struct ConvertToInt { enum { enable_conversion = sizeof(convert(get())) == sizeof(Yes) }; enum { value = ConvertToIntImpl2::value }; }; #define FMT_DISABLE_CONVERSION_TO_INT(Type) \ template <> \ struct ConvertToInt { enum { value = 0 }; } // Silence warnings about convering float to int. FMT_DISABLE_CONVERSION_TO_INT(float); FMT_DISABLE_CONVERSION_TO_INT(double); FMT_DISABLE_CONVERSION_TO_INT(long double); template struct EnableIf {}; template struct EnableIf { typedef T type; }; template struct Conditional { typedef T type; }; template struct Conditional { typedef F type; }; // For bcc32 which doesn't understand ! in template arguments. template struct Not { enum { value = 0 }; }; template<> struct Not { enum { value = 1 }; }; // Makes an Arg object from any type. template class MakeValue: public Arg { public: typedef typename Formatter::Char Char; private: // The following two methods are private to disallow formatting of // arbitrary pointers. If you want to output a pointer cast it to // "void *" or "const void *". In particular, this forbids formatting // of "[const] volatile char *" which is printed as bool by iostreams. // Do not implement! template MakeValue(const T *value); template MakeValue(T *value); // The following methods are private to disallow formatting of wide // characters and strings into narrow strings as in // fmt::format("{}", L"test"); // To fix this, use a wide format string: fmt::format(L"{}", L"test"). #if !defined(_MSC_VER) || defined(_NATIVE_WCHAR_T_DEFINED) MakeValue(typename WCharHelper::Unsupported); #endif MakeValue(typename WCharHelper::Unsupported); MakeValue(typename WCharHelper::Unsupported); MakeValue(typename WCharHelper::Unsupported); MakeValue(typename WCharHelper::Unsupported); void set_string(StringRef str) { string.value = str.data(); string.size = str.size(); } void set_string(WStringRef str) { wstring.value = str.data(); wstring.size = str.size(); } // Formats an argument of a custom type, such as a user-defined class. template static void format_custom_arg( void *formatter, const void *arg, void *format_str_ptr) { format(*static_cast(formatter), *static_cast(format_str_ptr), *static_cast(arg)); } public: MakeValue() {} #define FMT_MAKE_VALUE_(Type, field, TYPE, rhs) \ MakeValue(Type value) { field = rhs; } \ static uint64_t type(Type) { return Arg::TYPE; } #define FMT_MAKE_VALUE(Type, field, TYPE) \ FMT_MAKE_VALUE_(Type, field, TYPE, value) FMT_MAKE_VALUE(bool, int_value, BOOL) FMT_MAKE_VALUE(short, int_value, INT) FMT_MAKE_VALUE(unsigned short, uint_value, UINT) FMT_MAKE_VALUE(int, int_value, INT) FMT_MAKE_VALUE(unsigned, uint_value, UINT) MakeValue(long value) { // To minimize the number of types we need to deal with, long is // translated either to int or to long long depending on its size. if (check(sizeof(long) == sizeof(int))) int_value = static_cast(value); else long_long_value = value; } static uint64_t type(long) { return sizeof(long) == sizeof(int) ? Arg::INT : Arg::LONG_LONG; } MakeValue(unsigned long value) { if (check(sizeof(unsigned long) == sizeof(unsigned))) uint_value = static_cast(value); else ulong_long_value = value; } static uint64_t type(unsigned long) { return sizeof(unsigned long) == sizeof(unsigned) ? Arg::UINT : Arg::ULONG_LONG; } FMT_MAKE_VALUE(LongLong, long_long_value, LONG_LONG) FMT_MAKE_VALUE(ULongLong, ulong_long_value, ULONG_LONG) FMT_MAKE_VALUE(float, double_value, DOUBLE) FMT_MAKE_VALUE(double, double_value, DOUBLE) FMT_MAKE_VALUE(long double, long_double_value, LONG_DOUBLE) FMT_MAKE_VALUE(signed char, int_value, INT) FMT_MAKE_VALUE(unsigned char, uint_value, UINT) FMT_MAKE_VALUE(char, int_value, CHAR) #if !defined(_MSC_VER) || defined(_NATIVE_WCHAR_T_DEFINED) MakeValue(typename WCharHelper::Supported value) { int_value = value; } static uint64_t type(wchar_t) { return Arg::CHAR; } #endif #define FMT_MAKE_STR_VALUE(Type, TYPE) \ MakeValue(Type value) { set_string(value); } \ static uint64_t type(Type) { return Arg::TYPE; } FMT_MAKE_VALUE(char *, string.value, CSTRING) FMT_MAKE_VALUE(const char *, string.value, CSTRING) FMT_MAKE_VALUE(const signed char *, sstring.value, CSTRING) FMT_MAKE_VALUE(const unsigned char *, ustring.value, CSTRING) FMT_MAKE_STR_VALUE(const std::string &, STRING) FMT_MAKE_STR_VALUE(StringRef, STRING) FMT_MAKE_VALUE_(CStringRef, string.value, CSTRING, value.c_str()) #define FMT_MAKE_WSTR_VALUE(Type, TYPE) \ MakeValue(typename WCharHelper::Supported value) { \ set_string(value); \ } \ static uint64_t type(Type) { return Arg::TYPE; } FMT_MAKE_WSTR_VALUE(wchar_t *, WSTRING) FMT_MAKE_WSTR_VALUE(const wchar_t *, WSTRING) FMT_MAKE_WSTR_VALUE(const std::wstring &, WSTRING) FMT_MAKE_WSTR_VALUE(WStringRef, WSTRING) FMT_MAKE_VALUE(void *, pointer, POINTER) FMT_MAKE_VALUE(const void *, pointer, POINTER) template MakeValue(const T &value, typename EnableIf::value>::value, int>::type = 0) { custom.value = &value; custom.format = &format_custom_arg; } template MakeValue(const T &value, typename EnableIf::value, int>::type = 0) { int_value = value; } template static uint64_t type(const T &) { return ConvertToInt::value ? Arg::INT : Arg::CUSTOM; } // Additional template param `Char_` is needed here because make_type always // uses char. template MakeValue(const NamedArg &value) { pointer = &value; } template static uint64_t type(const NamedArg &) { return Arg::NAMED_ARG; } }; template class MakeArg: public Arg { public: MakeArg() { type = Arg::NONE; } template MakeArg(const T &value) : Arg(MakeValue(value)) { type = static_cast(MakeValue::type(value)); } }; template struct NamedArg: Arg { BasicStringRef name; template NamedArg(BasicStringRef argname, const T &value) : Arg(MakeArg< BasicFormatter >(value)), name(argname) {} }; #define FMT_DISPATCH(call) static_cast(this)->call // An argument visitor. // To use ArgVisitor define a subclass that implements some or all of the // visit methods with the same signatures as the methods in ArgVisitor, // for example, visit_int(int). // Specify the subclass name as the Impl template parameter. Then calling // ArgVisitor::visit for some argument will dispatch to a visit method // specific to the argument type. For example, if the argument type is // double then visit_double(double) method of a subclass will be called. // If the subclass doesn't contain a method with this signature, then // a corresponding method of ArgVisitor will be called. // // Example: // class MyArgVisitor : public ArgVisitor { // public: // void visit_int(int value) { print("{}", value); } // void visit_double(double value) { print("{}", value ); } // }; // // ArgVisitor uses the curiously recurring template pattern: // http://en.wikipedia.org/wiki/Curiously_recurring_template_pattern template class ArgVisitor { public: void report_unhandled_arg() {} Result visit_unhandled_arg() { FMT_DISPATCH(report_unhandled_arg()); return Result(); } Result visit_int(int value) { return FMT_DISPATCH(visit_any_int(value)); } Result visit_long_long(LongLong value) { return FMT_DISPATCH(visit_any_int(value)); } Result visit_uint(unsigned value) { return FMT_DISPATCH(visit_any_int(value)); } Result visit_ulong_long(ULongLong value) { return FMT_DISPATCH(visit_any_int(value)); } Result visit_bool(bool value) { return FMT_DISPATCH(visit_any_int(value)); } Result visit_char(int value) { return FMT_DISPATCH(visit_any_int(value)); } template Result visit_any_int(T) { return FMT_DISPATCH(visit_unhandled_arg()); } Result visit_double(double value) { return FMT_DISPATCH(visit_any_double(value)); } Result visit_long_double(long double value) { return FMT_DISPATCH(visit_any_double(value)); } template Result visit_any_double(T) { return FMT_DISPATCH(visit_unhandled_arg()); } Result visit_cstring(const char *) { return FMT_DISPATCH(visit_unhandled_arg()); } Result visit_string(Arg::StringValue) { return FMT_DISPATCH(visit_unhandled_arg()); } Result visit_wstring(Arg::StringValue) { return FMT_DISPATCH(visit_unhandled_arg()); } Result visit_pointer(const void *) { return FMT_DISPATCH(visit_unhandled_arg()); } Result visit_custom(Arg::CustomValue) { return FMT_DISPATCH(visit_unhandled_arg()); } Result visit(const Arg &arg) { switch (arg.type) { default: FMT_ASSERT(false, "invalid argument type"); return Result(); case Arg::INT: return FMT_DISPATCH(visit_int(arg.int_value)); case Arg::UINT: return FMT_DISPATCH(visit_uint(arg.uint_value)); case Arg::LONG_LONG: return FMT_DISPATCH(visit_long_long(arg.long_long_value)); case Arg::ULONG_LONG: return FMT_DISPATCH(visit_ulong_long(arg.ulong_long_value)); case Arg::BOOL: return FMT_DISPATCH(visit_bool(arg.int_value != 0)); case Arg::CHAR: return FMT_DISPATCH(visit_char(arg.int_value)); case Arg::DOUBLE: return FMT_DISPATCH(visit_double(arg.double_value)); case Arg::LONG_DOUBLE: return FMT_DISPATCH(visit_long_double(arg.long_double_value)); case Arg::CSTRING: return FMT_DISPATCH(visit_cstring(arg.string.value)); case Arg::STRING: return FMT_DISPATCH(visit_string(arg.string)); case Arg::WSTRING: return FMT_DISPATCH(visit_wstring(arg.wstring)); case Arg::POINTER: return FMT_DISPATCH(visit_pointer(arg.pointer)); case Arg::CUSTOM: return FMT_DISPATCH(visit_custom(arg.custom)); } } }; class RuntimeError: public std::runtime_error { protected: RuntimeError(): std::runtime_error("") {} }; template class PrintfArgFormatter; template class ArgMap; } // namespace internal /** An argument list. */ class ArgList { private: // To reduce compiled code size per formatting function call, types of first // MAX_PACKED_ARGS arguments are passed in the types_ field. uint64_t types_; union { // If the number of arguments is less than MAX_PACKED_ARGS, the argument // values are stored in values_, otherwise they are stored in args_. // This is done to reduce compiled code size as storing larger objects // may require more code (at least on x86-64) even if the same amount of // data is actually copied to stack. It saves ~10% on the bloat test. const internal::Value *values_; const internal::Arg *args_; }; internal::Arg::Type type(unsigned index) const { unsigned shift = index * 4; uint64_t mask = 0xf; return static_cast( (types_ & (mask << shift)) >> shift); } template friend class internal::ArgMap; public: // Maximum number of arguments with packed types. enum { MAX_PACKED_ARGS = 16 }; ArgList(): types_(0) {} ArgList(ULongLong types, const internal::Value *values) : types_(types), values_(values) {} ArgList(ULongLong types, const internal::Arg *args) : types_(types), args_(args) {} /** Returns the argument at specified index. */ internal::Arg operator[](unsigned index) const { using internal::Arg; Arg arg; bool use_values = type(MAX_PACKED_ARGS - 1) == Arg::NONE; if (index < MAX_PACKED_ARGS) { Arg::Type arg_type = type(index); internal::Value &val = arg; if (arg_type != Arg::NONE) val = use_values ? values_[index] : args_[index]; arg.type = arg_type; return arg; } if (use_values) { // The index is greater than the number of arguments that can be stored // in values, so return a "none" argument. arg.type = Arg::NONE; return arg; } for (unsigned i = MAX_PACKED_ARGS; i <= index; ++i) { if (args_[i].type == Arg::NONE) return args_[i]; } return args_[index]; } }; enum Alignment { ALIGN_DEFAULT, ALIGN_LEFT, ALIGN_RIGHT, ALIGN_CENTER, ALIGN_NUMERIC }; // Flags. enum { SIGN_FLAG = 1, PLUS_FLAG = 2, MINUS_FLAG = 4, HASH_FLAG = 8, CHAR_FLAG = 0x10 // Argument has char type - used in error reporting. }; // An empty format specifier. struct EmptySpec {}; // A type specifier. template struct TypeSpec: EmptySpec { Alignment align() const { return ALIGN_DEFAULT; } unsigned width() const { return 0; } int precision() const { return -1; } bool flag(unsigned) const { return false; } char type() const { return TYPE; } char fill() const { return ' '; } }; // A width specifier. struct WidthSpec { unsigned width_; // Fill is always wchar_t and cast to char if necessary to avoid having // two specialization of WidthSpec and its subclasses. wchar_t fill_; WidthSpec(unsigned width, wchar_t fill): width_(width), fill_(fill) {} unsigned width() const { return width_; } wchar_t fill() const { return fill_; } }; // An alignment specifier. struct AlignSpec: WidthSpec { Alignment align_; AlignSpec(unsigned width, wchar_t fill, Alignment align = ALIGN_DEFAULT) : WidthSpec(width, fill), align_(align) {} Alignment align() const { return align_; } int precision() const { return -1; } }; // An alignment and type specifier. template struct AlignTypeSpec: AlignSpec { AlignTypeSpec(unsigned width, wchar_t fill): AlignSpec(width, fill) {} bool flag(unsigned) const { return false; } char type() const { return TYPE; } }; // A full format specifier. struct FormatSpec: AlignSpec { unsigned flags_; int precision_; char type_; FormatSpec( unsigned width = 0, char type = 0, wchar_t fill = ' ') : AlignSpec(width, fill), flags_(0), precision_(-1), type_(type) {} bool flag(unsigned f) const { return (flags_ & f) != 0; } int precision() const { return precision_; } char type() const { return type_; } }; // An integer format specifier. template , typename Char = char> class IntFormatSpec: public SpecT { private: T value_; public: IntFormatSpec(T val, const SpecT &spec = SpecT()) : SpecT(spec), value_(val) {} T value() const { return value_; } }; // A string format specifier. template class StrFormatSpec: public AlignSpec { private: const Char *str_; public: template StrFormatSpec(const Char *str, unsigned width, FillChar fill) : AlignSpec(width, fill), str_(str) { internal::CharTraits::convert(FillChar()); } const Char *str() const { return str_; } }; /** Returns an integer format specifier to format the value in base 2. */ IntFormatSpec > bin(int value); /** Returns an integer format specifier to format the value in base 8. */ IntFormatSpec > oct(int value); /** Returns an integer format specifier to format the value in base 16 using lower-case letters for the digits above 9. */ IntFormatSpec > hex(int value); /** Returns an integer formatter format specifier to format in base 16 using upper-case letters for the digits above 9. */ IntFormatSpec > hexu(int value); /** \rst Returns an integer format specifier to pad the formatted argument with the fill character to the specified width using the default (right) numeric alignment. **Example**:: MemoryWriter out; out << pad(hex(0xcafe), 8, '0'); // out.str() == "0000cafe" \endrst */ template IntFormatSpec, Char> pad( int value, unsigned width, Char fill = ' '); #define FMT_DEFINE_INT_FORMATTERS(TYPE) \ inline IntFormatSpec > bin(TYPE value) { \ return IntFormatSpec >(value, TypeSpec<'b'>()); \ } \ \ inline IntFormatSpec > oct(TYPE value) { \ return IntFormatSpec >(value, TypeSpec<'o'>()); \ } \ \ inline IntFormatSpec > hex(TYPE value) { \ return IntFormatSpec >(value, TypeSpec<'x'>()); \ } \ \ inline IntFormatSpec > hexu(TYPE value) { \ return IntFormatSpec >(value, TypeSpec<'X'>()); \ } \ \ template \ inline IntFormatSpec > pad( \ IntFormatSpec > f, unsigned width) { \ return IntFormatSpec >( \ f.value(), AlignTypeSpec(width, ' ')); \ } \ \ /* For compatibility with older compilers we provide two overloads for pad, */ \ /* one that takes a fill character and one that doesn't. In the future this */ \ /* can be replaced with one overload making the template argument Char */ \ /* default to char (C++11). */ \ template \ inline IntFormatSpec, Char> pad( \ IntFormatSpec, Char> f, \ unsigned width, Char fill) { \ return IntFormatSpec, Char>( \ f.value(), AlignTypeSpec(width, fill)); \ } \ \ inline IntFormatSpec > pad( \ TYPE value, unsigned width) { \ return IntFormatSpec >( \ value, AlignTypeSpec<0>(width, ' ')); \ } \ \ template \ inline IntFormatSpec, Char> pad( \ TYPE value, unsigned width, Char fill) { \ return IntFormatSpec, Char>( \ value, AlignTypeSpec<0>(width, fill)); \ } FMT_DEFINE_INT_FORMATTERS(int) FMT_DEFINE_INT_FORMATTERS(long) FMT_DEFINE_INT_FORMATTERS(unsigned) FMT_DEFINE_INT_FORMATTERS(unsigned long) FMT_DEFINE_INT_FORMATTERS(LongLong) FMT_DEFINE_INT_FORMATTERS(ULongLong) /** \rst Returns a string formatter that pads the formatted argument with the fill character to the specified width using the default (left) string alignment. **Example**:: std::string s = str(MemoryWriter() << pad("abc", 8)); // s == "abc " \endrst */ template inline StrFormatSpec pad( const Char *str, unsigned width, Char fill = ' ') { return StrFormatSpec(str, width, fill); } inline StrFormatSpec pad( const wchar_t *str, unsigned width, char fill = ' ') { return StrFormatSpec(str, width, fill); } namespace internal { template class ArgMap { private: typedef std::vector, internal::Arg> > MapType; typedef typename MapType::value_type Pair; MapType map_; public: FMT_API void init(const ArgList &args); const internal::Arg* find(const fmt::BasicStringRef &name) const { // The list is unsorted, so just return the first matching name. for (typename MapType::const_iterator it = map_.begin(), end = map_.end(); it != end; ++it) { if (it->first == name) return &it->second; } return 0; } }; template class ArgFormatterBase: public ArgVisitor { private: BasicWriter &writer_; FormatSpec &spec_; FMT_DISALLOW_COPY_AND_ASSIGN(ArgFormatterBase); void write_pointer(const void *p) { spec_.flags_ = HASH_FLAG; spec_.type_ = 'x'; writer_.write_int(reinterpret_cast(p), spec_); } protected: BasicWriter &writer() { return writer_; } FormatSpec &spec() { return spec_; } void write(bool value) { const char *str_value = value ? "true" : "false"; Arg::StringValue str = { str_value, std::strlen(str_value) }; writer_.write_str(str, spec_); } void write(const char *value) { Arg::StringValue str = { value, value != 0 ? std::strlen(value) : 0 }; writer_.write_str(str, spec_); } public: ArgFormatterBase(BasicWriter &w, FormatSpec &s) : writer_(w), spec_(s) {} template void visit_any_int(T value) { writer_.write_int(value, spec_); } template void visit_any_double(T value) { writer_.write_double(value, spec_); } void visit_bool(bool value) { if (spec_.type_) return visit_any_int(value); write(value); } void visit_char(int value) { if (spec_.type_ && spec_.type_ != 'c') { spec_.flags_ |= CHAR_FLAG; writer_.write_int(value, spec_); return; } if (spec_.align_ == ALIGN_NUMERIC || spec_.flags_ != 0) FMT_THROW(FormatError("invalid format specifier for char")); typedef typename BasicWriter::CharPtr CharPtr; Char fill = internal::CharTraits::cast(spec_.fill()); CharPtr out = CharPtr(); const unsigned CHAR_WIDTH = 1; if (spec_.width_ > CHAR_WIDTH) { out = writer_.grow_buffer(spec_.width_); if (spec_.align_ == ALIGN_RIGHT) { std::uninitialized_fill_n(out, spec_.width_ - CHAR_WIDTH, fill); out += spec_.width_ - CHAR_WIDTH; } else if (spec_.align_ == ALIGN_CENTER) { out = writer_.fill_padding(out, spec_.width_, internal::check(CHAR_WIDTH), fill); } else { std::uninitialized_fill_n(out + CHAR_WIDTH, spec_.width_ - CHAR_WIDTH, fill); } } else { out = writer_.grow_buffer(CHAR_WIDTH); } *out = internal::CharTraits::cast(value); } void visit_cstring(const char *value) { if (spec_.type_ == 'p') return write_pointer(value); write(value); } void visit_string(Arg::StringValue value) { writer_.write_str(value, spec_); } using ArgVisitor::visit_wstring; void visit_wstring(Arg::StringValue value) { writer_.write_str(value, spec_); } void visit_pointer(const void *value) { if (spec_.type_ && spec_.type_ != 'p') report_unknown_type(spec_.type_, "pointer"); write_pointer(value); } }; // An argument formatter. template class BasicArgFormatter: public ArgFormatterBase, Char> { private: BasicFormatter &formatter_; const Char *format_; public: BasicArgFormatter(BasicFormatter &f, FormatSpec &s, const Char *fmt) : ArgFormatterBase, Char>(f.writer(), s), formatter_(f), format_(fmt) {} void visit_custom(Arg::CustomValue c) { c.format(&formatter_, c.value, &format_); } }; class FormatterBase { private: ArgList args_; int next_arg_index_; // Returns the argument with specified index. FMT_API Arg do_get_arg(unsigned arg_index, const char *&error); protected: const ArgList &args() const { return args_; } explicit FormatterBase(const ArgList &args) { args_ = args; next_arg_index_ = 0; } // Returns the next argument. Arg next_arg(const char *&error) { if (next_arg_index_ >= 0) return do_get_arg(internal::to_unsigned(next_arg_index_++), error); error = "cannot switch from manual to automatic argument indexing"; return Arg(); } // Checks if manual indexing is used and returns the argument with // specified index. Arg get_arg(unsigned arg_index, const char *&error) { return check_no_auto_index(error) ? do_get_arg(arg_index, error) : Arg(); } bool check_no_auto_index(const char *&error) { if (next_arg_index_ > 0) { error = "cannot switch from automatic to manual argument indexing"; return false; } next_arg_index_ = -1; return true; } template void write(BasicWriter &w, const Char *start, const Char *end) { if (start != end) w << BasicStringRef(start, internal::to_unsigned(end - start)); } }; // A printf formatter. template class PrintfFormatter: private FormatterBase { private: void parse_flags(FormatSpec &spec, const Char *&s); // Returns the argument with specified index or, if arg_index is equal // to the maximum unsigned value, the next argument. Arg get_arg(const Char *s, unsigned arg_index = (std::numeric_limits::max)()); // Parses argument index, flags and width and returns the argument index. unsigned parse_header(const Char *&s, FormatSpec &spec); public: explicit PrintfFormatter(const ArgList &args): FormatterBase(args) {} FMT_API void format(BasicWriter &writer, BasicCStringRef format_str); }; } // namespace internal /** This template formats data and writes the output to a writer. */ template class BasicFormatter: private internal::FormatterBase { public: /** The character type for the output. */ typedef CharType Char; private: BasicWriter &writer_; internal::ArgMap map_; FMT_DISALLOW_COPY_AND_ASSIGN(BasicFormatter); using internal::FormatterBase::get_arg; // Checks if manual indexing is used and returns the argument with // specified name. internal::Arg get_arg(BasicStringRef arg_name, const char *&error); // Parses argument index and returns corresponding argument. internal::Arg parse_arg_index(const Char *&s); // Parses argument name and returns corresponding argument. internal::Arg parse_arg_name(const Char *&s); public: /** \rst Constructs a ``BasicFormatter`` object. References to the arguments and the writer are stored in the formatter object so make sure they have appropriate lifetimes. \endrst */ BasicFormatter(const ArgList &args, BasicWriter &w) : internal::FormatterBase(args), writer_(w) {} /** Returns a reference to the writer associated with this formatter. */ BasicWriter &writer() { return writer_; } /** Formats stored arguments and writes the output to the writer. */ void format(BasicCStringRef format_str); // Formats a single argument and advances format_str, a format string pointer. const Char *format(const Char *&format_str, const internal::Arg &arg); }; // Generates a comma-separated list with results of applying f to // numbers 0..n-1. # define FMT_GEN(n, f) FMT_GEN##n(f) # define FMT_GEN1(f) f(0) # define FMT_GEN2(f) FMT_GEN1(f), f(1) # define FMT_GEN3(f) FMT_GEN2(f), f(2) # define FMT_GEN4(f) FMT_GEN3(f), f(3) # define FMT_GEN5(f) FMT_GEN4(f), f(4) # define FMT_GEN6(f) FMT_GEN5(f), f(5) # define FMT_GEN7(f) FMT_GEN6(f), f(6) # define FMT_GEN8(f) FMT_GEN7(f), f(7) # define FMT_GEN9(f) FMT_GEN8(f), f(8) # define FMT_GEN10(f) FMT_GEN9(f), f(9) namespace internal { inline uint64_t make_type() { return 0; } template inline uint64_t make_type(const T &arg) { return MakeValue< BasicFormatter >::type(arg); } template struct ArgArray; template struct ArgArray { typedef Value Type[N > 0 ? N : 1]; template static Value make(const T &value) { Value result = MakeValue(value); // Workaround a bug in Apple LLVM version 4.2 (clang-425.0.28) of clang: // https://github.com/cppformat/cppformat/issues/276 (void)result.custom.format; return result; } }; template struct ArgArray { typedef Arg Type[N + 1]; // +1 for the list end Arg::NONE template static Arg make(const T &value) { return MakeArg(value); } }; #if FMT_USE_VARIADIC_TEMPLATES template inline uint64_t make_type(const Arg &first, const Args & ... tail) { return make_type(first) | (make_type(tail...) << 4); } #else struct ArgType { uint64_t type; ArgType(): type(0) {} template ArgType(const T &arg) : type(make_type(arg)) {} }; # define FMT_ARG_TYPE_DEFAULT(n) ArgType t##n = ArgType() inline uint64_t make_type(FMT_GEN15(FMT_ARG_TYPE_DEFAULT)) { return t0.type | (t1.type << 4) | (t2.type << 8) | (t3.type << 12) | (t4.type << 16) | (t5.type << 20) | (t6.type << 24) | (t7.type << 28) | (t8.type << 32) | (t9.type << 36) | (t10.type << 40) | (t11.type << 44) | (t12.type << 48) | (t13.type << 52) | (t14.type << 56); } #endif template class FormatBuf: public std::basic_streambuf { private: typedef typename std::basic_streambuf::int_type int_type; typedef typename std::basic_streambuf::traits_type traits_type; Buffer &buffer_; Char *start_; public: FormatBuf(Buffer &buffer): buffer_(buffer), start_(&buffer[0]) { this->setp(start_, start_ + buffer_.capacity()); } int_type overflow(int_type ch = traits_type::eof()) { if (!traits_type::eq_int_type(ch, traits_type::eof())) { size_t size = this->size(); buffer_.resize(size); buffer_.reserve(size * 2); start_ = &buffer_[0]; start_[size] = traits_type::to_char_type(ch); this->setp(start_ + size + 1, start_ + size * 2); } return ch; } size_t size() const { return to_unsigned(this->pptr() - start_); } }; } // namespace internal # define FMT_MAKE_TEMPLATE_ARG(n) typename T##n # define FMT_MAKE_ARG_TYPE(n) T##n # define FMT_MAKE_ARG(n) const T##n &v##n # define FMT_ASSIGN_char(n) \ arr[n] = fmt::internal::MakeValue< fmt::BasicFormatter >(v##n) # define FMT_ASSIGN_wchar_t(n) \ arr[n] = fmt::internal::MakeValue< fmt::BasicFormatter >(v##n) #if FMT_USE_VARIADIC_TEMPLATES // Defines a variadic function returning void. # define FMT_VARIADIC_VOID(func, arg_type) \ template \ void func(arg_type arg0, const Args & ... args) { \ typedef fmt::internal::ArgArray ArgArray; \ typename ArgArray::Type array{ \ ArgArray::template make >(args)...}; \ func(arg0, fmt::ArgList(fmt::internal::make_type(args...), array)); \ } // Defines a variadic constructor. # define FMT_VARIADIC_CTOR(ctor, func, arg0_type, arg1_type) \ template \ ctor(arg0_type arg0, arg1_type arg1, const Args & ... args) { \ typedef fmt::internal::ArgArray ArgArray; \ typename ArgArray::Type array{ \ ArgArray::template make >(args)...}; \ func(arg0, arg1, fmt::ArgList(fmt::internal::make_type(args...), array)); \ } #else # define FMT_MAKE_REF(n) \ fmt::internal::MakeValue< fmt::BasicFormatter >(v##n) # define FMT_MAKE_REF2(n) v##n // Defines a wrapper for a function taking one argument of type arg_type // and n additional arguments of arbitrary types. # define FMT_WRAP1(func, arg_type, n) \ template \ inline void func(arg_type arg1, FMT_GEN(n, FMT_MAKE_ARG)) { \ const fmt::internal::ArgArray::Type array = {FMT_GEN(n, FMT_MAKE_REF)}; \ func(arg1, fmt::ArgList( \ fmt::internal::make_type(FMT_GEN(n, FMT_MAKE_REF2)), array)); \ } // Emulates a variadic function returning void on a pre-C++11 compiler. # define FMT_VARIADIC_VOID(func, arg_type) \ inline void func(arg_type arg) { func(arg, fmt::ArgList()); } \ FMT_WRAP1(func, arg_type, 1) FMT_WRAP1(func, arg_type, 2) \ FMT_WRAP1(func, arg_type, 3) FMT_WRAP1(func, arg_type, 4) \ FMT_WRAP1(func, arg_type, 5) FMT_WRAP1(func, arg_type, 6) \ FMT_WRAP1(func, arg_type, 7) FMT_WRAP1(func, arg_type, 8) \ FMT_WRAP1(func, arg_type, 9) FMT_WRAP1(func, arg_type, 10) # define FMT_CTOR(ctor, func, arg0_type, arg1_type, n) \ template \ ctor(arg0_type arg0, arg1_type arg1, FMT_GEN(n, FMT_MAKE_ARG)) { \ const fmt::internal::ArgArray::Type array = {FMT_GEN(n, FMT_MAKE_REF)}; \ func(arg0, arg1, fmt::ArgList( \ fmt::internal::make_type(FMT_GEN(n, FMT_MAKE_REF2)), array)); \ } // Emulates a variadic constructor on a pre-C++11 compiler. # define FMT_VARIADIC_CTOR(ctor, func, arg0_type, arg1_type) \ FMT_CTOR(ctor, func, arg0_type, arg1_type, 1) \ FMT_CTOR(ctor, func, arg0_type, arg1_type, 2) \ FMT_CTOR(ctor, func, arg0_type, arg1_type, 3) \ FMT_CTOR(ctor, func, arg0_type, arg1_type, 4) \ FMT_CTOR(ctor, func, arg0_type, arg1_type, 5) \ FMT_CTOR(ctor, func, arg0_type, arg1_type, 6) \ FMT_CTOR(ctor, func, arg0_type, arg1_type, 7) \ FMT_CTOR(ctor, func, arg0_type, arg1_type, 8) \ FMT_CTOR(ctor, func, arg0_type, arg1_type, 9) \ FMT_CTOR(ctor, func, arg0_type, arg1_type, 10) #endif // Generates a comma-separated list with results of applying f to pairs // (argument, index). #define FMT_FOR_EACH1(f, x0) f(x0, 0) #define FMT_FOR_EACH2(f, x0, x1) \ FMT_FOR_EACH1(f, x0), f(x1, 1) #define FMT_FOR_EACH3(f, x0, x1, x2) \ FMT_FOR_EACH2(f, x0 ,x1), f(x2, 2) #define FMT_FOR_EACH4(f, x0, x1, x2, x3) \ FMT_FOR_EACH3(f, x0, x1, x2), f(x3, 3) #define FMT_FOR_EACH5(f, x0, x1, x2, x3, x4) \ FMT_FOR_EACH4(f, x0, x1, x2, x3), f(x4, 4) #define FMT_FOR_EACH6(f, x0, x1, x2, x3, x4, x5) \ FMT_FOR_EACH5(f, x0, x1, x2, x3, x4), f(x5, 5) #define FMT_FOR_EACH7(f, x0, x1, x2, x3, x4, x5, x6) \ FMT_FOR_EACH6(f, x0, x1, x2, x3, x4, x5), f(x6, 6) #define FMT_FOR_EACH8(f, x0, x1, x2, x3, x4, x5, x6, x7) \ FMT_FOR_EACH7(f, x0, x1, x2, x3, x4, x5, x6), f(x7, 7) #define FMT_FOR_EACH9(f, x0, x1, x2, x3, x4, x5, x6, x7, x8) \ FMT_FOR_EACH8(f, x0, x1, x2, x3, x4, x5, x6, x7), f(x8, 8) #define FMT_FOR_EACH10(f, x0, x1, x2, x3, x4, x5, x6, x7, x8, x9) \ FMT_FOR_EACH9(f, x0, x1, x2, x3, x4, x5, x6, x7, x8), f(x9, 9) /** An error returned by an operating system or a language runtime, for example a file opening error. */ class SystemError: public internal::RuntimeError { private: void init(int err_code, CStringRef format_str, ArgList args); protected: int error_code_; typedef char Char; // For FMT_VARIADIC_CTOR. SystemError() {} public: /** \rst Constructs a :class:`fmt::SystemError` object with the description of the form .. parsed-literal:: **: ** where ** is the formatted message and ** is the system message corresponding to the error code. *error_code* is a system error code as given by ``errno``. If *error_code* is not a valid error code such as -1, the system message may look like "Unknown error -1" and is platform-dependent. **Example**:: // This throws a SystemError with the description // cannot open file 'madeup': No such file or directory // or similar (system message may vary). const char *filename = "madeup"; std::FILE *file = std::fopen(filename, "r"); if (!file) throw fmt::SystemError(errno, "cannot open file '{}'", filename); \endrst */ SystemError(int error_code, CStringRef message) { init(error_code, message, ArgList()); } FMT_VARIADIC_CTOR(SystemError, init, int, CStringRef) int error_code() const { return error_code_; } }; /** \rst This template provides operations for formatting and writing data into a character stream. The output is stored in a buffer provided by a subclass such as :class:`fmt::BasicMemoryWriter`. You can use one of the following typedefs for common character types: +---------+----------------------+ | Type | Definition | +=========+======================+ | Writer | BasicWriter | +---------+----------------------+ | WWriter | BasicWriter | +---------+----------------------+ \endrst */ template class BasicWriter { private: // Output buffer. Buffer &buffer_; FMT_DISALLOW_COPY_AND_ASSIGN(BasicWriter); typedef typename internal::CharTraits::CharPtr CharPtr; #if FMT_SECURE_SCL // Returns pointer value. static Char *get(CharPtr p) { return p.base(); } #else static Char *get(Char *p) { return p; } #endif // Fills the padding around the content and returns the pointer to the // content area. static CharPtr fill_padding(CharPtr buffer, unsigned total_size, std::size_t content_size, wchar_t fill); // Grows the buffer by n characters and returns a pointer to the newly // allocated area. CharPtr grow_buffer(std::size_t n) { std::size_t size = buffer_.size(); buffer_.resize(size + n); return internal::make_ptr(&buffer_[size], n); } // Writes an unsigned decimal integer. template Char *write_unsigned_decimal(UInt value, unsigned prefix_size = 0) { unsigned num_digits = internal::count_digits(value); Char *ptr = get(grow_buffer(prefix_size + num_digits)); internal::format_decimal(ptr + prefix_size, value, num_digits); return ptr; } // Writes a decimal integer. template void write_decimal(Int value) { typedef typename internal::IntTraits::MainType MainType; MainType abs_value = static_cast(value); if (internal::is_negative(value)) { abs_value = 0 - abs_value; *write_unsigned_decimal(abs_value, 1) = '-'; } else { write_unsigned_decimal(abs_value, 0); } } // Prepare a buffer for integer formatting. CharPtr prepare_int_buffer(unsigned num_digits, const EmptySpec &, const char *prefix, unsigned prefix_size) { unsigned size = prefix_size + num_digits; CharPtr p = grow_buffer(size); std::uninitialized_copy(prefix, prefix + prefix_size, p); return p + size - 1; } template CharPtr prepare_int_buffer(unsigned num_digits, const Spec &spec, const char *prefix, unsigned prefix_size); // Formats an integer. template void write_int(T value, Spec spec); // Formats a floating-point number (double or long double). template void write_double(T value, const FormatSpec &spec); // Writes a formatted string. template CharPtr write_str(const StrChar *s, std::size_t size, const AlignSpec &spec); template void write_str(const internal::Arg::StringValue &str, const FormatSpec &spec); // This following methods are private to disallow writing wide characters // and strings to a char stream. If you want to print a wide string as a // pointer as std::ostream does, cast it to const void*. // Do not implement! void operator<<(typename internal::WCharHelper::Unsupported); void operator<<( typename internal::WCharHelper::Unsupported); // Appends floating-point length specifier to the format string. // The second argument is only used for overload resolution. void append_float_length(Char *&format_ptr, long double) { *format_ptr++ = 'L'; } template void append_float_length(Char *&, T) {} template friend class internal::ArgFormatterBase; friend class internal::PrintfArgFormatter; protected: /** Constructs a ``BasicWriter`` object. */ explicit BasicWriter(Buffer &b): buffer_(b) {} public: /** \rst Destroys a ``BasicWriter`` object. \endrst */ virtual ~BasicWriter() {} /** Returns the total number of characters written. */ std::size_t size() const { return buffer_.size(); } /** Returns a pointer to the output buffer content. No terminating null character is appended. */ const Char *data() const FMT_NOEXCEPT { return &buffer_[0]; } /** Returns a pointer to the output buffer content with terminating null character appended. */ const Char *c_str() const { std::size_t size = buffer_.size(); buffer_.reserve(size + 1); buffer_[size] = '\0'; return &buffer_[0]; } /** \rst Returns the content of the output buffer as an `std::string`. \endrst */ std::basic_string str() const { return std::basic_string(&buffer_[0], buffer_.size()); } /** \rst Writes formatted data. *args* is an argument list representing arbitrary arguments. **Example**:: MemoryWriter out; out.write("Current point:\n"); out.write("({:+f}, {:+f})", -3.14, 3.14); This will write the following output to the ``out`` object: .. code-block:: none Current point: (-3.140000, +3.140000) The output can be accessed using :func:`data()`, :func:`c_str` or :func:`str` methods. See also :ref:`syntax`. \endrst */ void write(BasicCStringRef format, ArgList args) { BasicFormatter(args, *this).format(format); } FMT_VARIADIC_VOID(write, BasicCStringRef) BasicWriter &operator<<(int value) { write_decimal(value); return *this; } BasicWriter &operator<<(unsigned value) { return *this << IntFormatSpec(value); } BasicWriter &operator<<(long value) { write_decimal(value); return *this; } BasicWriter &operator<<(unsigned long value) { return *this << IntFormatSpec(value); } BasicWriter &operator<<(LongLong value) { write_decimal(value); return *this; } /** \rst Formats *value* and writes it to the stream. \endrst */ BasicWriter &operator<<(ULongLong value) { return *this << IntFormatSpec(value); } BasicWriter &operator<<(double value) { write_double(value, FormatSpec()); return *this; } /** \rst Formats *value* using the general format for floating-point numbers (``'g'``) and writes it to the stream. \endrst */ BasicWriter &operator<<(long double value) { write_double(value, FormatSpec()); return *this; } /** Writes a character to the stream. */ BasicWriter &operator<<(char value) { buffer_.push_back(value); return *this; } BasicWriter &operator<<( typename internal::WCharHelper::Supported value) { buffer_.push_back(value); return *this; } /** \rst Writes *value* to the stream. \endrst */ BasicWriter &operator<<(fmt::BasicStringRef value) { const Char *str = value.data(); buffer_.append(str, str + value.size()); return *this; } BasicWriter &operator<<( typename internal::WCharHelper::Supported value) { const char *str = value.data(); buffer_.append(str, str + value.size()); return *this; } template BasicWriter &operator<<(IntFormatSpec spec) { internal::CharTraits::convert(FillChar()); write_int(spec.value(), spec); return *this; } template BasicWriter &operator<<(const StrFormatSpec &spec) { const StrChar *s = spec.str(); write_str(s, std::char_traits::length(s), spec); return *this; } void clear() FMT_NOEXCEPT { buffer_.clear(); } }; template template typename BasicWriter::CharPtr BasicWriter::write_str( const StrChar *s, std::size_t size, const AlignSpec &spec) { CharPtr out = CharPtr(); if (spec.width() > size) { out = grow_buffer(spec.width()); Char fill = internal::CharTraits::cast(spec.fill()); if (spec.align() == ALIGN_RIGHT) { std::uninitialized_fill_n(out, spec.width() - size, fill); out += spec.width() - size; } else if (spec.align() == ALIGN_CENTER) { out = fill_padding(out, spec.width(), size, fill); } else { std::uninitialized_fill_n(out + size, spec.width() - size, fill); } } else { out = grow_buffer(size); } std::uninitialized_copy(s, s + size, out); return out; } template template void BasicWriter::write_str( const internal::Arg::StringValue &s, const FormatSpec &spec) { // Check if StrChar is convertible to Char. internal::CharTraits::convert(StrChar()); if (spec.type_ && spec.type_ != 's') internal::report_unknown_type(spec.type_, "string"); const StrChar *str_value = s.value; std::size_t str_size = s.size; if (str_size == 0) { if (!str_value) { FMT_THROW(FormatError("string pointer is null")); return; } } std::size_t precision = static_cast(spec.precision_); if (spec.precision_ >= 0 && precision < str_size) str_size = precision; write_str(str_value, str_size, spec); } template typename BasicWriter::CharPtr BasicWriter::fill_padding( CharPtr buffer, unsigned total_size, std::size_t content_size, wchar_t fill) { std::size_t padding = total_size - content_size; std::size_t left_padding = padding / 2; Char fill_char = internal::CharTraits::cast(fill); std::uninitialized_fill_n(buffer, left_padding, fill_char); buffer += left_padding; CharPtr content = buffer; std::uninitialized_fill_n(buffer + content_size, padding - left_padding, fill_char); return content; } template template typename BasicWriter::CharPtr BasicWriter::prepare_int_buffer( unsigned num_digits, const Spec &spec, const char *prefix, unsigned prefix_size) { unsigned width = spec.width(); Alignment align = spec.align(); Char fill = internal::CharTraits::cast(spec.fill()); if (spec.precision() > static_cast(num_digits)) { // Octal prefix '0' is counted as a digit, so ignore it if precision // is specified. if (prefix_size > 0 && prefix[prefix_size - 1] == '0') --prefix_size; unsigned number_size = prefix_size + internal::to_unsigned(spec.precision()); AlignSpec subspec(number_size, '0', ALIGN_NUMERIC); if (number_size >= width) return prepare_int_buffer(num_digits, subspec, prefix, prefix_size); buffer_.reserve(width); unsigned fill_size = width - number_size; if (align != ALIGN_LEFT) { CharPtr p = grow_buffer(fill_size); std::uninitialized_fill(p, p + fill_size, fill); } CharPtr result = prepare_int_buffer( num_digits, subspec, prefix, prefix_size); if (align == ALIGN_LEFT) { CharPtr p = grow_buffer(fill_size); std::uninitialized_fill(p, p + fill_size, fill); } return result; } unsigned size = prefix_size + num_digits; if (width <= size) { CharPtr p = grow_buffer(size); std::uninitialized_copy(prefix, prefix + prefix_size, p); return p + size - 1; } CharPtr p = grow_buffer(width); CharPtr end = p + width; if (align == ALIGN_LEFT) { std::uninitialized_copy(prefix, prefix + prefix_size, p); p += size; std::uninitialized_fill(p, end, fill); } else if (align == ALIGN_CENTER) { p = fill_padding(p, width, size, fill); std::uninitialized_copy(prefix, prefix + prefix_size, p); p += size; } else { if (align == ALIGN_NUMERIC) { if (prefix_size != 0) { p = std::uninitialized_copy(prefix, prefix + prefix_size, p); size -= prefix_size; } } else { std::uninitialized_copy(prefix, prefix + prefix_size, end - size); } std::uninitialized_fill(p, end - size, fill); p = end; } return p - 1; } template template void BasicWriter::write_int(T value, Spec spec) { unsigned prefix_size = 0; typedef typename internal::IntTraits::MainType UnsignedType; UnsignedType abs_value = static_cast(value); char prefix[4] = ""; if (internal::is_negative(value)) { prefix[0] = '-'; ++prefix_size; abs_value = 0 - abs_value; } else if (spec.flag(SIGN_FLAG)) { prefix[0] = spec.flag(PLUS_FLAG) ? '+' : ' '; ++prefix_size; } switch (spec.type()) { case 0: case 'd': { unsigned num_digits = internal::count_digits(abs_value); CharPtr p = prepare_int_buffer( num_digits, spec, prefix, prefix_size) + 1 - num_digits; internal::format_decimal(get(p), abs_value, num_digits); break; } case 'x': case 'X': { UnsignedType n = abs_value; if (spec.flag(HASH_FLAG)) { prefix[prefix_size++] = '0'; prefix[prefix_size++] = spec.type(); } unsigned num_digits = 0; do { ++num_digits; } while ((n >>= 4) != 0); Char *p = get(prepare_int_buffer( num_digits, spec, prefix, prefix_size)); n = abs_value; const char *digits = spec.type() == 'x' ? "0123456789abcdef" : "0123456789ABCDEF"; do { *p-- = digits[n & 0xf]; } while ((n >>= 4) != 0); break; } case 'b': case 'B': { UnsignedType n = abs_value; if (spec.flag(HASH_FLAG)) { prefix[prefix_size++] = '0'; prefix[prefix_size++] = spec.type(); } unsigned num_digits = 0; do { ++num_digits; } while ((n >>= 1) != 0); Char *p = get(prepare_int_buffer(num_digits, spec, prefix, prefix_size)); n = abs_value; do { *p-- = static_cast('0' + (n & 1)); } while ((n >>= 1) != 0); break; } case 'o': { UnsignedType n = abs_value; if (spec.flag(HASH_FLAG)) prefix[prefix_size++] = '0'; unsigned num_digits = 0; do { ++num_digits; } while ((n >>= 3) != 0); Char *p = get(prepare_int_buffer(num_digits, spec, prefix, prefix_size)); n = abs_value; do { *p-- = static_cast('0' + (n & 7)); } while ((n >>= 3) != 0); break; } default: internal::report_unknown_type( spec.type(), spec.flag(CHAR_FLAG) ? "char" : "integer"); break; } } template template void BasicWriter::write_double(T value, const FormatSpec &spec) { // Check type. char type = spec.type(); bool upper = false; switch (type) { case 0: type = 'g'; break; case 'e': case 'f': case 'g': case 'a': break; case 'F': #ifdef _MSC_VER // MSVC's printf doesn't support 'F'. type = 'f'; #endif // Fall through. case 'E': case 'G': case 'A': upper = true; break; default: internal::report_unknown_type(type, "double"); break; } char sign = 0; // Use isnegative instead of value < 0 because the latter is always // false for NaN. if (internal::FPUtil::isnegative(static_cast(value))) { sign = '-'; value = -value; } else if (spec.flag(SIGN_FLAG)) { sign = spec.flag(PLUS_FLAG) ? '+' : ' '; } if (internal::FPUtil::isnotanumber(value)) { // Format NaN ourselves because sprintf's output is not consistent // across platforms. std::size_t nan_size = 4; const char *nan = upper ? " NAN" : " nan"; if (!sign) { --nan_size; ++nan; } CharPtr out = write_str(nan, nan_size, spec); if (sign) *out = sign; return; } if (internal::FPUtil::isinfinity(value)) { // Format infinity ourselves because sprintf's output is not consistent // across platforms. std::size_t inf_size = 4; const char *inf = upper ? " INF" : " inf"; if (!sign) { --inf_size; ++inf; } CharPtr out = write_str(inf, inf_size, spec); if (sign) *out = sign; return; } std::size_t offset = buffer_.size(); unsigned width = spec.width(); if (sign) { buffer_.reserve(buffer_.size() + (width > 1u ? width : 1u)); if (width > 0) --width; ++offset; } // Build format string. enum { MAX_FORMAT_SIZE = 10 }; // longest format: %#-*.*Lg Char format[MAX_FORMAT_SIZE]; Char *format_ptr = format; *format_ptr++ = '%'; unsigned width_for_sprintf = width; if (spec.flag(HASH_FLAG)) *format_ptr++ = '#'; if (spec.align() == ALIGN_CENTER) { width_for_sprintf = 0; } else { if (spec.align() == ALIGN_LEFT) *format_ptr++ = '-'; if (width != 0) *format_ptr++ = '*'; } if (spec.precision() >= 0) { *format_ptr++ = '.'; *format_ptr++ = '*'; } append_float_length(format_ptr, value); *format_ptr++ = type; *format_ptr = '\0'; // Format using snprintf. Char fill = internal::CharTraits::cast(spec.fill()); unsigned n = 0; Char *start = 0; for (;;) { std::size_t buffer_size = buffer_.capacity() - offset; #ifdef _MSC_VER // MSVC's vsnprintf_s doesn't work with zero size, so reserve // space for at least one extra character to make the size non-zero. // Note that the buffer's capacity will increase by more than 1. if (buffer_size == 0) { buffer_.reserve(offset + 1); buffer_size = buffer_.capacity() - offset; } #endif start = &buffer_[offset]; int result = internal::CharTraits::format_float( start, buffer_size, format, width_for_sprintf, spec.precision(), value); if (result >= 0) { n = internal::to_unsigned(result); if (offset + n < buffer_.capacity()) break; // The buffer is large enough - continue with formatting. buffer_.reserve(offset + n + 1); } else { // If result is negative we ask to increase the capacity by at least 1, // but as std::vector, the buffer grows exponentially. buffer_.reserve(buffer_.capacity() + 1); } } if (sign) { if ((spec.align() != ALIGN_RIGHT && spec.align() != ALIGN_DEFAULT) || *start != ' ') { *(start - 1) = sign; sign = 0; } else { *(start - 1) = fill; } ++n; } if (spec.align() == ALIGN_CENTER && spec.width() > n) { width = spec.width(); CharPtr p = grow_buffer(width); std::memmove(get(p) + (width - n) / 2, get(p), n * sizeof(Char)); fill_padding(p, spec.width(), n, fill); return; } if (spec.fill() != ' ' || sign) { while (*start == ' ') *start++ = fill; if (sign) *(start - 1) = sign; } grow_buffer(n); } /** \rst This class template provides operations for formatting and writing data into a character stream. The output is stored in a memory buffer that grows dynamically. You can use one of the following typedefs for common character types and the standard allocator: +---------------+-----------------------------------------------------+ | Type | Definition | +===============+=====================================================+ | MemoryWriter | BasicMemoryWriter> | +---------------+-----------------------------------------------------+ | WMemoryWriter | BasicMemoryWriter> | +---------------+-----------------------------------------------------+ **Example**:: MemoryWriter out; out << "The answer is " << 42 << "\n"; out.write("({:+f}, {:+f})", -3.14, 3.14); This will write the following output to the ``out`` object: .. code-block:: none The answer is 42 (-3.140000, +3.140000) The output can be converted to an ``std::string`` with ``out.str()`` or accessed as a C string with ``out.c_str()``. \endrst */ template > class BasicMemoryWriter: public BasicWriter { private: internal::MemoryBuffer buffer_; public: explicit BasicMemoryWriter(const Allocator& alloc = Allocator()) : BasicWriter(buffer_), buffer_(alloc) {} #if FMT_USE_RVALUE_REFERENCES /** \rst Constructs a :class:`fmt::BasicMemoryWriter` object moving the content of the other object to it. \endrst */ BasicMemoryWriter(BasicMemoryWriter &&other) : BasicWriter(buffer_), buffer_(std::move(other.buffer_)) {} /** \rst Moves the content of the other ``BasicMemoryWriter`` object to this one. \endrst */ BasicMemoryWriter &operator=(BasicMemoryWriter &&other) { buffer_ = std::move(other.buffer_); return *this; } #endif }; typedef BasicMemoryWriter MemoryWriter; typedef BasicMemoryWriter WMemoryWriter; /** \rst This class template provides operations for formatting and writing data into a fixed-size array. For writing into a dynamically growing buffer use :class:`fmt::BasicMemoryWriter`. Any write method will throw ``std::runtime_error`` if the output doesn't fit into the array. You can use one of the following typedefs for common character types: +--------------+---------------------------+ | Type | Definition | +==============+===========================+ | ArrayWriter | BasicArrayWriter | +--------------+---------------------------+ | WArrayWriter | BasicArrayWriter | +--------------+---------------------------+ \endrst */ template class BasicArrayWriter: public BasicWriter { private: internal::FixedBuffer buffer_; public: /** \rst Constructs a :class:`fmt::BasicArrayWriter` object for *array* of the given size. \endrst */ BasicArrayWriter(Char *array, std::size_t size) : BasicWriter(buffer_), buffer_(array, size) {} /** \rst Constructs a :class:`fmt::BasicArrayWriter` object for *array* of the size known at compile time. \endrst */ template explicit BasicArrayWriter(Char(&array)[SIZE]) : BasicWriter(buffer_), buffer_(array, SIZE) {} }; typedef BasicArrayWriter ArrayWriter; typedef BasicArrayWriter WArrayWriter; // Formats a value. template void format(BasicFormatter &f, const Char *&format_str, const T &value) { internal::MemoryBuffer buffer; internal::FormatBuf format_buf(buffer); std::basic_ostream output(&format_buf); output << value; BasicStringRef str(&buffer[0], format_buf.size()); typedef internal::MakeArg< BasicFormatter > MakeArg; format_str = f.format(format_str, MakeArg(str)); } // Reports a system error without throwing an exception. // Can be used to report errors from destructors. FMT_API void report_system_error(int error_code, StringRef message) FMT_NOEXCEPT; #if FMT_USE_WINDOWS_H /** A Windows error. */ class WindowsError: public SystemError { private: FMT_API void init(int error_code, CStringRef format_str, ArgList args); public: /** \rst Constructs a :class:`fmt::WindowsError` object with the description of the form .. parsed-literal:: **: ** where ** is the formatted message and ** is the system message corresponding to the error code. *error_code* is a Windows error code as given by ``GetLastError``. If *error_code* is not a valid error code such as -1, the system message will look like "error -1". **Example**:: // This throws a WindowsError with the description // cannot open file 'madeup': The system cannot find the file specified. // or similar (system message may vary). const char *filename = "madeup"; LPOFSTRUCT of = LPOFSTRUCT(); HFILE file = OpenFile(filename, &of, OF_READ); if (file == HFILE_ERROR) { throw fmt::WindowsError(GetLastError(), "cannot open file '{}'", filename); } \endrst */ WindowsError(int error_code, CStringRef message) { init(error_code, message, ArgList()); } FMT_VARIADIC_CTOR(WindowsError, init, int, CStringRef) }; // Reports a Windows error without throwing an exception. // Can be used to report errors from destructors. FMT_API void report_windows_error(int error_code, StringRef message) FMT_NOEXCEPT; #endif enum Color { BLACK, RED, GREEN, YELLOW, BLUE, MAGENTA, CYAN, WHITE }; /** Formats a string and prints it to stdout using ANSI escape sequences to specify color (experimental). Example: print_colored(fmt::RED, "Elapsed time: {0:.2f} seconds", 1.23); */ FMT_API void print_colored(Color c, CStringRef format, ArgList args); /** \rst Formats arguments and returns the result as a string. **Example**:: std::string message = format("The answer is {}", 42); \endrst */ inline std::string format(CStringRef format_str, ArgList args) { MemoryWriter w; w.write(format_str, args); return w.str(); } inline std::wstring format(WCStringRef format_str, ArgList args) { WMemoryWriter w; w.write(format_str, args); return w.str(); } /** \rst Prints formatted data to the file *f*. **Example**:: print(stderr, "Don't {}!", "panic"); \endrst */ FMT_API void print(std::FILE *f, CStringRef format_str, ArgList args); /** \rst Prints formatted data to ``stdout``. **Example**:: print("Elapsed time: {0:.2f} seconds", 1.23); \endrst */ FMT_API void print(CStringRef format_str, ArgList args); template void printf(BasicWriter &w, BasicCStringRef format, ArgList args) { internal::PrintfFormatter(args).format(w, format); } /** \rst Formats arguments and returns the result as a string. **Example**:: std::string message = fmt::sprintf("The answer is %d", 42); \endrst */ inline std::string fmt_sprintf(CStringRef format, ArgList args) { MemoryWriter w; printf(w, format, args); return w.str(); } inline std::wstring fmt_sprintf(WCStringRef format, ArgList args) { WMemoryWriter w; printf(w, format, args); return w.str(); } /** \rst Prints formatted data to the file *f*. **Example**:: fmt::fprintf(stderr, "Don't %s!", "panic"); \endrst */ FMT_API int fprintf(std::FILE *f, CStringRef format, ArgList args); /** \rst Prints formatted data to ``stdout``. **Example**:: fmt::printf("Elapsed time: %.2f seconds", 1.23); \endrst */ inline int printf(CStringRef format, ArgList args) { return fprintf(stdout, format, args); } /** Fast integer formatter. */ class FormatInt { private: // Buffer should be large enough to hold all digits (digits10 + 1), // a sign and a null character. enum { BUFFER_SIZE = std::numeric_limits::digits10 + 3 }; mutable char buffer_[BUFFER_SIZE]; char *str_; // Formats value in reverse and returns the number of digits. char *format_decimal(ULongLong value) { char *buffer_end = buffer_ + BUFFER_SIZE - 1; while (value >= 100) { // Integer division is slow so do it for a group of two digits instead // of for every digit. The idea comes from the talk by Alexandrescu // "Three Optimization Tips for C++". See speed-test for a comparison. unsigned index = static_cast((value % 100) * 2); value /= 100; *--buffer_end = internal::Data::DIGITS[index + 1]; *--buffer_end = internal::Data::DIGITS[index]; } if (value < 10) { *--buffer_end = static_cast('0' + value); return buffer_end; } unsigned index = static_cast(value * 2); *--buffer_end = internal::Data::DIGITS[index + 1]; *--buffer_end = internal::Data::DIGITS[index]; return buffer_end; } void FormatSigned(LongLong value) { ULongLong abs_value = static_cast(value); bool negative = value < 0; if (negative) abs_value = 0 - abs_value; str_ = format_decimal(abs_value); if (negative) *--str_ = '-'; } public: explicit FormatInt(int value) { FormatSigned(value); } explicit FormatInt(long value) { FormatSigned(value); } explicit FormatInt(LongLong value) { FormatSigned(value); } explicit FormatInt(unsigned value): str_(format_decimal(value)) {} explicit FormatInt(unsigned long value): str_(format_decimal(value)) {} explicit FormatInt(ULongLong value): str_(format_decimal(value)) {} /** Returns the number of characters written to the output buffer. */ std::size_t size() const { return internal::to_unsigned(buffer_ - str_ + BUFFER_SIZE - 1); } /** Returns a pointer to the output buffer content. No terminating null character is appended. */ const char *data() const { return str_; } /** Returns a pointer to the output buffer content with terminating null character appended. */ const char *c_str() const { buffer_[BUFFER_SIZE - 1] = '\0'; return str_; } /** \rst Returns the content of the output buffer as an ``std::string``. \endrst */ std::string str() const { return std::string(str_, size()); } }; // Formats a decimal integer value writing into buffer and returns // a pointer to the end of the formatted string. This function doesn't // write a terminating null character. template inline void format_decimal(char *&buffer, T value) { typedef typename internal::IntTraits::MainType MainType; MainType abs_value = static_cast(value); if (internal::is_negative(value)) { *buffer++ = '-'; abs_value = 0 - abs_value; } if (abs_value < 100) { if (abs_value < 10) { *buffer++ = static_cast('0' + abs_value); return; } unsigned index = static_cast(abs_value * 2); *buffer++ = internal::Data::DIGITS[index]; *buffer++ = internal::Data::DIGITS[index + 1]; return; } unsigned num_digits = internal::count_digits(abs_value); internal::format_decimal(buffer, abs_value, num_digits); buffer += num_digits; } /** \rst Returns a named argument for formatting functions. **Example**:: print("Elapsed time: {s:.2f} seconds", arg("s", 1.23)); \endrst */ template inline internal::NamedArg arg(StringRef name, const T &arg) { return internal::NamedArg(name, arg); } template inline internal::NamedArg arg(WStringRef name, const T &arg) { return internal::NamedArg(name, arg); } // The following two functions are deleted intentionally to disable // nested named arguments as in ``format("{}", arg("a", arg("b", 42)))``. template void arg(StringRef, const internal::NamedArg&) FMT_DELETED_OR_UNDEFINED; template void arg(WStringRef, const internal::NamedArg&) FMT_DELETED_OR_UNDEFINED; } #if FMT_GCC_VERSION // Use the system_header pragma to suppress warnings about variadic macros // because suppressing -Wvariadic-macros with the diagnostic pragma doesn't // work. It is used at the end because we want to suppress as little warnings // as possible. # pragma GCC system_header #endif // This is used to work around VC++ bugs in handling variadic macros. #define FMT_EXPAND(args) args // Returns the number of arguments. // Based on https://groups.google.com/forum/#!topic/comp.std.c/d-6Mj5Lko_s. #define FMT_NARG(...) FMT_NARG_(__VA_ARGS__, FMT_RSEQ_N()) #define FMT_NARG_(...) FMT_EXPAND(FMT_ARG_N(__VA_ARGS__)) #define FMT_ARG_N(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, N, ...) N #define FMT_RSEQ_N() 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 #define FMT_CONCAT(a, b) a##b #define FMT_FOR_EACH_(N, f, ...) \ FMT_EXPAND(FMT_CONCAT(FMT_FOR_EACH, N)(f, __VA_ARGS__)) #define FMT_FOR_EACH(f, ...) \ FMT_EXPAND(FMT_FOR_EACH_(FMT_NARG(__VA_ARGS__), f, __VA_ARGS__)) #define FMT_ADD_ARG_NAME(type, index) type arg##index #define FMT_GET_ARG_NAME(type, index) arg##index #if FMT_USE_VARIADIC_TEMPLATES # define FMT_VARIADIC_(Char, ReturnType, func, call, ...) \ template \ ReturnType func(FMT_FOR_EACH(FMT_ADD_ARG_NAME, __VA_ARGS__), \ const Args & ... args) { \ typedef fmt::internal::ArgArray ArgArray; \ typename ArgArray::Type array{ \ ArgArray::template make >(args)...}; \ call(FMT_FOR_EACH(FMT_GET_ARG_NAME, __VA_ARGS__), \ fmt::ArgList(fmt::internal::make_type(args...), array)); \ } #else // Defines a wrapper for a function taking __VA_ARGS__ arguments // and n additional arguments of arbitrary types. # define FMT_WRAP(Char, ReturnType, func, call, n, ...) \ template \ inline ReturnType func(FMT_FOR_EACH(FMT_ADD_ARG_NAME, __VA_ARGS__), \ FMT_GEN(n, FMT_MAKE_ARG)) { \ fmt::internal::ArgArray::Type arr; \ FMT_GEN(n, FMT_ASSIGN_##Char); \ call(FMT_FOR_EACH(FMT_GET_ARG_NAME, __VA_ARGS__), fmt::ArgList( \ fmt::internal::make_type(FMT_GEN(n, FMT_MAKE_REF2)), arr)); \ } # define FMT_VARIADIC_(Char, ReturnType, func, call, ...) \ inline ReturnType func(FMT_FOR_EACH(FMT_ADD_ARG_NAME, __VA_ARGS__)) { \ call(FMT_FOR_EACH(FMT_GET_ARG_NAME, __VA_ARGS__), fmt::ArgList()); \ } \ FMT_WRAP(Char, ReturnType, func, call, 1, __VA_ARGS__) \ FMT_WRAP(Char, ReturnType, func, call, 2, __VA_ARGS__) \ FMT_WRAP(Char, ReturnType, func, call, 3, __VA_ARGS__) \ FMT_WRAP(Char, ReturnType, func, call, 4, __VA_ARGS__) \ FMT_WRAP(Char, ReturnType, func, call, 5, __VA_ARGS__) \ FMT_WRAP(Char, ReturnType, func, call, 6, __VA_ARGS__) \ FMT_WRAP(Char, ReturnType, func, call, 7, __VA_ARGS__) \ FMT_WRAP(Char, ReturnType, func, call, 8, __VA_ARGS__) \ FMT_WRAP(Char, ReturnType, func, call, 9, __VA_ARGS__) \ FMT_WRAP(Char, ReturnType, func, call, 10, __VA_ARGS__) \ FMT_WRAP(Char, ReturnType, func, call, 11, __VA_ARGS__) \ FMT_WRAP(Char, ReturnType, func, call, 12, __VA_ARGS__) \ FMT_WRAP(Char, ReturnType, func, call, 13, __VA_ARGS__) \ FMT_WRAP(Char, ReturnType, func, call, 14, __VA_ARGS__) \ FMT_WRAP(Char, ReturnType, func, call, 15, __VA_ARGS__) #endif // FMT_USE_VARIADIC_TEMPLATES /** \rst Defines a variadic function with the specified return type, function name and argument types passed as variable arguments to this macro. **Example**:: void print_error(const char *file, int line, const char *format, fmt::ArgList args) { fmt::print("{}: {}: ", file, line); fmt::print(format, args); } FMT_VARIADIC(void, print_error, const char *, int, const char *) ``FMT_VARIADIC`` is used for compatibility with legacy C++ compilers that don't implement variadic templates. You don't have to use this macro if you don't need legacy compiler support and can use variadic templates directly:: template void print_error(const char *file, int line, const char *format, const Args & ... args) { fmt::print("{}: {}: ", file, line); fmt::print(format, args...); } \endrst */ #define FMT_VARIADIC(ReturnType, func, ...) \ FMT_VARIADIC_(char, ReturnType, func, return func, __VA_ARGS__) #define FMT_VARIADIC_W(ReturnType, func, ...) \ FMT_VARIADIC_(wchar_t, ReturnType, func, return func, __VA_ARGS__) #define FMT_CAPTURE_ARG_(id, index) ::fmt::arg(#id, id) #define FMT_CAPTURE_ARG_W_(id, index) ::fmt::arg(L###id, id) /** \rst Convenient macro to capture the arguments' names and values into several ``fmt::arg(name, value)``. **Example**:: int x = 1, y = 2; print("point: ({x}, {y})", FMT_CAPTURE(x, y)); // same as: // print("point: ({x}, {y})", arg("x", x), arg("y", y)); \endrst */ #define FMT_CAPTURE(...) FMT_FOR_EACH(FMT_CAPTURE_ARG_, __VA_ARGS__) #define FMT_CAPTURE_W(...) FMT_FOR_EACH(FMT_CAPTURE_ARG_W_, __VA_ARGS__) namespace fmt { FMT_VARIADIC(std::string, format, CStringRef) FMT_VARIADIC_W(std::wstring, format, WCStringRef) FMT_VARIADIC(void, print, CStringRef) FMT_VARIADIC(void, print, std::FILE *, CStringRef) FMT_VARIADIC(void, print_colored, Color, CStringRef) FMT_VARIADIC(std::string, fmt_sprintf, CStringRef) FMT_VARIADIC_W(std::wstring, fmt_sprintf, WCStringRef) FMT_VARIADIC(int, printf, CStringRef) FMT_VARIADIC(int, fprintf, std::FILE *, CStringRef) #if FMT_USE_IOSTREAMS /** \rst Prints formatted data to the stream *os*. **Example**:: print(cerr, "Don't {}!", "panic"); \endrst */ FMT_API void print(std::ostream &os, CStringRef format_str, ArgList args); FMT_VARIADIC(void, print, std::ostream &, CStringRef) /** \rst Prints formatted data to the stream *os*. **Example**:: fprintf(cerr, "Don't %s!", "panic"); \endrst */ FMT_API int fprintf(std::ostream &os, CStringRef format_str, ArgList args); FMT_VARIADIC(int, fprintf, std::ostream &, CStringRef) #endif namespace internal { template inline bool is_name_start(Char c) { return ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || '_' == c; } // Parses an unsigned integer advancing s to the end of the parsed input. // This function assumes that the first character of s is a digit. template unsigned parse_nonnegative_int(const Char *&s) { assert('0' <= *s && *s <= '9'); unsigned value = 0; do { unsigned new_value = value * 10 + (*s++ - '0'); // Check if value wrapped around. if (new_value < value) { value = (std::numeric_limits::max)(); break; } value = new_value; } while ('0' <= *s && *s <= '9'); // Convert to unsigned to prevent a warning. unsigned max_int = (std::numeric_limits::max)(); if (value > max_int) FMT_THROW(FormatError("number is too big")); return value; } inline void require_numeric_argument(const Arg &arg, char spec) { if (arg.type > Arg::LAST_NUMERIC_TYPE) { std::string message = fmt::format("format specifier '{}' requires numeric argument", spec); FMT_THROW(fmt::FormatError(message)); } } template void check_sign(const Char *&s, const Arg &arg) { char sign = static_cast(*s); require_numeric_argument(arg, sign); if (arg.type == Arg::UINT || arg.type == Arg::ULONG_LONG) { FMT_THROW(FormatError(fmt::format( "format specifier '{}' requires signed argument", sign))); } ++s; } } // namespace internal template inline internal::Arg BasicFormatter::get_arg( BasicStringRef arg_name, const char *&error) { if (check_no_auto_index(error)) { map_.init(args()); const internal::Arg *arg = map_.find(arg_name); if (arg) return *arg; error = "argument not found"; } return internal::Arg(); } template inline internal::Arg BasicFormatter::parse_arg_index(const Char *&s) { const char *error = 0; internal::Arg arg = *s < '0' || *s > '9' ? next_arg(error) : get_arg(internal::parse_nonnegative_int(s), error); if (error) { FMT_THROW(FormatError( *s != '}' && *s != ':' ? "invalid format string" : error)); } return arg; } template inline internal::Arg BasicFormatter::parse_arg_name(const Char *&s) { assert(internal::is_name_start(*s)); const Char *start = s; Char c; do { c = *++s; } while (internal::is_name_start(c) || ('0' <= c && c <= '9')); const char *error = 0; internal::Arg arg = get_arg(BasicStringRef(start, s - start), error); if (error) FMT_THROW(FormatError(error)); return arg; } template const Char *BasicFormatter::format( const Char *&format_str, const internal::Arg &arg) { using internal::Arg; const Char *s = format_str; FormatSpec spec; if (*s == ':') { if (arg.type == Arg::CUSTOM) { arg.custom.format(this, arg.custom.value, &s); return s; } ++s; // Parse fill and alignment. if (Char c = *s) { const Char *p = s + 1; spec.align_ = ALIGN_DEFAULT; do { switch (*p) { case '<': spec.align_ = ALIGN_LEFT; break; case '>': spec.align_ = ALIGN_RIGHT; break; case '=': spec.align_ = ALIGN_NUMERIC; break; case '^': spec.align_ = ALIGN_CENTER; break; } if (spec.align_ != ALIGN_DEFAULT) { if (p != s) { if (c == '}') break; if (c == '{') FMT_THROW(FormatError("invalid fill character '{'")); s += 2; spec.fill_ = c; } else ++s; if (spec.align_ == ALIGN_NUMERIC) require_numeric_argument(arg, '='); break; } } while (--p >= s); } // Parse sign. switch (*s) { case '+': check_sign(s, arg); spec.flags_ |= SIGN_FLAG | PLUS_FLAG; break; case '-': check_sign(s, arg); spec.flags_ |= MINUS_FLAG; break; case ' ': check_sign(s, arg); spec.flags_ |= SIGN_FLAG; break; } if (*s == '#') { require_numeric_argument(arg, '#'); spec.flags_ |= HASH_FLAG; ++s; } // Parse zero flag. if (*s == '0') { require_numeric_argument(arg, '0'); spec.align_ = ALIGN_NUMERIC; spec.fill_ = '0'; ++s; } // Parse width. if ('0' <= *s && *s <= '9') { spec.width_ = internal::parse_nonnegative_int(s); } else if (*s == '{') { ++s; Arg width_arg = internal::is_name_start(*s) ? parse_arg_name(s) : parse_arg_index(s); if (*s++ != '}') FMT_THROW(FormatError("invalid format string")); ULongLong value = 0; switch (width_arg.type) { case Arg::INT: if (width_arg.int_value < 0) FMT_THROW(FormatError("negative width")); value = width_arg.int_value; break; case Arg::UINT: value = width_arg.uint_value; break; case Arg::LONG_LONG: if (width_arg.long_long_value < 0) FMT_THROW(FormatError("negative width")); value = width_arg.long_long_value; break; case Arg::ULONG_LONG: value = width_arg.ulong_long_value; break; default: FMT_THROW(FormatError("width is not integer")); } if (value >(std::numeric_limits::max)()) FMT_THROW(FormatError("number is too big")); spec.width_ = static_cast(value); } // Parse precision. if (*s == '.') { ++s; spec.precision_ = 0; if ('0' <= *s && *s <= '9') { spec.precision_ = internal::parse_nonnegative_int(s); } else if (*s == '{') { ++s; Arg precision_arg = internal::is_name_start(*s) ? parse_arg_name(s) : parse_arg_index(s); if (*s++ != '}') FMT_THROW(FormatError("invalid format string")); ULongLong value = 0; switch (precision_arg.type) { case Arg::INT: if (precision_arg.int_value < 0) FMT_THROW(FormatError("negative precision")); value = precision_arg.int_value; break; case Arg::UINT: value = precision_arg.uint_value; break; case Arg::LONG_LONG: if (precision_arg.long_long_value < 0) FMT_THROW(FormatError("negative precision")); value = precision_arg.long_long_value; break; case Arg::ULONG_LONG: value = precision_arg.ulong_long_value; break; default: FMT_THROW(FormatError("precision is not integer")); } if (value >(std::numeric_limits::max)()) FMT_THROW(FormatError("number is too big")); spec.precision_ = static_cast(value); } else { FMT_THROW(FormatError("missing precision specifier")); } if (arg.type <= Arg::LAST_INTEGER_TYPE || arg.type == Arg::POINTER) { FMT_THROW(FormatError( fmt::format("precision not allowed in {} format specifier", arg.type == Arg::POINTER ? "pointer" : "integer"))); } } // Parse type. if (*s != '}' && *s) spec.type_ = static_cast(*s++); } if (*s++ != '}') FMT_THROW(FormatError("missing '}' in format string")); // Format argument. ArgFormatter(*this, spec, s - 1).visit(arg); return s; } template void BasicFormatter::format(BasicCStringRef format_str) { const Char *s = format_str.c_str(); const Char *start = s; while (*s) { Char c = *s++; if (c != '{' && c != '}') continue; if (*s == c) { write(writer_, start, s); start = ++s; continue; } if (c == '}') FMT_THROW(FormatError("unmatched '}' in format string")); write(writer_, start, s - 1); internal::Arg arg = internal::is_name_start(*s) ? parse_arg_name(s) : parse_arg_index(s); start = s = format(s, arg); } write(writer_, start, s); } } // namespace fmt #if FMT_USE_USER_DEFINED_LITERALS namespace fmt { namespace internal { template struct UdlFormat { const Char *str; template auto operator()(Args && ... args) const -> decltype(format(str, std::forward(args)...)) { return format(str, std::forward(args)...); } }; template struct UdlArg { const Char *str; template NamedArg operator=(T &&value) const { return { str, std::forward(value) }; } }; } // namespace internal inline namespace literals { /** \rst C++11 literal equivalent of :func:`fmt::format`. **Example**:: using namespace fmt::literals; std::string message = "The answer is {}"_format(42); \endrst */ inline internal::UdlFormat operator"" _format(const char *s, std::size_t) { return { s }; } inline internal::UdlFormat operator"" _format(const wchar_t *s, std::size_t) { return { s }; } /** \rst C++11 literal equivalent of :func:`fmt::arg`. **Example**:: using namespace fmt::literals; print("Elapsed time: {s:.2f} seconds", "s"_a=1.23); \endrst */ inline internal::UdlArg operator"" _a(const char *s, std::size_t) { return { s }; } inline internal::UdlArg operator"" _a(const wchar_t *s, std::size_t) { return { s }; } } // inline namespace literals } // namespace fmt #endif // FMT_USE_USER_DEFINED_LITERALS // Restore warnings. #if FMT_GCC_VERSION >= 406 # pragma GCC diagnostic pop #endif #if defined(__clang__) && !defined(__INTEL_COMPILER) # pragma clang diagnostic pop #endif #ifdef FMT_HEADER_ONLY # include "format.cc" #endif #endif // FMT_FORMAT_H_ gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/Utility/GmmLog/spdlog/details/line_logger_fwd.h000066400000000000000000000036071466655022700311220ustar00rootroot00000000000000// // Copyright(c) 2015 Gabi Melman. // Distributed under the MIT License (http://opensource.org/licenses/MIT) // #pragma once #include <../Utility/GmmLog/spdlog/common.h> #include <../Utility/GmmLog/spdlog/details/log_msg.h> #include // Line logger class - aggregates operator<< calls to fast ostream // and logs upon destruction namespace spdlog { // Forward declaration class logger; namespace details { class line_logger { public: line_logger(logger* callback_logger, level::level_enum msg_level, bool enabled); // No copy intended. Only move line_logger(const line_logger& other) = delete; line_logger& operator=(const line_logger&) = delete; line_logger& operator=(line_logger&&) = delete; line_logger(line_logger&& other); //Log the log message using the callback logger ~line_logger(); // // Support for format string with variadic args // void write(const char* what); template void write(const char* fmt, const Args&... args); // // Support for operator<< // line_logger& operator<<(const char* what); line_logger& operator<<(const std::string& what); line_logger& operator<<(int what); line_logger& operator<<(unsigned int what); line_logger& operator<<(long what); line_logger& operator<<(unsigned long what); line_logger& operator<<(long long what); line_logger& operator<<(unsigned long long what); line_logger& operator<<(double what); line_logger& operator<<(long double what); line_logger& operator<<(float what); line_logger& operator<<(char what); //Support user types which implements operator<< template line_logger& operator<<(const T& what); void disable(); bool is_enabled() const; private: logger* _callback_logger; log_msg _log_msg; bool _enabled; }; } //Namespace details } // Namespace spdlog gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/Utility/GmmLog/spdlog/details/line_logger_impl.h000066400000000000000000000102511466655022700312740ustar00rootroot00000000000000// // Copyright(c) 2015 Gabi Melman. // Distributed under the MIT License (http://opensource.org/licenses/MIT) // #pragma once #include #include <../Utility/GmmLog/spdlog/details/line_logger_fwd.h> #include <../Utility/GmmLog/spdlog/common.h> #include <../Utility/GmmLog/spdlog/logger.h> #include #include // Line logger class - aggregates operator<< calls to fast ostream // and logs upon destruction inline spdlog::details::line_logger::line_logger(logger* callback_logger, level::level_enum msg_level, bool enabled): _callback_logger(callback_logger), _log_msg(msg_level), _enabled(enabled) {} inline spdlog::details::line_logger::line_logger(line_logger&& other) : _callback_logger(other._callback_logger), _log_msg(std::move(other._log_msg)), _enabled(other._enabled) { other.disable(); } //Log the log message using the callback logger inline spdlog::details::line_logger::~line_logger() { if (_enabled) { #ifndef SPDLOG_NO_NAME _log_msg.logger_name = _callback_logger->name(); #endif #ifndef SPDLOG_NO_DATETIME _log_msg.time = os::now(); #endif #ifndef SPDLOG_NO_THREAD_ID _log_msg.thread_id = os::thread_id(); #endif _callback_logger->_log_msg(_log_msg); } } // // Support for format string with variadic args // inline void spdlog::details::line_logger::write(const char* what) { if (_enabled) _log_msg.raw << what; } template inline void spdlog::details::line_logger::write(const char* fmt, const Args&... args) { if (!_enabled) return; try { _log_msg.raw.write(fmt, args...); } catch (const fmt::FormatError& e) { throw spdlog_ex(fmt::format("formatting error while processing format string '{}': {}", fmt, e.what())); } } // // Support for operator<< // inline spdlog::details::line_logger& spdlog::details::line_logger::operator<<(const char* what) { if (_enabled) _log_msg.raw << what; return *this; } inline spdlog::details::line_logger& spdlog::details::line_logger::operator<<(const std::string& what) { if (_enabled) _log_msg.raw << what; return *this; } inline spdlog::details::line_logger& spdlog::details::line_logger::operator<<(int what) { if (_enabled) _log_msg.raw << what; return *this; } inline spdlog::details::line_logger& spdlog::details::line_logger::operator<<(unsigned int what) { if (_enabled) _log_msg.raw << what; return *this; } inline spdlog::details::line_logger& spdlog::details::line_logger::operator<<(long what) { if (_enabled) _log_msg.raw << what; return *this; } inline spdlog::details::line_logger& spdlog::details::line_logger::operator<<(unsigned long what) { if (_enabled) _log_msg.raw << what; return *this; } inline spdlog::details::line_logger& spdlog::details::line_logger::operator<<(long long what) { if (_enabled) _log_msg.raw << what; return *this; } inline spdlog::details::line_logger& spdlog::details::line_logger::operator<<(unsigned long long what) { if (_enabled) _log_msg.raw << what; return *this; } inline spdlog::details::line_logger& spdlog::details::line_logger::operator<<(double what) { if (_enabled) _log_msg.raw << what; return *this; } inline spdlog::details::line_logger& spdlog::details::line_logger::operator<<(long double what) { if (_enabled) _log_msg.raw << what; return *this; } inline spdlog::details::line_logger& spdlog::details::line_logger::operator<<(float what) { if (_enabled) _log_msg.raw << what; return *this; } inline spdlog::details::line_logger& spdlog::details::line_logger::operator<<(char what) { if (_enabled) _log_msg.raw << what; return *this; } //Support user types which implements operator<< template inline spdlog::details::line_logger& spdlog::details::line_logger::operator<<(const T& what) { if (_enabled) _log_msg.raw.write("{}", what); return *this; } inline void spdlog::details::line_logger::disable() { _enabled = false; } inline bool spdlog::details::line_logger::is_enabled() const { return _enabled; } gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/Utility/GmmLog/spdlog/details/log_msg.h000066400000000000000000000015641466655022700274230ustar00rootroot00000000000000// // Copyright(c) 2015 Gabi Melman. // Distributed under the MIT License (http://opensource.org/licenses/MIT) // #pragma once #include #include #include #include namespace spdlog { namespace details { struct log_msg { log_msg() = default; log_msg(const std::string *loggers_name, level::level_enum lvl) : logger_name(loggers_name), level(lvl) { #ifndef SPDLOG_NO_DATETIME time = os::now(); #endif #ifndef SPDLOG_NO_THREAD_ID thread_id = os::thread_id(); #endif } log_msg(const log_msg& other) = delete; log_msg& operator=(log_msg&& other) = delete; log_msg(log_msg&& other) = delete; const std::string *logger_name; level::level_enum level; log_clock::time_point time; size_t thread_id; fmt::MemoryWriter raw; fmt::MemoryWriter formatted; }; } } gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/Utility/GmmLog/spdlog/details/logger_impl.h000066400000000000000000000145651466655022700303010ustar00rootroot00000000000000// // Copyright(c) 2015 Gabi Melman. // Distributed under the MIT License (http://opensource.org/licenses/MIT) // #pragma once #include #include #include #include // create logger with given name, sinks and the default pattern formatter // all other ctors will call this one template inline spdlog::logger::logger(const std::string& logger_name, const It& begin, const It& end): _name(logger_name), _sinks(begin, end), _formatter(std::make_shared("%+")) { _level = level::info; _flush_level = level::off; _last_err_time = 0; _err_handler = [this](const std::string &msg) { this->_default_err_handler(msg); }; } // ctor with sinks as init list inline spdlog::logger::logger(const std::string& logger_name, sinks_init_list sinks_list): logger(logger_name, sinks_list.begin(), sinks_list.end()) {} // ctor with single sink inline spdlog::logger::logger(const std::string& logger_name, spdlog::sink_ptr single_sink): logger(logger_name, { single_sink }) {} inline spdlog::logger::~logger() = default; inline void spdlog::logger::set_formatter(spdlog::formatter_ptr msg_formatter) { _set_formatter(msg_formatter); } inline void spdlog::logger::set_pattern(const std::string& pattern) { _set_pattern(pattern); } template inline void spdlog::logger::log(level::level_enum lvl, const char* fmt, const Args&... args) { if (!should_log(lvl)) return; try { details::log_msg log_msg(&_name, lvl); log_msg.raw.write(fmt, args...); _sink_it(log_msg); } catch (const std::exception &ex) { _err_handler(ex.what()); } catch (...) { _err_handler("Unknown exception"); } } template inline void spdlog::logger::log(level::level_enum lvl, const char* msg) { if (!should_log(lvl)) return; try { details::log_msg log_msg(&_name, lvl); log_msg.raw << msg; _sink_it(log_msg); } catch (const std::exception &ex) { _err_handler(ex.what()); } catch (...) { _err_handler("Unknown exception"); } } template inline void spdlog::logger::log(level::level_enum lvl, const T& msg) { if (!should_log(lvl)) return; try { details::log_msg log_msg(&_name, lvl); log_msg.raw << msg; _sink_it(log_msg); } catch (const std::exception &ex) { _err_handler(ex.what()); } catch (...) { _err_handler("Unknown exception"); } } template inline void spdlog::logger::trace(const char* fmt, const Args&... args) { log(level::trace, fmt, args...); } template inline void spdlog::logger::debug(const char* fmt, const Args&... args) { log(level::debug, fmt, args...); } template inline void spdlog::logger::info(const char* fmt, const Args&... args) { log(level::info, fmt, args...); } template inline void spdlog::logger::warn(const char* fmt, const Args&... args) { log(level::warn, fmt, args...); } template inline void spdlog::logger::error(const char* fmt, const Args&... args) { log(level::err, fmt, args...); } template inline void spdlog::logger::critical(const char* fmt, const Args&... args) { log(level::critical, fmt, args...); } template inline void spdlog::logger::trace(const T& msg) { log(level::trace, msg); } template inline void spdlog::logger::debug(const T& msg) { log(level::debug, msg); } template inline void spdlog::logger::info(const T& msg) { log(level::info, msg); } template inline void spdlog::logger::warn(const T& msg) { log(level::warn, msg); } template inline void spdlog::logger::error(const T& msg) { log(level::err, msg); } template inline void spdlog::logger::critical(const T& msg) { log(level::critical, msg); } // // name and level // inline const std::string& spdlog::logger::name() const { return _name; } inline void spdlog::logger::set_level(spdlog::level::level_enum log_level) { _level.store(log_level); } inline void spdlog::logger::set_error_handler(spdlog::log_err_handler err_handler) { _err_handler = err_handler; } inline spdlog::log_err_handler spdlog::logger::error_handler() { return _err_handler; } inline void spdlog::logger::flush_on(level::level_enum log_level) { _flush_level.store(log_level); } inline spdlog::level::level_enum spdlog::logger::level() const { return static_cast(_level.load(std::memory_order_relaxed)); } inline bool spdlog::logger::should_log(spdlog::level::level_enum msg_level) const { return msg_level >= _level.load(std::memory_order_relaxed); } // // protected virtual called at end of each user log call (if enabled) by the line_logger // inline void spdlog::logger::_sink_it(details::log_msg& msg) { _formatter->format(msg); for (auto &sink : _sinks) { if( sink->should_log( msg.level)) { sink->log(msg); } } if(_should_flush_on(msg)) flush(); } inline void spdlog::logger::_set_pattern(const std::string& pattern) { _formatter = std::make_shared(pattern); } inline void spdlog::logger::_set_formatter(formatter_ptr msg_formatter) { _formatter = msg_formatter; } inline void spdlog::logger::flush() { for (auto& sink : _sinks) sink->flush(); } inline void spdlog::logger::_default_err_handler(const std::string &msg) { auto now = time(nullptr); if (now - _last_err_time < 60) return; auto tm_time = details::os::localtime(now); char date_buf[100]; std::strftime(date_buf, sizeof(date_buf), "%Y-%m-%d %H:%M:%S", &tm_time); details::log_msg err_msg; err_msg.formatted.write("[*** LOG ERROR ***] [{}] [{}] [{}]{}", name(), msg, date_buf, details::os::eol); sinks::stderr_sink_mt::instance()->log(err_msg); _last_err_time = now; } inline bool spdlog::logger::_should_flush_on(const details::log_msg &msg) { const auto flush_level = _flush_level.load(std::memory_order_relaxed); return (msg.level >= flush_level) && (msg.level != level::off); } inline const std::vector& spdlog::logger::sinks() const { return _sinks; } gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/Utility/GmmLog/spdlog/details/mpmc_bounded_q.h000066400000000000000000000125601466655022700307460ustar00rootroot00000000000000/* A modified version of Bounded MPMC queue by Dmitry Vyukov. Original code from: http://www.1024cores.net/home/lock-free-algorithms/queues/bounded-mpmc-queue licensed by Dmitry Vyukov under the terms below: Simplified BSD license Copyright (c) 2010-2011 Dmitry Vyukov. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY DMITRY VYUKOV "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL DMITRY VYUKOV OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. The views and conclusions contained in the software and documentation are those of the authors and should not be interpreted as representing official policies, either expressed or implied, of Dmitry Vyukov. */ /* The code in its current form adds the license below: Copyright(c) 2015 Gabi Melman. Distributed under the MIT License (http://opensource.org/licenses/MIT) */ #pragma once #include #include #include namespace spdlog { namespace details { template class mpmc_bounded_queue { public: using item_type = T; mpmc_bounded_queue(size_t buffer_size) :max_size_(buffer_size), buffer_(new cell_t [buffer_size]), buffer_mask_(buffer_size - 1) { //queue size must be power of two if(!((buffer_size >= 2) && ((buffer_size & (buffer_size - 1)) == 0))) throw spdlog_ex("async logger queue size must be power of two"); for (size_t i = 0; i != buffer_size; i += 1) buffer_[i].sequence_.store(i, std::memory_order_relaxed); enqueue_pos_.store(0, std::memory_order_relaxed); dequeue_pos_.store(0, std::memory_order_relaxed); } ~mpmc_bounded_queue() { delete [] buffer_; } bool enqueue(T&& data) { cell_t* cell; size_t pos = enqueue_pos_.load(std::memory_order_relaxed); for (;;) { cell = &buffer_[pos & buffer_mask_]; size_t seq = cell->sequence_.load(std::memory_order_acquire); intptr_t dif = (intptr_t)seq - (intptr_t)pos; if (dif == 0) { if (enqueue_pos_.compare_exchange_weak(pos, pos + 1, std::memory_order_relaxed)) break; } else if (dif < 0) { return false; } else { pos = enqueue_pos_.load(std::memory_order_relaxed); } } cell->data_ = std::move(data); cell->sequence_.store(pos + 1, std::memory_order_release); return true; } bool dequeue(T& data) { cell_t* cell; size_t pos = dequeue_pos_.load(std::memory_order_relaxed); for (;;) { cell = &buffer_[pos & buffer_mask_]; size_t seq = cell->sequence_.load(std::memory_order_acquire); intptr_t dif = (intptr_t)seq - (intptr_t)(pos + 1); if (dif == 0) { if (dequeue_pos_.compare_exchange_weak(pos, pos + 1, std::memory_order_relaxed)) break; } else if (dif < 0) return false; else pos = dequeue_pos_.load(std::memory_order_relaxed); } data = std::move(cell->data_); cell->sequence_.store(pos + buffer_mask_ + 1, std::memory_order_release); return true; } size_t approx_size() { size_t first_pos = dequeue_pos_.load(std::memory_order_relaxed); size_t last_pos = enqueue_pos_.load(std::memory_order_relaxed); if (last_pos <= first_pos) return 0; auto size = last_pos - first_pos; return size < max_size_ ? size : max_size_; } private: struct cell_t { std::atomic sequence_; T data_; }; size_t const max_size_; static size_t const cacheline_size = 64; typedef char cacheline_pad_t [cacheline_size]; cacheline_pad_t pad0_; cell_t* const buffer_; size_t const buffer_mask_; cacheline_pad_t pad1_; std::atomic enqueue_pos_; cacheline_pad_t pad2_; std::atomic dequeue_pos_; cacheline_pad_t pad3_; mpmc_bounded_queue(mpmc_bounded_queue const&) = delete; void operator= (mpmc_bounded_queue const&) = delete; }; } // ns details } // ns spdlog gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/Utility/GmmLog/spdlog/details/null_mutex.h000066400000000000000000000011521466655022700301610ustar00rootroot00000000000000// // Copyright(c) 2015 Gabi Melman. // Distributed under the MIT License (http://opensource.org/licenses/MIT) // #pragma once #include // null, no cost dummy "mutex" and dummy "atomic" int namespace spdlog { namespace details { struct null_mutex { void lock() {} void unlock() {} bool try_lock() { return true; } }; struct null_atomic_int { int value; null_atomic_int() = default; null_atomic_int(int val):value(val) {} int load(std::memory_order) const { return value; } void store(int val) { value = val; } }; } } gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/Utility/GmmLog/spdlog/details/os.h000066400000000000000000000214001466655022700264040ustar00rootroot00000000000000// // Copyright(c) 2015 Gabi Melman. // Distributed under the MIT License (http://opensource.org/licenses/MIT) // #pragma once #include #include #include #include #include #include #include #include #ifdef _WIN32 #ifndef NOMINMAX #define NOMINMAX //prevent windows redefining min/max #endif #ifndef WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN #endif #include #ifdef __MINGW32__ #include #endif #include #include #elif __linux__ #include //Use gettid() syscall under linux to get thread id #include #include #elif __FreeBSD__ #include //Use thr_self() syscall under FreeBSD to get thread id #else #include #endif namespace spdlog { namespace details { namespace os { inline spdlog::log_clock::time_point now() { #if defined __linux__ && defined SPDLOG_CLOCK_COARSE timespec ts; ::clock_gettime(CLOCK_REALTIME_COARSE, &ts); return std::chrono::time_point( std::chrono::duration_cast( std::chrono::seconds(ts.tv_sec) + std::chrono::nanoseconds(ts.tv_nsec))); #else return log_clock::now(); #endif } inline std::tm localtime(const std::time_t &time_tt) { #ifdef _WIN32 std::tm tm; localtime_s(&tm, &time_tt); #else std::tm tm; localtime_r(&time_tt, &tm); #endif return tm; } inline std::tm localtime() { std::time_t now_t = time(nullptr); return localtime(now_t); } inline std::tm gmtime(const std::time_t &time_tt) { #ifdef _WIN32 std::tm tm; gmtime_s(&tm, &time_tt); #else std::tm tm; gmtime_r(&time_tt, &tm); #endif return tm; } inline std::tm gmtime() { std::time_t now_t = time(nullptr); return gmtime(now_t); } inline bool operator==(const std::tm& tm1, const std::tm& tm2) { return (tm1.tm_sec == tm2.tm_sec && tm1.tm_min == tm2.tm_min && tm1.tm_hour == tm2.tm_hour && tm1.tm_mday == tm2.tm_mday && tm1.tm_mon == tm2.tm_mon && tm1.tm_year == tm2.tm_year && tm1.tm_isdst == tm2.tm_isdst); } inline bool operator!=(const std::tm& tm1, const std::tm& tm2) { return !(tm1 == tm2); } // eol definition #if !defined (SPDLOG_EOL) #ifdef _WIN32 #define SPDLOG_EOL "\r\n" #else #define SPDLOG_EOL "\n" #endif #endif SPDLOG_CONSTEXPR static const char* eol = SPDLOG_EOL; SPDLOG_CONSTEXPR static int eol_size = sizeof(SPDLOG_EOL) - 1; //fopen_s on non windows for writing inline int fopen_s(FILE** fp, const filename_t& filename, const filename_t& mode) { #ifdef _WIN32 #ifdef SPDLOG_WCHAR_FILENAMES *fp = _wfsopen((filename.c_str()), mode.c_str(), _SH_DENYWR); #else *fp = _fsopen((filename.c_str()), mode.c_str(), _SH_DENYWR); #endif return *fp == nullptr; #else *fp = fopen((filename.c_str()), mode.c_str()); return *fp == nullptr; #endif } inline int remove(const filename_t &filename) { #if defined(_WIN32) && defined(SPDLOG_WCHAR_FILENAMES) return _wremove(filename.c_str()); #else return std::remove(filename.c_str()); #endif } inline int rename(const filename_t& filename1, const filename_t& filename2) { #if defined(_WIN32) && defined(SPDLOG_WCHAR_FILENAMES) return _wrename(filename1.c_str(), filename2.c_str()); #else return std::rename(filename1.c_str(), filename2.c_str()); #endif } //Return if file exists inline bool file_exists(const filename_t& filename) { #ifdef _WIN32 #ifdef SPDLOG_WCHAR_FILENAMES auto attribs = GetFileAttributesW(filename.c_str()); #else auto attribs = GetFileAttributesA(filename.c_str()); #endif return (attribs != INVALID_FILE_ATTRIBUTES && !(attribs & FILE_ATTRIBUTE_DIRECTORY)); #else //common linux/unix all have the stat system call struct stat buffer; return (stat (filename.c_str(), &buffer) == 0); #endif } //Return file size according to open FILE* object inline size_t filesize(FILE *f) { if (f == nullptr) throw spdlog_ex("Failed getting file size. fd is null"); #ifdef _WIN32 int fd = _fileno(f); #if _WIN64 //64 bits struct _stat64 st; if (_fstat64(fd, &st) == 0) return st.st_size; #else //windows 32 bits long ret = _filelength(fd); if (ret >= 0) return static_cast(ret); #endif #else // unix int fd = fileno(f); //64 bits(but not in osx, where fstat64 is deprecated) #if !defined(__FreeBSD__) && !defined(__APPLE__) && (defined(__x86_64__) || defined(__ppc64__)) struct stat64 st; if (fstat64(fd, &st) == 0) return static_cast(st.st_size); #else // unix 32 bits or osx struct stat st; if (fstat(fd, &st) == 0) return static_cast(st.st_size); #endif #endif throw spdlog_ex("Failed getting file size from fd", errno); } //Return utc offset in minutes or throw spdlog_ex on failure inline int utc_minutes_offset(const std::tm& tm = details::os::localtime()) { #ifdef _WIN32 #if _WIN32_WINNT < _WIN32_WINNT_WS08 TIME_ZONE_INFORMATION tzinfo; auto rv = GetTimeZoneInformation(&tzinfo); #else DYNAMIC_TIME_ZONE_INFORMATION tzinfo; auto rv = GetDynamicTimeZoneInformation(&tzinfo); #endif if (rv == TIME_ZONE_ID_INVALID) throw spdlog::spdlog_ex("Failed getting timezone info. ", errno); int offset = -tzinfo.Bias; if (tm.tm_isdst) offset -= tzinfo.DaylightBias; else offset -= tzinfo.StandardBias; return offset; #else #if defined(sun) || defined(__sun) // 'tm_gmtoff' field is BSD extension and it's missing on SunOS/Solaris struct helper { static long int calculate_gmt_offset(const std::tm & localtm = details::os::localtime(), const std::tm & gmtm = details::os::gmtime()) { int local_year = localtm.tm_year + (1900 - 1); int gmt_year = gmtm.tm_year + (1900 - 1); long int days = ( // difference in day of year localtm.tm_yday - gmtm.tm_yday // + intervening leap days + ((local_year >> 2) - (gmt_year >> 2)) - (local_year / 100 - gmt_year / 100) + ((local_year / 100 >> 2) - (gmt_year / 100 >> 2)) // + difference in years * 365 */ + (long int)(local_year - gmt_year) * 365 ); long int hours = (24 * days) + (localtm.tm_hour - gmtm.tm_hour); long int mins = (60 * hours) + (localtm.tm_min - gmtm.tm_min); long int secs = (60 * mins) + (localtm.tm_sec - gmtm.tm_sec); return secs; } }; long int offset_seconds = helper::calculate_gmt_offset(tm); #else long int offset_seconds = tm.tm_gmtoff; #endif return static_cast(offset_seconds / 60); #endif } //Return current thread id as size_t //It exists because the std::this_thread::get_id() is much slower(espcially under VS 2013) inline size_t thread_id() { #ifdef _WIN32 return static_cast(::GetCurrentThreadId()); #elif __linux__ # if defined(__ANDROID__) && defined(__ANDROID_API__) && (__ANDROID_API__ < 21) # define SYS_gettid __NR_gettid # endif return static_cast(syscall(SYS_gettid)); #elif __FreeBSD__ long tid; thr_self(&tid); return static_cast(tid); #else //Default to standard C++11 (OSX and other Unix) return static_cast(std::hash()(std::this_thread::get_id())); #endif } // wchar support for windows file names (SPDLOG_WCHAR_FILENAMES must be defined) #if defined(_WIN32) && defined(SPDLOG_WCHAR_FILENAMES) #define SPDLOG_FILENAME_T(s) L ## s inline std::string filename_to_str(const filename_t& filename) { std::wstring_convert, wchar_t> c; return c.to_bytes(filename); } #else #define SPDLOG_FILENAME_T(s) s inline std::string filename_to_str(const filename_t& filename) { return filename; } #endif // Return errno string (thread safe) inline std::string errno_str(int err_num) { char buf[256]; SPDLOG_CONSTEXPR auto buf_size = sizeof(buf); #ifdef _WIN32 if(strerror_s(buf, buf_size, err_num) == 0) return std::string(buf); else return "Unkown error"; #elif defined(__FreeBSD__) || defined(__APPLE__) || defined(ANDROID) || defined(__QNX__) || \ ((_POSIX_C_SOURCE >= 200112L) && ! _GNU_SOURCE) // posix version if (strerror_r(err_num, buf, buf_size) == 0) return std::string(buf); else return "Unkown error"; #else // gnu version (might not use the given buf, so its retval pointer must be used) return std::string(strerror_r(err_num, buf, buf_size)); #endif } } //os } //details } //spdlog gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/Utility/GmmLog/spdlog/details/pattern_formatter_impl.h000066400000000000000000000431541466655022700325560ustar00rootroot00000000000000// // Copyright(c) 2015 Gabi Melman. // Distributed under the MIT License (http://opensource.org/licenses/MIT) // #pragma once #include #include #include #include #include #include #include #include #include #include #include #include namespace spdlog { namespace details { class flag_formatter { public: virtual ~flag_formatter() {} virtual void format(details::log_msg& msg, const std::tm& tm_time) = 0; }; /////////////////////////////////////////////////////////////////////// // name & level pattern appenders /////////////////////////////////////////////////////////////////////// namespace { class name_formatter:public flag_formatter { void format(details::log_msg& msg, const std::tm&) override { msg.formatted << *msg.logger_name; } }; } // log level appender class level_formatter:public flag_formatter { void format(details::log_msg& msg, const std::tm&) override { msg.formatted << level::to_str(msg.level); } }; // short log level appender class short_level_formatter:public flag_formatter { void format(details::log_msg& msg, const std::tm&) override { msg.formatted << level::to_short_str(msg.level); } }; /////////////////////////////////////////////////////////////////////// // Date time pattern appenders /////////////////////////////////////////////////////////////////////// static const char* ampm(const tm& t) { return t.tm_hour >= 12 ? "PM" : "AM"; } static int to12h(const tm& t) { return t.tm_hour > 12 ? t.tm_hour - 12 : t.tm_hour; } //Abbreviated weekday name static const std::string days[] { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" }; class a_formatter:public flag_formatter { void format(details::log_msg& msg, const std::tm& tm_time) override { msg.formatted << days[tm_time.tm_wday]; } }; //Full weekday name static const std::string full_days[] { "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" }; class A_formatter:public flag_formatter { void format(details::log_msg& msg, const std::tm& tm_time) override { msg.formatted << full_days[tm_time.tm_wday]; } }; //Abbreviated month static const std::string months[] { "Jan", "Feb", "Mar", "Apr", "May", "June", "July", "Aug", "Sept", "Oct", "Nov", "Dec" }; class b_formatter:public flag_formatter { void format(details::log_msg& msg, const std::tm& tm_time) override { msg.formatted << months[tm_time.tm_mon]; } }; //Full month name static const std::string full_months[] { "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" }; class B_formatter:public flag_formatter { void format(details::log_msg& msg, const std::tm& tm_time) override { msg.formatted << full_months[tm_time.tm_mon]; } }; //write 2 ints seperated by sep with padding of 2 static fmt::MemoryWriter& pad_n_join(fmt::MemoryWriter& w, int v1, int v2, char sep) { w << fmt::pad(v1, 2, '0') << sep << fmt::pad(v2, 2, '0'); return w; } //write 3 ints seperated by sep with padding of 2 static fmt::MemoryWriter& pad_n_join(fmt::MemoryWriter& w, int v1, int v2, int v3, char sep) { w << fmt::pad(v1, 2, '0') << sep << fmt::pad(v2, 2, '0') << sep << fmt::pad(v3, 2, '0'); return w; } //Date and time representation (Thu Aug 23 15:35:46 2014) class c_formatter:public flag_formatter { void format(details::log_msg& msg, const std::tm& tm_time) override { msg.formatted << days[tm_time.tm_wday] << ' ' << months[tm_time.tm_mon] << ' ' << tm_time.tm_mday << ' '; pad_n_join(msg.formatted, tm_time.tm_hour, tm_time.tm_min, tm_time.tm_sec, ':') << ' ' << tm_time.tm_year + 1900; } }; // year - 2 digit class C_formatter:public flag_formatter { void format(details::log_msg& msg, const std::tm& tm_time) override { msg.formatted << fmt::pad(tm_time.tm_year % 100, 2, '0'); } }; // Short MM/DD/YY date, equivalent to %m/%d/%y 08/23/01 class D_formatter:public flag_formatter { void format(details::log_msg& msg, const std::tm& tm_time) override { pad_n_join(msg.formatted, tm_time.tm_mon + 1, tm_time.tm_mday, tm_time.tm_year % 100, '/'); } }; // year - 4 digit class Y_formatter:public flag_formatter { void format(details::log_msg& msg, const std::tm& tm_time) override { msg.formatted << tm_time.tm_year + 1900; } }; // month 1-12 class m_formatter:public flag_formatter { void format(details::log_msg& msg, const std::tm& tm_time) override { msg.formatted << fmt::pad(tm_time.tm_mon + 1, 2, '0'); } }; // day of month 1-31 class d_formatter:public flag_formatter { void format(details::log_msg& msg, const std::tm& tm_time) override { msg.formatted << fmt::pad(tm_time.tm_mday, 2, '0'); } }; // hours in 24 format 0-23 class H_formatter:public flag_formatter { void format(details::log_msg& msg, const std::tm& tm_time) override { msg.formatted << fmt::pad(tm_time.tm_hour, 2, '0'); } }; // hours in 12 format 1-12 class I_formatter:public flag_formatter { void format(details::log_msg& msg, const std::tm& tm_time) override { msg.formatted << fmt::pad(to12h(tm_time), 2, '0'); } }; // minutes 0-59 class M_formatter:public flag_formatter { void format(details::log_msg& msg, const std::tm& tm_time) override { msg.formatted << fmt::pad(tm_time.tm_min, 2, '0'); } }; // seconds 0-59 class S_formatter:public flag_formatter { void format(details::log_msg& msg, const std::tm& tm_time) override { msg.formatted << fmt::pad(tm_time.tm_sec, 2, '0'); } }; // milliseconds class e_formatter:public flag_formatter { void format(details::log_msg& msg, const std::tm&) override { auto duration = msg.time.time_since_epoch(); auto millis = std::chrono::duration_cast(duration).count() % 1000; msg.formatted << fmt::pad(static_cast(millis), 3, '0'); } }; // microseconds class f_formatter:public flag_formatter { void format(details::log_msg& msg, const std::tm&) override { auto duration = msg.time.time_since_epoch(); auto micros = std::chrono::duration_cast(duration).count() % 1000000; msg.formatted << fmt::pad(static_cast(micros), 6, '0'); } }; // nanoseconds class F_formatter:public flag_formatter { void format(details::log_msg& msg, const std::tm&) override { auto duration = msg.time.time_since_epoch(); auto ns = std::chrono::duration_cast(duration).count() % 1000000000; msg.formatted << fmt::pad(static_cast(ns), 9, '0'); } }; // AM/PM class p_formatter:public flag_formatter { void format(details::log_msg& msg, const std::tm& tm_time) override { msg.formatted << ampm(tm_time); } }; // 12 hour clock 02:55:02 pm class r_formatter:public flag_formatter { void format(details::log_msg& msg, const std::tm& tm_time) override { pad_n_join(msg.formatted, to12h(tm_time), tm_time.tm_min, tm_time.tm_sec, ':') << ' ' << ampm(tm_time); } }; // 24-hour HH:MM time, equivalent to %H:%M class R_formatter:public flag_formatter { void format(details::log_msg& msg, const std::tm& tm_time) override { pad_n_join(msg.formatted, tm_time.tm_hour, tm_time.tm_min, ':'); } }; // ISO 8601 time format (HH:MM:SS), equivalent to %H:%M:%S class T_formatter:public flag_formatter { void format(details::log_msg& msg, const std::tm& tm_time) override { pad_n_join(msg.formatted, tm_time.tm_hour, tm_time.tm_min, tm_time.tm_sec, ':'); } }; // ISO 8601 offset from UTC in timezone (+-HH:MM) class z_formatter:public flag_formatter { public: const std::chrono::seconds cache_refresh = std::chrono::seconds(5); z_formatter():_last_update(std::chrono::seconds(0)) {} z_formatter(const z_formatter&) = delete; z_formatter& operator=(const z_formatter&) = delete; void format(details::log_msg& msg, const std::tm& tm_time) override { #ifdef _WIN32 int total_minutes = get_cached_offset(msg, tm_time); #else // No need to chache under gcc, // it is very fast (already stored in tm.tm_gmtoff) int total_minutes = os::utc_minutes_offset(tm_time); #endif bool is_negative = total_minutes < 0; char sign; if (is_negative) { total_minutes = -total_minutes; sign = '-'; } else { sign = '+'; } int h = total_minutes / 60; int m = total_minutes % 60; msg.formatted << sign; pad_n_join(msg.formatted, h, m, ':'); } private: log_clock::time_point _last_update; int _offset_minutes; std::mutex _mutex; int get_cached_offset(const log_msg& msg, const std::tm& tm_time) { using namespace std::chrono; std::lock_guard l(_mutex); if (msg.time - _last_update >= cache_refresh) { _offset_minutes = os::utc_minutes_offset(tm_time); _last_update = msg.time; } return _offset_minutes; } }; //Thread id class t_formatter:public flag_formatter { void format(details::log_msg& msg, const std::tm&) override { msg.formatted << msg.thread_id; } }; class v_formatter:public flag_formatter { void format(details::log_msg& msg, const std::tm&) override { msg.formatted << fmt::StringRef(msg.raw.data(), msg.raw.size()); } }; class ch_formatter:public flag_formatter { public: explicit ch_formatter(char ch): _ch(ch) {} void format(details::log_msg& msg, const std::tm&) override { msg.formatted << _ch; } private: char _ch; }; //aggregate user chars to display as is class aggregate_formatter:public flag_formatter { public: aggregate_formatter() {} void add_ch(char ch) { _str += ch; } void format(details::log_msg& msg, const std::tm&) override { msg.formatted << _str; } private: std::string _str; }; // Full info formatter // pattern: [%Y-%m-%d %H:%M:%S.%e] [%n] [%l] %v class full_formatter:public flag_formatter { void format(details::log_msg& msg, const std::tm& tm_time) override { #ifndef SPDLOG_NO_DATETIME auto duration = msg.time.time_since_epoch(); auto millis = std::chrono::duration_cast(duration).count() % 1000; /* Slower version(while still very fast - about 3.2 million lines/sec under 10 threads), msg.formatted.write("[{:d}-{:02d}-{:02d} {:02d}:{:02d}:{:02d}.{:03d}] [{}] [{}] {} ", tm_time.tm_year + 1900, tm_time.tm_mon + 1, tm_time.tm_mday, tm_time.tm_hour, tm_time.tm_min, tm_time.tm_sec, static_cast(millis), msg.logger_name, level::to_str(msg.level), msg.raw.str());*/ // Faster (albeit uglier) way to format the line (5.6 million lines/sec under 10 threads) msg.formatted << '[' << static_cast(tm_time.tm_year + 1900) << '-' << fmt::pad(static_cast(tm_time.tm_mon + 1), 2, '0') << '-' << fmt::pad(static_cast(tm_time.tm_mday), 2, '0') << ' ' << fmt::pad(static_cast(tm_time.tm_hour), 2, '0') << ':' << fmt::pad(static_cast(tm_time.tm_min), 2, '0') << ':' << fmt::pad(static_cast(tm_time.tm_sec), 2, '0') << '.' << fmt::pad(static_cast(millis), 3, '0') << "] "; //no datetime needed #else (void)tm_time; #endif #ifndef SPDLOG_NO_NAME msg.formatted << '[' << *msg.logger_name << "] "; #endif msg.formatted << '[' << level::to_str(msg.level) << "] "; msg.formatted << fmt::StringRef(msg.raw.data(), msg.raw.size()); } }; } } /////////////////////////////////////////////////////////////////////////////// // pattern_formatter inline impl /////////////////////////////////////////////////////////////////////////////// inline spdlog::pattern_formatter::pattern_formatter(const std::string& pattern) { compile_pattern(pattern); } inline void spdlog::pattern_formatter::compile_pattern(const std::string& pattern) { auto end = pattern.end(); std::unique_ptr user_chars; for (auto it = pattern.begin(); it != end; ++it) { if (*it == '%') { if (user_chars) //append user chars found so far _formatters.push_back(std::move(user_chars)); if (++it != end) handle_flag(*it); else break; } else // chars not following the % sign should be displayed as is { if (!user_chars) user_chars = std::unique_ptr(new details::aggregate_formatter()); user_chars->add_ch(*it); } } if (user_chars) //append raw chars found so far { _formatters.push_back(std::move(user_chars)); } } inline void spdlog::pattern_formatter::handle_flag(char flag) { switch (flag) { // logger name case 'n': _formatters.push_back(std::unique_ptr(new details::name_formatter())); break; case 'l': _formatters.push_back(std::unique_ptr(new details::level_formatter())); break; case 'L': _formatters.push_back(std::unique_ptr(new details::short_level_formatter())); break; case('t'): _formatters.push_back(std::unique_ptr(new details::t_formatter())); break; case('v'): _formatters.push_back(std::unique_ptr(new details::v_formatter())); break; case('a'): _formatters.push_back(std::unique_ptr(new details::a_formatter())); break; case('A'): _formatters.push_back(std::unique_ptr(new details::A_formatter())); break; case('b'): case('h'): _formatters.push_back(std::unique_ptr(new details::b_formatter())); break; case('B'): _formatters.push_back(std::unique_ptr(new details::B_formatter())); break; case('c'): _formatters.push_back(std::unique_ptr(new details::c_formatter())); break; case('C'): _formatters.push_back(std::unique_ptr(new details::C_formatter())); break; case('Y'): _formatters.push_back(std::unique_ptr(new details::Y_formatter())); break; case('D'): case('x'): _formatters.push_back(std::unique_ptr(new details::D_formatter())); break; case('m'): _formatters.push_back(std::unique_ptr(new details::m_formatter())); break; case('d'): _formatters.push_back(std::unique_ptr(new details::d_formatter())); break; case('H'): _formatters.push_back(std::unique_ptr(new details::H_formatter())); break; case('I'): _formatters.push_back(std::unique_ptr(new details::I_formatter())); break; case('M'): _formatters.push_back(std::unique_ptr(new details::M_formatter())); break; case('S'): _formatters.push_back(std::unique_ptr(new details::S_formatter())); break; case('e'): _formatters.push_back(std::unique_ptr(new details::e_formatter())); break; case('f'): _formatters.push_back(std::unique_ptr(new details::f_formatter())); break; case('F'): _formatters.push_back(std::unique_ptr(new details::F_formatter())); break; case('p'): _formatters.push_back(std::unique_ptr(new details::p_formatter())); break; case('r'): _formatters.push_back(std::unique_ptr(new details::r_formatter())); break; case('R'): _formatters.push_back(std::unique_ptr(new details::R_formatter())); break; case('T'): case('X'): _formatters.push_back(std::unique_ptr(new details::T_formatter())); break; case('z'): _formatters.push_back(std::unique_ptr(new details::z_formatter())); break; case ('+'): _formatters.push_back(std::unique_ptr(new details::full_formatter())); break; default: //Unkown flag appears as is _formatters.push_back(std::unique_ptr(new details::ch_formatter('%'))); _formatters.push_back(std::unique_ptr(new details::ch_formatter(flag))); break; } } inline void spdlog::pattern_formatter::format(details::log_msg& msg) { #ifndef SPDLOG_NO_DATETIME auto tm_time = details::os::localtime(log_clock::to_time_t(msg.time)); #else std::tm tm_time; #endif for (auto &f : _formatters) { f->format(msg, tm_time); } //write eol msg.formatted.write(details::os::eol, details::os::eol_size); } gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/Utility/GmmLog/spdlog/details/registry.h000066400000000000000000000125041466655022700276400ustar00rootroot00000000000000// // Copyright(c) 2015 Gabi Melman. // Distributed under the MIT License (http://opensource.org/licenses/MIT) // #pragma once // Loggers registy of unique name->logger pointer // An attempt to create a logger with an already existing name will be ignored // If user requests a non existing logger, nullptr will be returned // This class is thread safe #include #include #include #include #include #include #include #include #include #include namespace spdlog { namespace details { template class registry_t { public: void register_logger(std::shared_ptr logger) { std::lock_guard lock(_mutex); auto logger_name = logger->name(); throw_if_exists(logger_name); _loggers[logger_name] = logger; } std::shared_ptr get(const std::string& logger_name) { std::lock_guard lock(_mutex); auto found = _loggers.find(logger_name); return found == _loggers.end() ? nullptr : found->second; } template std::shared_ptr create(const std::string& logger_name, const It& sinks_begin, const It& sinks_end) { std::lock_guard lock(_mutex); throw_if_exists(logger_name); std::shared_ptr new_logger; if (_async_mode) new_logger = std::make_shared(logger_name, sinks_begin, sinks_end, _async_q_size, _overflow_policy, _worker_warmup_cb, _flush_interval_ms, _worker_teardown_cb); else new_logger = std::make_shared(logger_name, sinks_begin, sinks_end); if (_formatter) new_logger->set_formatter(_formatter); if (_err_handler) new_logger->set_error_handler(_err_handler); new_logger->set_level(_level); //Add to registry _loggers[logger_name] = new_logger; return new_logger; } void apply_all(std::function)> fun) { std::lock_guard lock(_mutex); for (auto &l : _loggers) fun(l.second); } void drop(const std::string& logger_name) { std::lock_guard lock(_mutex); _loggers.erase(logger_name); } void drop_all() { std::lock_guard lock(_mutex); _loggers.clear(); } std::shared_ptr create(const std::string& logger_name, sinks_init_list sinks) { return create(logger_name, sinks.begin(), sinks.end()); } std::shared_ptr create(const std::string& logger_name, sink_ptr sink) { return create(logger_name, { sink }); } void formatter(formatter_ptr f) { std::lock_guard lock(_mutex); _formatter = f; for (auto& l : _loggers) l.second->set_formatter(_formatter); } void set_pattern(const std::string& pattern) { std::lock_guard lock(_mutex); _formatter = std::make_shared(pattern); for (auto& l : _loggers) l.second->set_formatter(_formatter); } void set_level(level::level_enum log_level) { std::lock_guard lock(_mutex); for (auto& l : _loggers) l.second->set_level(log_level); _level = log_level; } void set_error_handler(log_err_handler handler) { for (auto& l : _loggers) l.second->set_error_handler(handler); _err_handler = handler; } void set_async_mode(size_t q_size, const async_overflow_policy overflow_policy, const std::function& worker_warmup_cb, const std::chrono::milliseconds& flush_interval_ms, const std::function& worker_teardown_cb) { std::lock_guard lock(_mutex); _async_mode = true; _async_q_size = q_size; _overflow_policy = overflow_policy; _worker_warmup_cb = worker_warmup_cb; _flush_interval_ms = flush_interval_ms; _worker_teardown_cb = worker_teardown_cb; } void set_sync_mode() { std::lock_guard lock(_mutex); _async_mode = false; } static registry_t& instance() { static registry_t s_instance; return s_instance; } private: registry_t() {} registry_t(const registry_t&) = delete; registry_t& operator=(const registry_t&) = delete; void throw_if_exists(const std::string &logger_name) { if (_loggers.find(logger_name) != _loggers.end()) throw spdlog_ex("logger with name '" + logger_name + "' already exists"); } Mutex _mutex; std::unordered_map > _loggers; formatter_ptr _formatter; level::level_enum _level = level::info; log_err_handler _err_handler; bool _async_mode = false; size_t _async_q_size = 0; async_overflow_policy _overflow_policy = async_overflow_policy::block_retry; std::function _worker_warmup_cb = nullptr; std::chrono::milliseconds _flush_interval_ms; std::function _worker_teardown_cb = nullptr; }; #ifdef SPDLOG_NO_REGISTRY_MUTEX typedef registry_t registry; #else typedef registry_t registry; #endif } } gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/Utility/GmmLog/spdlog/details/spdlog_impl.h000066400000000000000000000206221466655022700303010ustar00rootroot00000000000000// // Copyright(c) 2015 Gabi Melman. // Distributed under the MIT License (http://opensource.org/licenses/MIT) // #pragma once // // Global registry functions // #include #include #include #include #ifdef SPDLOG_ENABLE_SYSLOG #include #endif #ifdef _WIN32 #include #else #include #endif #ifdef __ANDROID__ #include #endif #include #include #include #include inline void spdlog::register_logger(std::shared_ptr logger) { return details::registry::instance().register_logger(logger); } inline std::shared_ptr spdlog::get(const std::string& name) { return details::registry::instance().get(name); } inline void spdlog::drop(const std::string &name) { details::registry::instance().drop(name); } // Create multi/single threaded simple file logger inline std::shared_ptr spdlog::basic_logger_mt(const std::string& logger_name, const filename_t& filename, bool truncate) { return create(logger_name, filename, truncate); } inline std::shared_ptr spdlog::basic_logger_st(const std::string& logger_name, const filename_t& filename, bool truncate) { return create(logger_name, filename, truncate); } // Create multi/single threaded rotating file logger inline std::shared_ptr spdlog::rotating_logger_mt(const std::string& logger_name, const filename_t& filename, size_t max_file_size, size_t max_files) { return create(logger_name, filename, SPDLOG_FILENAME_T("txt"), max_file_size, max_files); } inline std::shared_ptr spdlog::rotating_logger_st(const std::string& logger_name, const filename_t& filename, size_t max_file_size, size_t max_files) { return create(logger_name, filename, SPDLOG_FILENAME_T("txt"), max_file_size, max_files); } // Create file logger which creates new file at midnight): inline std::shared_ptr spdlog::daily_logger_mt(const std::string& logger_name, const filename_t& filename, int hour, int minute) { return create(logger_name, filename, SPDLOG_FILENAME_T("txt"), hour, minute); } inline std::shared_ptr spdlog::daily_logger_st(const std::string& logger_name, const filename_t& filename, int hour, int minute) { return create(logger_name, filename, SPDLOG_FILENAME_T("txt"), hour, minute); } // // stdout/stderr loggers // inline std::shared_ptr spdlog::stdout_logger_mt(const std::string& logger_name) { return spdlog::details::registry::instance().create(logger_name, spdlog::sinks::stdout_sink_mt::instance()); } inline std::shared_ptr spdlog::stdout_logger_st(const std::string& logger_name) { return spdlog::details::registry::instance().create(logger_name, spdlog::sinks::stdout_sink_st::instance()); } inline std::shared_ptr spdlog::stderr_logger_mt(const std::string& logger_name) { return spdlog::details::registry::instance().create(logger_name, spdlog::sinks::stderr_sink_mt::instance()); } inline std::shared_ptr spdlog::stderr_logger_st(const std::string& logger_name) { return spdlog::details::registry::instance().create(logger_name, spdlog::sinks::stderr_sink_st::instance()); } // // stdout/stderr color loggers // #ifdef _WIN32 inline std::shared_ptr spdlog::stdout_color_mt(const std::string& logger_name) { auto sink = std::make_shared(); return spdlog::details::registry::instance().create(logger_name, sink); } inline std::shared_ptr spdlog::stdout_color_st(const std::string& logger_name) { auto sink = std::make_shared(); return spdlog::details::registry::instance().create(logger_name, sink); } inline std::shared_ptr spdlog::stderr_color_mt(const std::string& logger_name) { auto sink = std::make_shared(); return spdlog::details::registry::instance().create(logger_name, sink); } inline std::shared_ptr spdlog::stderr_color_st(const std::string& logger_name) { auto sink = std::make_shared(); return spdlog::details::registry::instance().create(logger_name, sink); } #else //ansi terminal colors inline std::shared_ptr spdlog::stdout_color_mt(const std::string& logger_name) { auto sink = std::make_shared(spdlog::sinks::stdout_sink_mt::instance()); return spdlog::details::registry::instance().create(logger_name, sink); } inline std::shared_ptr spdlog::stdout_color_st(const std::string& logger_name) { auto sink = std::make_shared(spdlog::sinks::stdout_sink_st::instance()); return spdlog::details::registry::instance().create(logger_name, sink); } inline std::shared_ptr spdlog::stderr_color_mt(const std::string& logger_name) { auto sink = std::make_shared(spdlog::sinks::stderr_sink_mt::instance()); return spdlog::details::registry::instance().create(logger_name, sink); } inline std::shared_ptr spdlog::stderr_color_st(const std::string& logger_name) { auto sink = std::make_shared(spdlog::sinks::stderr_sink_st::instance()); return spdlog::details::registry::instance().create(logger_name, sink); } #endif #ifdef SPDLOG_ENABLE_SYSLOG // Create syslog logger inline std::shared_ptr spdlog::syslog_logger(const std::string& logger_name, const std::string& syslog_ident, int syslog_option) { return create(logger_name, syslog_ident, syslog_option); } #endif #ifdef __ANDROID__ inline std::shared_ptr spdlog::android_logger(const std::string& logger_name, const std::string& tag) { return create(logger_name, tag); } #endif // Create and register a logger a single sink inline std::shared_ptr spdlog::create(const std::string& logger_name, const spdlog::sink_ptr& sink) { return details::registry::instance().create(logger_name, sink); } //Create logger with multiple sinks inline std::shared_ptr spdlog::create(const std::string& logger_name, spdlog::sinks_init_list sinks) { return details::registry::instance().create(logger_name, sinks); } template inline std::shared_ptr spdlog::create(const std::string& logger_name, Args... args) { sink_ptr sink = std::make_shared(args...); return details::registry::instance().create(logger_name, { sink }); } template inline std::shared_ptr spdlog::create(const std::string& logger_name, const It& sinks_begin, const It& sinks_end) { return details::registry::instance().create(logger_name, sinks_begin, sinks_end); } inline void spdlog::set_formatter(spdlog::formatter_ptr f) { details::registry::instance().formatter(f); } inline void spdlog::set_pattern(const std::string& format_string) { return details::registry::instance().set_pattern(format_string); } inline void spdlog::set_level(level::level_enum log_level) { return details::registry::instance().set_level(log_level); } inline void spdlog::set_error_handler(log_err_handler handler) { return details::registry::instance().set_error_handler(handler); } inline void spdlog::set_async_mode(size_t queue_size, const async_overflow_policy overflow_policy, const std::function& worker_warmup_cb, const std::chrono::milliseconds& flush_interval_ms, const std::function& worker_teardown_cb) { details::registry::instance().set_async_mode(queue_size, overflow_policy, worker_warmup_cb, flush_interval_ms, worker_teardown_cb); } inline void spdlog::set_sync_mode() { details::registry::instance().set_sync_mode(); } inline void spdlog::apply_all(std::function)> fun) { details::registry::instance().apply_all(fun); } inline void spdlog::drop_all() { details::registry::instance().drop_all(); } gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/Utility/GmmLog/spdlog/fmt/000077500000000000000000000000001466655022700247565ustar00rootroot00000000000000gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/Utility/GmmLog/spdlog/fmt/bundled/000077500000000000000000000000001466655022700263735ustar00rootroot00000000000000gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/Utility/GmmLog/spdlog/fmt/bundled/format.cc000066400000000000000000000450051466655022700301760ustar00rootroot00000000000000/* Formatting library for C++ Copyright (c) 2012 - 2016, Victor Zverovich All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ // commented out by spdlog // #include "format.h" // #include "printf.h" #include #include #include #include #include #include #include // for std::ptrdiff_t #if defined(_WIN32) && defined(__MINGW32__) # include #endif #if FMT_USE_WINDOWS_H # if defined(NOMINMAX) || defined(FMT_WIN_MINMAX) # include # else # define NOMINMAX # include # undef NOMINMAX # endif #endif using fmt::internal::Arg; #if FMT_EXCEPTIONS # define FMT_TRY try # define FMT_CATCH(x) catch (x) #else # define FMT_TRY if (true) # define FMT_CATCH(x) if (false) #endif #ifdef _MSC_VER # pragma warning(push) # pragma warning(disable: 4127) // conditional expression is constant # pragma warning(disable: 4702) // unreachable code // Disable deprecation warning for strerror. The latter is not called but // MSVC fails to detect it. # pragma warning(disable: 4996) #endif // Dummy implementations of strerror_r and strerror_s called if corresponding // system functions are not available. static inline fmt::internal::Null<> strerror_r(int, char *, ...) { return fmt::internal::Null<>(); } static inline fmt::internal::Null<> strerror_s(char *, std::size_t, ...) { return fmt::internal::Null<>(); } namespace fmt { FMT_FUNC internal::RuntimeError::~RuntimeError() throw() {} FMT_FUNC FormatError::~FormatError() throw() {} FMT_FUNC SystemError::~SystemError() throw() {} namespace { #ifndef _MSC_VER # define FMT_SNPRINTF snprintf #else // _MSC_VER inline int fmt_snprintf(char *buffer, size_t size, const char *format, ...) { va_list args; va_start(args, format); int result = vsnprintf_s(buffer, size, _TRUNCATE, format, args); va_end(args); return result; } # define FMT_SNPRINTF fmt_snprintf #endif // _MSC_VER #if defined(_WIN32) && defined(__MINGW32__) && !defined(__NO_ISOCEXT) # define FMT_SWPRINTF snwprintf #else # define FMT_SWPRINTF swprintf #endif // defined(_WIN32) && defined(__MINGW32__) && !defined(__NO_ISOCEXT) const char RESET_COLOR[] = "\x1b[0m"; typedef void(*FormatFunc)(Writer &, int, StringRef); // Portable thread-safe version of strerror. // Sets buffer to point to a string describing the error code. // This can be either a pointer to a string stored in buffer, // or a pointer to some static immutable string. // Returns one of the following values: // 0 - success // ERANGE - buffer is not large enough to store the error message // other - failure // Buffer should be at least of size 1. int safe_strerror( int error_code, char *&buffer, std::size_t buffer_size) FMT_NOEXCEPT{ FMT_ASSERT(buffer != 0 && buffer_size != 0, "invalid buffer"); class StrError { private: int error_code_; char *&buffer_; std::size_t buffer_size_; // A noop assignment operator to avoid bogus warnings. void operator=(const StrError &) {} // Handle the result of XSI-compliant version of strerror_r. int handle(int result) { // glibc versions before 2.13 return result in errno. return result == -1 ? errno : result; } // Handle the result of GNU-specific version of strerror_r. int handle(char *message) { // If the buffer is full then the message is probably truncated. if (message == buffer_ && strlen(buffer_) == buffer_size_ - 1) return ERANGE; buffer_ = message; return 0; } // Handle the case when strerror_r is not available. int handle(internal::Null<>) { return fallback(strerror_s(buffer_, buffer_size_, error_code_)); } // Fallback to strerror_s when strerror_r is not available. int fallback(int result) { // If the buffer is full then the message is probably truncated. return result == 0 && strlen(buffer_) == buffer_size_ - 1 ? ERANGE : result; } // Fallback to strerror if strerror_r and strerror_s are not available. int fallback(internal::Null<>) { errno = 0; buffer_ = strerror(error_code_); return errno; } public: StrError(int err_code, char *&buf, std::size_t buf_size) : error_code_(err_code), buffer_(buf), buffer_size_(buf_size) {} int run() { strerror_r(0, 0, ""); // Suppress a warning about unused strerror_r. return handle(strerror_r(error_code_, buffer_, buffer_size_)); } }; return StrError(error_code, buffer, buffer_size).run(); } void format_error_code(Writer &out, int error_code, StringRef message) FMT_NOEXCEPT{ // Report error code making sure that the output fits into // INLINE_BUFFER_SIZE to avoid dynamic memory allocation and potential // bad_alloc. out.clear(); static const char SEP[] = ": "; static const char ERROR_STR[] = "error "; // Subtract 2 to account for terminating null characters in SEP and ERROR_STR. std::size_t error_code_size = sizeof(SEP) + sizeof(ERROR_STR) - 2; typedef internal::IntTraits::MainType MainType; MainType abs_value = static_cast(error_code); if (internal::is_negative(error_code)) { abs_value = 0 - abs_value; ++error_code_size; } error_code_size += internal::count_digits(abs_value); if (message.size() <= internal::INLINE_BUFFER_SIZE - error_code_size) out << message << SEP; out << ERROR_STR << error_code; assert(out.size() <= internal::INLINE_BUFFER_SIZE); } void report_error(FormatFunc func, int error_code, StringRef message) FMT_NOEXCEPT{ MemoryWriter full_message; func(full_message, error_code, message); // Use Writer::data instead of Writer::c_str to avoid potential memory // allocation. std::fwrite(full_message.data(), full_message.size(), 1, stderr); std::fputc('\n', stderr); } } // namespace namespace internal { // This method is used to preserve binary compatibility with fmt 3.0. // It can be removed in 4.0. FMT_FUNC void format_system_error( Writer &out, int error_code, StringRef message) FMT_NOEXCEPT{ fmt::format_system_error(out, error_code, message); } } // namespace internal FMT_FUNC void SystemError::init( int err_code, CStringRef format_str, ArgList args) { error_code_ = err_code; MemoryWriter w; format_system_error(w, err_code, format(format_str, args)); std::runtime_error &base = *this; base = std::runtime_error(w.str()); } template int internal::CharTraits::format_float( char *buffer, std::size_t size, const char *format, unsigned width, int precision, T value) { if (width == 0) { return precision < 0 ? FMT_SNPRINTF(buffer, size, format, value) : FMT_SNPRINTF(buffer, size, format, precision, value); } return precision < 0 ? FMT_SNPRINTF(buffer, size, format, width, value) : FMT_SNPRINTF(buffer, size, format, width, precision, value); } template int internal::CharTraits::format_float( wchar_t *buffer, std::size_t size, const wchar_t *format, unsigned width, int precision, T value) { if (width == 0) { return precision < 0 ? FMT_SWPRINTF(buffer, size, format, value) : FMT_SWPRINTF(buffer, size, format, precision, value); } return precision < 0 ? FMT_SWPRINTF(buffer, size, format, width, value) : FMT_SWPRINTF(buffer, size, format, width, precision, value); } template const char internal::BasicData::DIGITS[] = "0001020304050607080910111213141516171819" "2021222324252627282930313233343536373839" "4041424344454647484950515253545556575859" "6061626364656667686970717273747576777879" "8081828384858687888990919293949596979899"; #define FMT_POWERS_OF_10(factor) \ factor * 10, \ factor * 100, \ factor * 1000, \ factor * 10000, \ factor * 100000, \ factor * 1000000, \ factor * 10000000, \ factor * 100000000, \ factor * 1000000000 template const uint32_t internal::BasicData::POWERS_OF_10_32[] = { 0, FMT_POWERS_OF_10(1) }; template const uint64_t internal::BasicData::POWERS_OF_10_64[] = { 0, FMT_POWERS_OF_10(1), FMT_POWERS_OF_10(ULongLong(1000000000)), // Multiply several constants instead of using a single long long constant // to avoid warnings about C++98 not supporting long long. ULongLong(1000000000) * ULongLong(1000000000) * 10 }; FMT_FUNC void internal::report_unknown_type(char code, const char *type) { (void)type; if (std::isprint(static_cast(code))) { FMT_THROW(FormatError( format("unknown format code '{}' for {}", code, type))); } FMT_THROW(FormatError( format("unknown format code '\\x{:02x}' for {}", static_cast(code), type))); } #if FMT_USE_WINDOWS_H FMT_FUNC internal::UTF8ToUTF16::UTF8ToUTF16(StringRef s) { static const char ERROR_MSG[] = "cannot convert string from UTF-8 to UTF-16"; if (s.size() > INT_MAX) FMT_THROW(WindowsError(ERROR_INVALID_PARAMETER, ERROR_MSG)); int s_size = static_cast(s.size()); int length = MultiByteToWideChar( CP_UTF8, MB_ERR_INVALID_CHARS, s.data(), s_size, 0, 0); if (length == 0) FMT_THROW(WindowsError(GetLastError(), ERROR_MSG)); buffer_.resize(length + 1); length = MultiByteToWideChar( CP_UTF8, MB_ERR_INVALID_CHARS, s.data(), s_size, &buffer_[0], length); if (length == 0) FMT_THROW(WindowsError(GetLastError(), ERROR_MSG)); buffer_[length] = 0; } FMT_FUNC internal::UTF16ToUTF8::UTF16ToUTF8(WStringRef s) { if (int error_code = convert(s)) { FMT_THROW(WindowsError(error_code, "cannot convert string from UTF-16 to UTF-8")); } } FMT_FUNC int internal::UTF16ToUTF8::convert(WStringRef s) { if (s.size() > INT_MAX) return ERROR_INVALID_PARAMETER; int s_size = static_cast(s.size()); int length = WideCharToMultiByte(CP_UTF8, 0, s.data(), s_size, 0, 0, 0, 0); if (length == 0) return GetLastError(); buffer_.resize(length + 1); length = WideCharToMultiByte( CP_UTF8, 0, s.data(), s_size, &buffer_[0], length, 0, 0); if (length == 0) return GetLastError(); buffer_[length] = 0; return 0; } FMT_FUNC void WindowsError::init( int err_code, CStringRef format_str, ArgList args) { error_code_ = err_code; MemoryWriter w; internal::format_windows_error(w, err_code, format(format_str, args)); std::runtime_error &base = *this; base = std::runtime_error(w.str()); } FMT_FUNC void internal::format_windows_error( Writer &out, int error_code, StringRef message) FMT_NOEXCEPT{ FMT_TRY{ MemoryBuffer buffer; buffer.resize(INLINE_BUFFER_SIZE); for (;;) { wchar_t *system_message = &buffer[0]; int result = FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, 0, error_code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), system_message, static_cast(buffer.size()), 0); if (result != 0) { UTF16ToUTF8 utf8_message; if (utf8_message.convert(system_message) == ERROR_SUCCESS) { out << message << ": " << utf8_message; return; } break; } if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) break; // Can't get error message, report error code instead. buffer.resize(buffer.size() * 2); } } FMT_CATCH(...) {} fmt::format_error_code(out, error_code, message); // 'fmt::' is for bcc32. } #endif // FMT_USE_WINDOWS_H FMT_FUNC void format_system_error( Writer &out, int error_code, StringRef message) FMT_NOEXCEPT{ FMT_TRY{ internal::MemoryBuffer buffer; buffer.resize(internal::INLINE_BUFFER_SIZE); for (;;) { char *system_message = &buffer[0]; int result = safe_strerror(error_code, system_message, buffer.size()); if (result == 0) { out << message << ": " << system_message; return; } if (result != ERANGE) break; // Can't get error message, report error code instead. buffer.resize(buffer.size() * 2); } } FMT_CATCH(...) {} fmt::format_error_code(out, error_code, message); // 'fmt::' is for bcc32. } template void internal::ArgMap::init(const ArgList &args) { if (!map_.empty()) return; typedef internal::NamedArg NamedArg; const NamedArg *named_arg = 0; bool use_values = args.type(ArgList::MAX_PACKED_ARGS - 1) == internal::Arg::NONE; if (use_values) { for (unsigned i = 0;/*nothing*/; ++i) { internal::Arg::Type arg_type = args.type(i); switch (arg_type) { case internal::Arg::NONE: return; case internal::Arg::NAMED_ARG: named_arg = static_cast(args.values_[i].pointer); map_.push_back(Pair(named_arg->name, *named_arg)); break; default: /*nothing*/ ; } } return; } for (unsigned i = 0; i != ArgList::MAX_PACKED_ARGS; ++i) { internal::Arg::Type arg_type = args.type(i); if (arg_type == internal::Arg::NAMED_ARG) { named_arg = static_cast(args.args_[i].pointer); map_.push_back(Pair(named_arg->name, *named_arg)); } } for (unsigned i = ArgList::MAX_PACKED_ARGS;/*nothing*/; ++i) { switch (args.args_[i].type) { case internal::Arg::NONE: return; case internal::Arg::NAMED_ARG: named_arg = static_cast(args.args_[i].pointer); map_.push_back(Pair(named_arg->name, *named_arg)); break; default: /*nothing*/ ; } } } template void internal::FixedBuffer::grow(std::size_t) { FMT_THROW(std::runtime_error("buffer overflow")); } FMT_FUNC Arg internal::FormatterBase::do_get_arg( unsigned arg_index, const char *&error) { Arg arg = args_[arg_index]; switch (arg.type) { case Arg::NONE: error = "argument index out of range"; break; case Arg::NAMED_ARG: arg = *static_cast(arg.pointer); break; default: /*nothing*/ ; } return arg; } FMT_FUNC void report_system_error( int error_code, fmt::StringRef message) FMT_NOEXCEPT{ // 'fmt::' is for bcc32. report_error(format_system_error, error_code, message); } #if FMT_USE_WINDOWS_H FMT_FUNC void report_windows_error( int error_code, fmt::StringRef message) FMT_NOEXCEPT{ // 'fmt::' is for bcc32. report_error(internal::format_windows_error, error_code, message); } #endif FMT_FUNC void print(std::FILE *f, CStringRef format_str, ArgList args) { MemoryWriter w; w.write(format_str, args); std::fwrite(w.data(), 1, w.size(), f); } FMT_FUNC void print(CStringRef format_str, ArgList args) { print(stdout, format_str, args); } FMT_FUNC void print_colored(Color c, CStringRef format, ArgList args) { char escape[] = "\x1b[30m"; escape[3] = static_cast('0' + c); std::fputs(escape, stdout); print(format, args); std::fputs(RESET_COLOR, stdout); } template void printf(BasicWriter &w, BasicCStringRef format, ArgList args); FMT_FUNC int fprintf(std::FILE *f, CStringRef format, ArgList args) { MemoryWriter w; printf(w, format, args); std::size_t size = w.size(); return std::fwrite(w.data(), 1, size, f) < size ? -1 : static_cast(size); } #ifndef FMT_HEADER_ONLY template struct internal::BasicData; // Explicit instantiations for char. template void internal::FixedBuffer::grow(std::size_t); template void internal::ArgMap::init(const ArgList &args); template void PrintfFormatter::format(CStringRef format); template int internal::CharTraits::format_float( char *buffer, std::size_t size, const char *format, unsigned width, int precision, double value); template int internal::CharTraits::format_float( char *buffer, std::size_t size, const char *format, unsigned width, int precision, long double value); // Explicit instantiations for wchar_t. template void internal::FixedBuffer::grow(std::size_t); template void internal::ArgMap::init(const ArgList &args); template void PrintfFormatter::format(WCStringRef format); template int internal::CharTraits::format_float( wchar_t *buffer, std::size_t size, const wchar_t *format, unsigned width, int precision, double value); template int internal::CharTraits::format_float( wchar_t *buffer, std::size_t size, const wchar_t *format, unsigned width, int precision, long double value); #endif // FMT_HEADER_ONLY } // namespace fmt #ifdef _MSC_VER # pragma warning(pop) #endifgmmlib-intel-gmmlib-22.5.2/Source/GmmLib/Utility/GmmLog/spdlog/fmt/bundled/format.h000066400000000000000000003653071466655022700300520ustar00rootroot00000000000000/* Formatting library for C++ Copyright (c) 2012 - 2016, Victor Zverovich All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef FMT_FORMAT_H_ #define FMT_FORMAT_H_ #include #include #include #include #include #include #include #include #include #include #include #ifdef _SECURE_SCL # define FMT_SECURE_SCL _SECURE_SCL #else # define FMT_SECURE_SCL 0 #endif #if FMT_SECURE_SCL # include #endif #ifdef _MSC_VER # define FMT_MSC_VER _MSC_VER #else # define FMT_MSC_VER 0 #endif #if FMT_MSC_VER && FMT_MSC_VER <= 1500 typedef unsigned __int32 uint32_t; typedef unsigned __int64 uint64_t; typedef __int64 intmax_t; #else #include #endif #if !defined(FMT_HEADER_ONLY) && defined(_WIN32) # ifdef FMT_EXPORT # define FMT_API __declspec(dllexport) # elif defined(FMT_SHARED) # define FMT_API __declspec(dllimport) # endif #endif #ifndef FMT_API # define FMT_API #endif #ifdef __GNUC__ # define FMT_GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__) # define FMT_GCC_EXTENSION __extension__ # if FMT_GCC_VERSION >= 406 # pragma GCC diagnostic push // Disable the warning about "long long" which is sometimes reported even // when using __extension__. # pragma GCC diagnostic ignored "-Wlong-long" // Disable the warning about declaration shadowing because it affects too // many valid cases. # pragma GCC diagnostic ignored "-Wshadow" // Disable the warning about implicit conversions that may change the sign of // an integer; silencing it otherwise would require many explicit casts. # pragma GCC diagnostic ignored "-Wsign-conversion" # endif # if __cplusplus >= 201103L || defined __GXX_EXPERIMENTAL_CXX0X__ # define FMT_HAS_GXX_CXX11 1 # endif #else # define FMT_GCC_EXTENSION #endif #if defined(__INTEL_COMPILER) # define FMT_ICC_VERSION __INTEL_COMPILER #elif defined(__ICL) # define FMT_ICC_VERSION __ICL #endif #if defined(__clang__) && !defined(FMT_ICC_VERSION) # pragma clang diagnostic push # pragma clang diagnostic ignored "-Wdocumentation-unknown-command" # pragma clang diagnostic ignored "-Wpadded" #endif #ifdef __GNUC_LIBSTD__ # define FMT_GNUC_LIBSTD_VERSION (__GNUC_LIBSTD__ * 100 + __GNUC_LIBSTD_MINOR__) #endif #ifdef __has_feature # define FMT_HAS_FEATURE(x) __has_feature(x) #else # define FMT_HAS_FEATURE(x) 0 #endif #ifdef __has_builtin # define FMT_HAS_BUILTIN(x) __has_builtin(x) #else # define FMT_HAS_BUILTIN(x) 0 #endif #ifdef __has_cpp_attribute # define FMT_HAS_CPP_ATTRIBUTE(x) __has_cpp_attribute(x) #else # define FMT_HAS_CPP_ATTRIBUTE(x) 0 #endif #ifndef FMT_USE_VARIADIC_TEMPLATES // Variadic templates are available in GCC since version 4.4 // (http://gcc.gnu.org/projects/cxx0x.html) and in Visual C++ // since version 2013. # define FMT_USE_VARIADIC_TEMPLATES \ (FMT_HAS_FEATURE(cxx_variadic_templates) || \ (FMT_GCC_VERSION >= 404 && FMT_HAS_GXX_CXX11) || FMT_MSC_VER >= 1800) #endif #ifndef FMT_USE_RVALUE_REFERENCES // Don't use rvalue references when compiling with clang and an old libstdc++ // as the latter doesn't provide std::move. # if defined(FMT_GNUC_LIBSTD_VERSION) && FMT_GNUC_LIBSTD_VERSION <= 402 # define FMT_USE_RVALUE_REFERENCES 0 # else # define FMT_USE_RVALUE_REFERENCES \ (FMT_HAS_FEATURE(cxx_rvalue_references) || \ (FMT_GCC_VERSION >= 403 && FMT_HAS_GXX_CXX11) || FMT_MSC_VER >= 1600) # endif #endif #if FMT_USE_RVALUE_REFERENCES # include // for std::move #endif // Check if exceptions are disabled. #if defined(__GNUC__) && !defined(__EXCEPTIONS) # define FMT_EXCEPTIONS 0 #endif #if FMT_MSC_VER && !_HAS_EXCEPTIONS # define FMT_EXCEPTIONS 0 #endif #ifndef FMT_EXCEPTIONS # define FMT_EXCEPTIONS 1 #endif #ifndef FMT_THROW # if FMT_EXCEPTIONS # define FMT_THROW(x) throw x # else # define FMT_THROW(x) assert(false) # endif #endif // Define FMT_USE_NOEXCEPT to make fmt use noexcept (C++11 feature). #ifndef FMT_USE_NOEXCEPT # define FMT_USE_NOEXCEPT 0 #endif #ifndef FMT_NOEXCEPT # if FMT_EXCEPTIONS # if FMT_USE_NOEXCEPT || FMT_HAS_FEATURE(cxx_noexcept) || \ (FMT_GCC_VERSION >= 408 && FMT_HAS_GXX_CXX11) || \ FMT_MSC_VER >= 1900 # define FMT_NOEXCEPT noexcept # else # define FMT_NOEXCEPT throw() # endif # else # define FMT_NOEXCEPT # endif #endif #ifndef FMT_OVERRIDE # if FMT_USE_OVERRIDE || FMT_HAS_FEATURE(cxx_override) || \ (FMT_GCC_VERSION >= 408 && FMT_HAS_GXX_CXX11) || \ FMT_MSC_VER >= 1900 # define FMT_OVERRIDE override # else # define FMT_OVERRIDE # endif #endif // A macro to disallow the copy constructor and operator= functions // This should be used in the private: declarations for a class #ifndef FMT_USE_DELETED_FUNCTIONS # define FMT_USE_DELETED_FUNCTIONS 0 #endif #if FMT_USE_DELETED_FUNCTIONS || FMT_HAS_FEATURE(cxx_deleted_functions) || \ (FMT_GCC_VERSION >= 404 && FMT_HAS_GXX_CXX11) || FMT_MSC_VER >= 1800 # define FMT_DELETED_OR_UNDEFINED = delete # define FMT_DISALLOW_COPY_AND_ASSIGN(TypeName) \ TypeName(const TypeName&) = delete; \ TypeName& operator=(const TypeName&) = delete #else # define FMT_DELETED_OR_UNDEFINED # define FMT_DISALLOW_COPY_AND_ASSIGN(TypeName) \ TypeName(const TypeName&); \ TypeName& operator=(const TypeName&) #endif #ifndef FMT_USE_USER_DEFINED_LITERALS // All compilers which support UDLs also support variadic templates. This // makes the fmt::literals implementation easier. However, an explicit check // for variadic templates is added here just in case. // For Intel's compiler both it and the system gcc/msc must support UDLs. # define FMT_USE_USER_DEFINED_LITERALS \ FMT_USE_VARIADIC_TEMPLATES && FMT_USE_RVALUE_REFERENCES && \ (FMT_HAS_FEATURE(cxx_user_literals) || \ (FMT_GCC_VERSION >= 407 && FMT_HAS_GXX_CXX11) || FMT_MSC_VER >= 1900) && \ (!defined(FMT_ICC_VERSION) || FMT_ICC_VERSION >= 1500) #endif #ifndef FMT_ASSERT # define FMT_ASSERT(condition, message) assert((condition) && message) #endif #if FMT_GCC_VERSION >= 400 || FMT_HAS_BUILTIN(__builtin_clz) # define FMT_BUILTIN_CLZ(n) __builtin_clz(n) #endif #if FMT_GCC_VERSION >= 400 || FMT_HAS_BUILTIN(__builtin_clzll) # define FMT_BUILTIN_CLZLL(n) __builtin_clzll(n) #endif // Some compilers masquerade as both MSVC and GCC-likes or // otherwise support __builtin_clz and __builtin_clzll, so // only define FMT_BUILTIN_CLZ using the MSVC intrinsics // if the clz and clzll builtins are not available. #if FMT_MSC_VER && !defined(FMT_BUILTIN_CLZLL) # include // _BitScanReverse, _BitScanReverse64 namespace fmt { namespace internal { # pragma intrinsic(_BitScanReverse) inline uint32_t clz(uint32_t x) { unsigned long r = 0; _BitScanReverse(&r, x); assert(x != 0); // Static analysis complains about using uninitialized data // "r", but the only way that can happen is if "x" is 0, // which the callers guarantee to not happen. # pragma warning(suppress: 6102) return 31 - r; } # define FMT_BUILTIN_CLZ(n) fmt::internal::clz(n) # ifdef _WIN64 # pragma intrinsic(_BitScanReverse64) # endif inline uint32_t clzll(uint64_t x) { unsigned long r = 0; # ifdef _WIN64 _BitScanReverse64(&r, x); # else // Scan the high 32 bits. if (_BitScanReverse(&r, static_cast(x >> 32))) return 63 - (r + 32); // Scan the low 32 bits. _BitScanReverse(&r, static_cast(x)); # endif assert(x != 0); // Static analysis complains about using uninitialized data // "r", but the only way that can happen is if "x" is 0, // which the callers guarantee to not happen. # pragma warning(suppress: 6102) return 63 - r; } # define FMT_BUILTIN_CLZLL(n) fmt::internal::clzll(n) } } #endif namespace fmt { namespace internal { struct DummyInt { int data[2]; operator int() const { return 0; } }; typedef std::numeric_limits FPUtil; // Dummy implementations of system functions such as signbit and ecvt called // if the latter are not available. inline DummyInt signbit(...) { return DummyInt(); } inline DummyInt _ecvt_s(...) { return DummyInt(); } inline DummyInt isinf(...) { return DummyInt(); } inline DummyInt _finite(...) { return DummyInt(); } inline DummyInt isnan(...) { return DummyInt(); } inline DummyInt _isnan(...) { return DummyInt(); } // A helper function to suppress bogus "conditional expression is constant" // warnings. template inline T const_check(T value) { return value; } } } // namespace fmt namespace std { // Standard permits specialization of std::numeric_limits. This specialization // is used to resolve ambiguity between isinf and std::isinf in glibc: // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=48891 // and the same for isnan and signbit. template <> class numeric_limits : public std::numeric_limits { public: // Portable version of isinf. template static bool isinfinity(T x) { using namespace fmt::internal; // The resolution "priority" is: // isinf macro > std::isinf > ::isinf > fmt::internal::isinf if (const_check(sizeof(isinf(x)) == sizeof(bool) || sizeof(isinf(x)) == sizeof(int))) { return isinf(x) != 0; } return !_finite(static_cast(x)); } // Portable version of isnan. template static bool isnotanumber(T x) { using namespace fmt::internal; if (const_check(sizeof(isnan(x)) == sizeof(bool) || sizeof(isnan(x)) == sizeof(int))) { return isnan(x) != 0; } return _isnan(static_cast(x)) != 0; } // Portable version of signbit. static bool isnegative(double x) { using namespace fmt::internal; if (const_check(sizeof(signbit(x)) == sizeof(int))) return signbit(x) != 0; if (x < 0) return true; if (!isnotanumber(x)) return false; int dec = 0, sign = 0; char buffer[2]; // The buffer size must be >= 2 or _ecvt_s will fail. _ecvt_s(buffer, sizeof(buffer), x, 0, &dec, &sign); return sign != 0; } }; } // namespace std namespace fmt { // Fix the warning about long long on older versions of GCC // that don't support the diagnostic pragma. FMT_GCC_EXTENSION typedef long long LongLong; FMT_GCC_EXTENSION typedef unsigned long long ULongLong; #if FMT_USE_RVALUE_REFERENCES using std::move; #endif template class BasicWriter; typedef BasicWriter Writer; typedef BasicWriter WWriter; template class ArgFormatter; template class BasicPrintfArgFormatter; template > class BasicFormatter; /** \rst A string reference. It can be constructed from a C string or ``std::string``. You can use one of the following typedefs for common character types: +------------+-------------------------+ | Type | Definition | +============+=========================+ | StringRef | BasicStringRef | +------------+-------------------------+ | WStringRef | BasicStringRef | +------------+-------------------------+ This class is most useful as a parameter type to allow passing different types of strings to a function, for example:: template std::string format(StringRef format_str, const Args & ... args); format("{}", 42); format(std::string("{}"), 42); \endrst */ template class BasicStringRef { private: const Char *data_; std::size_t size_; public: /** Constructs a string reference object from a C string and a size. */ BasicStringRef(const Char *s, std::size_t size) : data_(s), size_(size) {} /** \rst Constructs a string reference object from a C string computing the size with ``std::char_traits::length``. \endrst */ BasicStringRef(const Char *s) : data_(s), size_(std::char_traits::length(s)) {} /** \rst Constructs a string reference from an ``std::string`` object. \endrst */ BasicStringRef(const std::basic_string &s) : data_(s.c_str()), size_(s.size()) {} /** \rst Converts a string reference to an ``std::string`` object. \endrst */ std::basic_string to_string() const { return std::basic_string(data_, size_); } /** Returns a pointer to the string data. */ const Char *data() const { return data_; } /** Returns the string size. */ std::size_t size() const { return size_; } // Lexicographically compare this string reference to other. int compare(BasicStringRef other) const { std::size_t size = size_ < other.size_ ? size_ : other.size_; int result = std::char_traits::compare(data_, other.data_, size); if (result == 0) result = size_ == other.size_ ? 0 : (size_ < other.size_ ? -1 : 1); return result; } friend bool operator==(BasicStringRef lhs, BasicStringRef rhs) { return lhs.compare(rhs) == 0; } friend bool operator!=(BasicStringRef lhs, BasicStringRef rhs) { return lhs.compare(rhs) != 0; } friend bool operator<(BasicStringRef lhs, BasicStringRef rhs) { return lhs.compare(rhs) < 0; } friend bool operator<=(BasicStringRef lhs, BasicStringRef rhs) { return lhs.compare(rhs) <= 0; } friend bool operator>(BasicStringRef lhs, BasicStringRef rhs) { return lhs.compare(rhs) > 0; } friend bool operator>=(BasicStringRef lhs, BasicStringRef rhs) { return lhs.compare(rhs) >= 0; } }; typedef BasicStringRef StringRef; typedef BasicStringRef WStringRef; /** \rst A reference to a null terminated string. It can be constructed from a C string or ``std::string``. You can use one of the following typedefs for common character types: +-------------+--------------------------+ | Type | Definition | +=============+==========================+ | CStringRef | BasicCStringRef | +-------------+--------------------------+ | WCStringRef | BasicCStringRef | +-------------+--------------------------+ This class is most useful as a parameter type to allow passing different types of strings to a function, for example:: template std::string format(CStringRef format_str, const Args & ... args); format("{}", 42); format(std::string("{}"), 42); \endrst */ template class BasicCStringRef { private: const Char *data_; public: /** Constructs a string reference object from a C string. */ BasicCStringRef(const Char *s) : data_(s) {} /** \rst Constructs a string reference from an ``std::string`` object. \endrst */ BasicCStringRef(const std::basic_string &s) : data_(s.c_str()) {} /** Returns the pointer to a C string. */ const Char *c_str() const { return data_; } }; typedef BasicCStringRef CStringRef; typedef BasicCStringRef WCStringRef; /** A formatting error such as invalid format string. */ class FormatError : public std::runtime_error { public: explicit FormatError(CStringRef message) : std::runtime_error(message.c_str()) {} ~FormatError() throw(); }; namespace internal { // MakeUnsigned::Type gives an unsigned type corresponding to integer type T. template struct MakeUnsigned { typedef T Type; }; #define FMT_SPECIALIZE_MAKE_UNSIGNED(T, U) \ template <> \ struct MakeUnsigned { typedef U Type; } FMT_SPECIALIZE_MAKE_UNSIGNED(char, unsigned char); FMT_SPECIALIZE_MAKE_UNSIGNED(signed char, unsigned char); FMT_SPECIALIZE_MAKE_UNSIGNED(short, unsigned short); FMT_SPECIALIZE_MAKE_UNSIGNED(int, unsigned); FMT_SPECIALIZE_MAKE_UNSIGNED(long, unsigned long); FMT_SPECIALIZE_MAKE_UNSIGNED(LongLong, ULongLong); // Casts nonnegative integer to unsigned. template inline typename MakeUnsigned::Type to_unsigned(Int value) { FMT_ASSERT(value >= 0, "negative value"); return static_cast::Type>(value); } // The number of characters to store in the MemoryBuffer object itself // to avoid dynamic memory allocation. enum { INLINE_BUFFER_SIZE = 500 }; #if FMT_SECURE_SCL // Use checked iterator to avoid warnings on MSVC. template inline stdext::checked_array_iterator make_ptr(T *ptr, std::size_t size) { return stdext::checked_array_iterator(ptr, size); } #else template inline T *make_ptr(T *ptr, std::size_t) { return ptr; } #endif } // namespace internal /** \rst A buffer supporting a subset of ``std::vector``'s operations. \endrst */ template class Buffer { private: FMT_DISALLOW_COPY_AND_ASSIGN(Buffer); protected: T *ptr_; std::size_t size_; std::size_t capacity_; Buffer(T *ptr = 0, std::size_t capacity = 0) : ptr_(ptr), size_(0), capacity_(capacity) {} /** \rst Increases the buffer capacity to hold at least *size* elements updating ``ptr_`` and ``capacity_``. \endrst */ virtual void grow(std::size_t size) = 0; public: virtual ~Buffer() {} /** Returns the size of this buffer. */ std::size_t size() const { return size_; } /** Returns the capacity of this buffer. */ std::size_t capacity() const { return capacity_; } /** Resizes the buffer. If T is a POD type new elements may not be initialized. */ void resize(std::size_t new_size) { if (new_size > capacity_) grow(new_size); size_ = new_size; } /** \rst Reserves space to store at least *capacity* elements. \endrst */ void reserve(std::size_t capacity) { if (capacity > capacity_) grow(capacity); } void clear() FMT_NOEXCEPT{ size_ = 0; } void push_back(const T &value) { if (size_ == capacity_) grow(size_ + 1); ptr_[size_++] = value; } /** Appends data to the end of the buffer. */ template void append(const U *begin, const U *end); T &operator[](std::size_t index) { return ptr_[index]; } const T &operator[](std::size_t index) const { return ptr_[index]; } }; template template void Buffer::append(const U *begin, const U *end) { std::size_t new_size = size_ + internal::to_unsigned(end - begin); if (new_size > capacity_) grow(new_size); std::uninitialized_copy(begin, end, internal::make_ptr(ptr_, capacity_) + size_); size_ = new_size; } namespace internal { // A memory buffer for trivially copyable/constructible types with the first // SIZE elements stored in the object itself. template > class MemoryBuffer : private Allocator, public Buffer { private: T data_[SIZE]; // Deallocate memory allocated by the buffer. void deallocate() { if (this->ptr_ != data_) Allocator::deallocate(this->ptr_, this->capacity_); } protected: void grow(std::size_t size) FMT_OVERRIDE; public: explicit MemoryBuffer(const Allocator &alloc = Allocator()) : Allocator(alloc), Buffer(data_, SIZE) {} ~MemoryBuffer() { deallocate(); } #if FMT_USE_RVALUE_REFERENCES private: // Move data from other to this buffer. void move(MemoryBuffer &other) { Allocator &this_alloc = *this, &other_alloc = other; this_alloc = std::move(other_alloc); this->size_ = other.size_; this->capacity_ = other.capacity_; if (other.ptr_ == other.data_) { this->ptr_ = data_; std::uninitialized_copy(other.data_, other.data_ + this->size_, make_ptr(data_, this->capacity_)); } else { this->ptr_ = other.ptr_; // Set pointer to the inline array so that delete is not called // when deallocating. other.ptr_ = other.data_; } } public: MemoryBuffer(MemoryBuffer &&other) { move(other); } MemoryBuffer &operator=(MemoryBuffer &&other) { assert(this != &other); deallocate(); move(other); return *this; } #endif // Returns a copy of the allocator associated with this buffer. Allocator get_allocator() const { return *this; } }; template void MemoryBuffer::grow(std::size_t size) { std::size_t new_capacity = this->capacity_ + this->capacity_ / 2; if (size > new_capacity) new_capacity = size; T *new_ptr = this->allocate(new_capacity); // The following code doesn't throw, so the raw pointer above doesn't leak. std::uninitialized_copy(this->ptr_, this->ptr_ + this->size_, make_ptr(new_ptr, new_capacity)); std::size_t old_capacity = this->capacity_; T *old_ptr = this->ptr_; this->capacity_ = new_capacity; this->ptr_ = new_ptr; // deallocate may throw (at least in principle), but it doesn't matter since // the buffer already uses the new storage and will deallocate it in case // of exception. if (old_ptr != data_) Allocator::deallocate(old_ptr, old_capacity); } // A fixed-size buffer. template class FixedBuffer : public fmt::Buffer { public: FixedBuffer(Char *array, std::size_t size) : fmt::Buffer(array, size) {} protected: FMT_API void grow(std::size_t size); }; template class BasicCharTraits { public: #if FMT_SECURE_SCL typedef stdext::checked_array_iterator CharPtr; #else typedef Char *CharPtr; #endif static Char cast(int value) { return static_cast(value); } }; template class CharTraits; template <> class CharTraits : public BasicCharTraits { private: // Conversion from wchar_t to char is not allowed. static char convert(wchar_t); public: static char convert(char value) { return value; } // Formats a floating-point number. template FMT_API static int format_float(char *buffer, std::size_t size, const char *format, unsigned width, int precision, T value); }; template <> class CharTraits : public BasicCharTraits { public: static wchar_t convert(char value) { return value; } static wchar_t convert(wchar_t value) { return value; } template FMT_API static int format_float(wchar_t *buffer, std::size_t size, const wchar_t *format, unsigned width, int precision, T value); }; // Checks if a number is negative - used to avoid warnings. template struct SignChecker { template static bool is_negative(T value) { return value < 0; } }; template <> struct SignChecker { template static bool is_negative(T) { return false; } }; // Returns true if value is negative, false otherwise. // Same as (value < 0) but doesn't produce warnings if T is an unsigned type. template inline bool is_negative(T value) { return SignChecker::is_signed>::is_negative(value); } // Selects uint32_t if FitsIn32Bits is true, uint64_t otherwise. template struct TypeSelector { typedef uint32_t Type; }; template <> struct TypeSelector { typedef uint64_t Type; }; template struct IntTraits { // Smallest of uint32_t and uint64_t that is large enough to represent // all values of T. typedef typename TypeSelector::digits <= 32>::Type MainType; }; FMT_API void report_unknown_type(char code, const char *type); // Static data is placed in this class template to allow header-only // configuration. template struct FMT_API BasicData { static const uint32_t POWERS_OF_10_32[]; static const uint64_t POWERS_OF_10_64[]; static const char DIGITS[]; }; #ifndef FMT_USE_EXTERN_TEMPLATES // Clang doesn't have a feature check for extern templates so we check // for variadic templates which were introduced in the same version. # define FMT_USE_EXTERN_TEMPLATES (__clang__ && FMT_USE_VARIADIC_TEMPLATES) #endif #if FMT_USE_EXTERN_TEMPLATES && !defined(FMT_HEADER_ONLY) extern template struct BasicData; #endif typedef BasicData<> Data; #ifdef FMT_BUILTIN_CLZLL // Returns the number of decimal digits in n. Leading zeros are not counted // except for n == 0 in which case count_digits returns 1. inline unsigned count_digits(uint64_t n) { // Based on http://graphics.stanford.edu/~seander/bithacks.html#IntegerLog10 // and the benchmark https://github.com/localvoid/cxx-benchmark-count-digits. int t = (64 - FMT_BUILTIN_CLZLL(n | 1)) * 1233 >> 12; return to_unsigned(t) - (n < Data::POWERS_OF_10_64[t]) + 1; } #else // Fallback version of count_digits used when __builtin_clz is not available. inline unsigned count_digits(uint64_t n) { unsigned count = 1; for (;;) { // Integer division is slow so do it for a group of four digits instead // of for every digit. The idea comes from the talk by Alexandrescu // "Three Optimization Tips for C++". See speed-test for a comparison. if (n < 10) return count; if (n < 100) return count + 1; if (n < 1000) return count + 2; if (n < 10000) return count + 3; n /= 10000u; count += 4; } } #endif #ifdef FMT_BUILTIN_CLZ // Optional version of count_digits for better performance on 32-bit platforms. inline unsigned count_digits(uint32_t n) { int t = (32 - FMT_BUILTIN_CLZ(n | 1)) * 1233 >> 12; return to_unsigned(t) - (n < Data::POWERS_OF_10_32[t]) + 1; } #endif // A functor that doesn't add a thousands separator. struct NoThousandsSep { template void operator()(Char *) {} }; // A functor that adds a thousands separator. class ThousandsSep { private: fmt::StringRef sep_; // Index of a decimal digit with the least significant digit having index 0. unsigned digit_index_; public: explicit ThousandsSep(fmt::StringRef sep) : sep_(sep), digit_index_(0) {} template void operator()(Char *&buffer) { if (++digit_index_ % 3 != 0) return; buffer -= sep_.size(); std::uninitialized_copy(sep_.data(), sep_.data() + sep_.size(), internal::make_ptr(buffer, sep_.size())); } }; // Formats a decimal unsigned integer value writing into buffer. // thousands_sep is a functor that is called after writing each char to // add a thousands separator if necessary. template inline void format_decimal(Char *buffer, UInt value, unsigned num_digits, ThousandsSep thousands_sep) { buffer += num_digits; while (value >= 100) { // Integer division is slow so do it for a group of two digits instead // of for every digit. The idea comes from the talk by Alexandrescu // "Three Optimization Tips for C++". See speed-test for a comparison. unsigned index = static_cast((value % 100) * 2); value /= 100; *--buffer = Data::DIGITS[index + 1]; thousands_sep(buffer); *--buffer = Data::DIGITS[index]; thousands_sep(buffer); } if (value < 10) { *--buffer = static_cast('0' + value); return; } unsigned index = static_cast(value * 2); *--buffer = Data::DIGITS[index + 1]; thousands_sep(buffer); *--buffer = Data::DIGITS[index]; } template inline void format_decimal(Char *buffer, UInt value, unsigned num_digits) { return format_decimal(buffer, value, num_digits, NoThousandsSep()); } #ifndef _WIN32 # define FMT_USE_WINDOWS_H 0 #elif !defined(FMT_USE_WINDOWS_H) # define FMT_USE_WINDOWS_H 1 #endif // Define FMT_USE_WINDOWS_H to 0 to disable use of windows.h. // All the functionality that relies on it will be disabled too. #if FMT_USE_WINDOWS_H // A converter from UTF-8 to UTF-16. // It is only provided for Windows since other systems support UTF-8 natively. class UTF8ToUTF16 { private: MemoryBuffer buffer_; public: FMT_API explicit UTF8ToUTF16(StringRef s); operator WStringRef() const { return WStringRef(&buffer_[0], size()); } size_t size() const { return buffer_.size() - 1; } const wchar_t *c_str() const { return &buffer_[0]; } std::wstring str() const { return std::wstring(&buffer_[0], size()); } }; // A converter from UTF-16 to UTF-8. // It is only provided for Windows since other systems support UTF-8 natively. class UTF16ToUTF8 { private: MemoryBuffer buffer_; public: UTF16ToUTF8() {} FMT_API explicit UTF16ToUTF8(WStringRef s); operator StringRef() const { return StringRef(&buffer_[0], size()); } size_t size() const { return buffer_.size() - 1; } const char *c_str() const { return &buffer_[0]; } std::string str() const { return std::string(&buffer_[0], size()); } // Performs conversion returning a system error code instead of // throwing exception on conversion error. This method may still throw // in case of memory allocation error. FMT_API int convert(WStringRef s); }; FMT_API void format_windows_error(fmt::Writer &out, int error_code, fmt::StringRef message) FMT_NOEXCEPT; #endif // A formatting argument value. struct Value { template struct StringValue { const Char *value; std::size_t size; }; typedef void(*FormatFunc)( void *formatter, const void *arg, void *format_str_ptr); struct CustomValue { const void *value; FormatFunc format; }; union { int int_value; unsigned uint_value; LongLong long_long_value; ULongLong ulong_long_value; double double_value; long double long_double_value; const void *pointer; StringValue string; StringValue sstring; StringValue ustring; StringValue wstring; CustomValue custom; }; enum Type { NONE, NAMED_ARG, // Integer types should go first, INT, UINT, LONG_LONG, ULONG_LONG, BOOL, CHAR, LAST_INTEGER_TYPE = CHAR, // followed by floating-point types. DOUBLE, LONG_DOUBLE, LAST_NUMERIC_TYPE = LONG_DOUBLE, CSTRING, STRING, WSTRING, POINTER, CUSTOM }; }; // A formatting argument. It is a trivially copyable/constructible type to // allow storage in internal::MemoryBuffer. struct Arg : Value { Type type; }; template struct NamedArg; template struct NamedArgWithType; template struct Null {}; // A helper class template to enable or disable overloads taking wide // characters and strings in MakeValue. template struct WCharHelper { typedef Null Supported; typedef T Unsupported; }; template struct WCharHelper { typedef T Supported; typedef Null Unsupported; }; typedef char Yes[1]; typedef char No[2]; template T &get(); // These are non-members to workaround an overload resolution bug in bcc32. Yes &convert(fmt::ULongLong); No &convert(...); template struct ConvertToIntImpl { enum { value = ENABLE_CONVERSION }; }; template struct ConvertToIntImpl2 { enum { value = false }; }; template struct ConvertToIntImpl2 { enum { // Don't convert numeric types. value = ConvertToIntImpl::is_specialized>::value }; }; template struct ConvertToInt { enum { enable_conversion = sizeof(convert(get())) == sizeof(Yes) }; enum { value = ConvertToIntImpl2::value }; }; #define FMT_DISABLE_CONVERSION_TO_INT(Type) \ template <> \ struct ConvertToInt { enum { value = 0 }; } // Silence warnings about convering float to int. FMT_DISABLE_CONVERSION_TO_INT(float); FMT_DISABLE_CONVERSION_TO_INT(double); FMT_DISABLE_CONVERSION_TO_INT(long double); template struct EnableIf {}; template struct EnableIf { typedef T type; }; template struct Conditional { typedef T type; }; template struct Conditional { typedef F type; }; // For bcc32 which doesn't understand ! in template arguments. template struct Not { enum { value = 0 }; }; template <> struct Not { enum { value = 1 }; }; template struct False { enum { value = 0 }; }; template struct LConvCheck { LConvCheck(int) {} }; // Returns the thousands separator for the current locale. // We check if ``lconv`` contains ``thousands_sep`` because on Android // ``lconv`` is stubbed as an empty struct. template inline StringRef thousands_sep( LConv *lc, LConvCheck = 0) { return lc->thousands_sep; } inline fmt::StringRef thousands_sep(...) { return ""; } #define FMT_CONCAT(a, b) a##b #if FMT_GCC_VERSION >= 407 # define FMT_UNUSED __attribute__((unused)) #else # define FMT_UNUSED #endif #ifndef FMT_USE_STATIC_ASSERT # define FMT_USE_STATIC_ASSERT 0 #endif #if FMT_USE_STATIC_ASSERT || FMT_HAS_FEATURE(cxx_static_assert) || \ (FMT_GCC_VERSION >= 403 && FMT_HAS_GXX_CXX11) || _MSC_VER >= 1600 # define FMT_STATIC_ASSERT(cond, message) static_assert(cond, message) #else # define FMT_CONCAT_(a, b) FMT_CONCAT(a, b) # define FMT_STATIC_ASSERT(cond, message) \ typedef int FMT_CONCAT_(Assert, __LINE__)[(cond) ? 1 : -1] FMT_UNUSED #endif template void format_arg(Formatter &, const Char *, const T &) { FMT_STATIC_ASSERT(False::value, "Cannot format argument. To enable the use of ostream " "operator<< include fmt/ostream.h. Otherwise provide " "an overload of format_arg."); } // Makes an Arg object from any type. template class MakeValue : public Arg { public: typedef typename Formatter::Char Char; private: // The following two methods are private to disallow formatting of // arbitrary pointers. If you want to output a pointer cast it to // "void *" or "const void *". In particular, this forbids formatting // of "[const] volatile char *" which is printed as bool by iostreams. // Do not implement! template MakeValue(const T *value); template MakeValue(T *value); // The following methods are private to disallow formatting of wide // characters and strings into narrow strings as in // fmt::format("{}", L"test"); // To fix this, use a wide format string: fmt::format(L"{}", L"test"). #if !FMT_MSC_VER || defined(_NATIVE_WCHAR_T_DEFINED) MakeValue(typename WCharHelper::Unsupported); #endif MakeValue(typename WCharHelper::Unsupported); MakeValue(typename WCharHelper::Unsupported); MakeValue(typename WCharHelper::Unsupported); MakeValue(typename WCharHelper::Unsupported); void set_string(StringRef str) { string.value = str.data(); string.size = str.size(); } void set_string(WStringRef str) { wstring.value = str.data(); wstring.size = str.size(); } // Formats an argument of a custom type, such as a user-defined class. template static void format_custom_arg( void *formatter, const void *arg, void *format_str_ptr) { format_arg(*static_cast(formatter), *static_cast(format_str_ptr), *static_cast(arg)); } public: MakeValue() {} #define FMT_MAKE_VALUE_(Type, field, TYPE, rhs) \ MakeValue(Type value) { field = rhs; } \ static uint64_t type(Type) { return Arg::TYPE; } #define FMT_MAKE_VALUE(Type, field, TYPE) \ FMT_MAKE_VALUE_(Type, field, TYPE, value) FMT_MAKE_VALUE(bool, int_value, BOOL) FMT_MAKE_VALUE(short, int_value, INT) FMT_MAKE_VALUE(unsigned short, uint_value, UINT) FMT_MAKE_VALUE(int, int_value, INT) FMT_MAKE_VALUE(unsigned, uint_value, UINT) MakeValue(long value) { // To minimize the number of types we need to deal with, long is // translated either to int or to long long depending on its size. if (const_check(sizeof(long) == sizeof(int))) int_value = static_cast(value); else long_long_value = value; } static uint64_t type(long) { return sizeof(long) == sizeof(int) ? Arg::INT : Arg::LONG_LONG; } MakeValue(unsigned long value) { if (const_check(sizeof(unsigned long) == sizeof(unsigned))) uint_value = static_cast(value); else ulong_long_value = value; } static uint64_t type(unsigned long) { return sizeof(unsigned long) == sizeof(unsigned) ? Arg::UINT : Arg::ULONG_LONG; } FMT_MAKE_VALUE(LongLong, long_long_value, LONG_LONG) FMT_MAKE_VALUE(ULongLong, ulong_long_value, ULONG_LONG) FMT_MAKE_VALUE(float, double_value, DOUBLE) FMT_MAKE_VALUE(double, double_value, DOUBLE) FMT_MAKE_VALUE(long double, long_double_value, LONG_DOUBLE) FMT_MAKE_VALUE(signed char, int_value, INT) FMT_MAKE_VALUE(unsigned char, uint_value, UINT) FMT_MAKE_VALUE(char, int_value, CHAR) #if !defined(_MSC_VER) || defined(_NATIVE_WCHAR_T_DEFINED) MakeValue(typename WCharHelper::Supported value) { int_value = value; } static uint64_t type(wchar_t) { return Arg::CHAR; } #endif #define FMT_MAKE_STR_VALUE(Type, TYPE) \ MakeValue(Type value) { set_string(value); } \ static uint64_t type(Type) { return Arg::TYPE; } FMT_MAKE_VALUE(char *, string.value, CSTRING) FMT_MAKE_VALUE(const char *, string.value, CSTRING) FMT_MAKE_VALUE(signed char *, sstring.value, CSTRING) FMT_MAKE_VALUE(const signed char *, sstring.value, CSTRING) FMT_MAKE_VALUE(unsigned char *, ustring.value, CSTRING) FMT_MAKE_VALUE(const unsigned char *, ustring.value, CSTRING) FMT_MAKE_STR_VALUE(const std::string &, STRING) FMT_MAKE_STR_VALUE(StringRef, STRING) FMT_MAKE_VALUE_(CStringRef, string.value, CSTRING, value.c_str()) #define FMT_MAKE_WSTR_VALUE(Type, TYPE) \ MakeValue(typename WCharHelper::Supported value) { \ set_string(value); \ } \ static uint64_t type(Type) { return Arg::TYPE; } FMT_MAKE_WSTR_VALUE(wchar_t *, WSTRING) FMT_MAKE_WSTR_VALUE(const wchar_t *, WSTRING) FMT_MAKE_WSTR_VALUE(const std::wstring &, WSTRING) FMT_MAKE_WSTR_VALUE(WStringRef, WSTRING) FMT_MAKE_VALUE(void *, pointer, POINTER) FMT_MAKE_VALUE(const void *, pointer, POINTER) template MakeValue(const T &value, typename EnableIf::value>::value, int>::type = 0) { custom.value = &value; custom.format = &format_custom_arg; } template MakeValue(const T &value, typename EnableIf::value, int>::type = 0) { int_value = value; } template static uint64_t type(const T &) { return ConvertToInt::value ? Arg::INT : Arg::CUSTOM; } // Additional template param `Char_` is needed here because make_type always // uses char. template MakeValue(const NamedArg &value) { pointer = &value; } template MakeValue(const NamedArgWithType &value) { pointer = &value; } template static uint64_t type(const NamedArg &) { return Arg::NAMED_ARG; } template static uint64_t type(const NamedArgWithType &) { return Arg::NAMED_ARG; } }; template class MakeArg : public Arg { public: MakeArg() { type = Arg::NONE; } template MakeArg(const T &value) : Arg(MakeValue(value)) { type = static_cast(MakeValue::type(value)); } }; template struct NamedArg : Arg { BasicStringRef name; template NamedArg(BasicStringRef argname, const T &value) : Arg(MakeArg< BasicFormatter >(value)), name(argname) {} }; template struct NamedArgWithType : NamedArg { NamedArgWithType(BasicStringRef argname, const T &value) : NamedArg(argname, value) {} }; class RuntimeError : public std::runtime_error { protected: RuntimeError() : std::runtime_error("") {} ~RuntimeError() throw(); }; template class ArgMap; } // namespace internal /** An argument list. */ class ArgList { private: // To reduce compiled code size per formatting function call, types of first // MAX_PACKED_ARGS arguments are passed in the types_ field. uint64_t types_; union { // If the number of arguments is less than MAX_PACKED_ARGS, the argument // values are stored in values_, otherwise they are stored in args_. // This is done to reduce compiled code size as storing larger objects // may require more code (at least on x86-64) even if the same amount of // data is actually copied to stack. It saves ~10% on the bloat test. const internal::Value *values_; const internal::Arg *args_; }; internal::Arg::Type type(unsigned index) const { return type(types_, index); } template friend class internal::ArgMap; public: // Maximum number of arguments with packed types. enum { MAX_PACKED_ARGS = 16 }; ArgList() : types_(0) {} ArgList(ULongLong types, const internal::Value *values) : types_(types), values_(values) {} ArgList(ULongLong types, const internal::Arg *args) : types_(types), args_(args) {} uint64_t types() const { return types_; } /** Returns the argument at specified index. */ internal::Arg operator[](unsigned index) const { using internal::Arg; Arg arg; bool use_values = type(MAX_PACKED_ARGS - 1) == Arg::NONE; if (index < MAX_PACKED_ARGS) { Arg::Type arg_type = type(index); internal::Value &val = arg; if (arg_type != Arg::NONE) val = use_values ? values_[index] : args_[index]; arg.type = arg_type; return arg; } if (use_values) { // The index is greater than the number of arguments that can be stored // in values, so return a "none" argument. arg.type = Arg::NONE; return arg; } for (unsigned i = MAX_PACKED_ARGS; i <= index; ++i) { if (args_[i].type == Arg::NONE) return args_[i]; } return args_[index]; } static internal::Arg::Type type(uint64_t types, unsigned index) { unsigned shift = index * 4; uint64_t mask = 0xf; return static_cast( (types & (mask << shift)) >> shift); } }; #define FMT_DISPATCH(call) static_cast(this)->call /** \rst An argument visitor based on the `curiously recurring template pattern `_. To use `~fmt::ArgVisitor` define a subclass that implements some or all of the visit methods with the same signatures as the methods in `~fmt::ArgVisitor`, for example, `~fmt::ArgVisitor::visit_int()`. Pass the subclass as the *Impl* template parameter. Then calling `~fmt::ArgVisitor::visit` for some argument will dispatch to a visit method specific to the argument type. For example, if the argument type is ``double`` then the `~fmt::ArgVisitor::visit_double()` method of a subclass will be called. If the subclass doesn't contain a method with this signature, then a corresponding method of `~fmt::ArgVisitor` will be called. **Example**:: class MyArgVisitor : public fmt::ArgVisitor { public: void visit_int(int value) { fmt::print("{}", value); } void visit_double(double value) { fmt::print("{}", value ); } }; \endrst */ template class ArgVisitor { private: typedef internal::Arg Arg; public: void report_unhandled_arg() {} Result visit_unhandled_arg() { FMT_DISPATCH(report_unhandled_arg()); return Result(); } /** Visits an ``int`` argument. **/ Result visit_int(int value) { return FMT_DISPATCH(visit_any_int(value)); } /** Visits a ``long long`` argument. **/ Result visit_long_long(LongLong value) { return FMT_DISPATCH(visit_any_int(value)); } /** Visits an ``unsigned`` argument. **/ Result visit_uint(unsigned value) { return FMT_DISPATCH(visit_any_int(value)); } /** Visits an ``unsigned long long`` argument. **/ Result visit_ulong_long(ULongLong value) { return FMT_DISPATCH(visit_any_int(value)); } /** Visits a ``bool`` argument. **/ Result visit_bool(bool value) { return FMT_DISPATCH(visit_any_int(value)); } /** Visits a ``char`` or ``wchar_t`` argument. **/ Result visit_char(int value) { return FMT_DISPATCH(visit_any_int(value)); } /** Visits an argument of any integral type. **/ template Result visit_any_int(T) { return FMT_DISPATCH(visit_unhandled_arg()); } /** Visits a ``double`` argument. **/ Result visit_double(double value) { return FMT_DISPATCH(visit_any_double(value)); } /** Visits a ``long double`` argument. **/ Result visit_long_double(long double value) { return FMT_DISPATCH(visit_any_double(value)); } /** Visits a ``double`` or ``long double`` argument. **/ template Result visit_any_double(T) { return FMT_DISPATCH(visit_unhandled_arg()); } /** Visits a null-terminated C string (``const char *``) argument. **/ Result visit_cstring(const char *) { return FMT_DISPATCH(visit_unhandled_arg()); } /** Visits a string argument. **/ Result visit_string(Arg::StringValue) { return FMT_DISPATCH(visit_unhandled_arg()); } /** Visits a wide string argument. **/ Result visit_wstring(Arg::StringValue) { return FMT_DISPATCH(visit_unhandled_arg()); } /** Visits a pointer argument. **/ Result visit_pointer(const void *) { return FMT_DISPATCH(visit_unhandled_arg()); } /** Visits an argument of a custom (user-defined) type. **/ Result visit_custom(Arg::CustomValue) { return FMT_DISPATCH(visit_unhandled_arg()); } /** \rst Visits an argument dispatching to the appropriate visit method based on the argument type. For example, if the argument type is ``double`` then the `~fmt::ArgVisitor::visit_double()` method of the *Impl* class will be called. \endrst */ Result visit(const Arg &arg) { switch (arg.type) { case Arg::NONE: case Arg::NAMED_ARG: FMT_ASSERT(false, "invalid argument type"); break; case Arg::INT: return FMT_DISPATCH(visit_int(arg.int_value)); case Arg::UINT: return FMT_DISPATCH(visit_uint(arg.uint_value)); case Arg::LONG_LONG: return FMT_DISPATCH(visit_long_long(arg.long_long_value)); case Arg::ULONG_LONG: return FMT_DISPATCH(visit_ulong_long(arg.ulong_long_value)); case Arg::BOOL: return FMT_DISPATCH(visit_bool(arg.int_value != 0)); case Arg::CHAR: return FMT_DISPATCH(visit_char(arg.int_value)); case Arg::DOUBLE: return FMT_DISPATCH(visit_double(arg.double_value)); case Arg::LONG_DOUBLE: return FMT_DISPATCH(visit_long_double(arg.long_double_value)); case Arg::CSTRING: return FMT_DISPATCH(visit_cstring(arg.string.value)); case Arg::STRING: return FMT_DISPATCH(visit_string(arg.string)); case Arg::WSTRING: return FMT_DISPATCH(visit_wstring(arg.wstring)); case Arg::POINTER: return FMT_DISPATCH(visit_pointer(arg.pointer)); case Arg::CUSTOM: return FMT_DISPATCH(visit_custom(arg.custom)); } return Result(); } }; enum Alignment { ALIGN_DEFAULT, ALIGN_LEFT, ALIGN_RIGHT, ALIGN_CENTER, ALIGN_NUMERIC }; // Flags. enum { SIGN_FLAG = 1, PLUS_FLAG = 2, MINUS_FLAG = 4, HASH_FLAG = 8, CHAR_FLAG = 0x10 // Argument has char type - used in error reporting. }; // An empty format specifier. struct EmptySpec {}; // A type specifier. template struct TypeSpec : EmptySpec { Alignment align() const { return ALIGN_DEFAULT; } unsigned width() const { return 0; } int precision() const { return -1; } bool flag(unsigned) const { return false; } char type() const { return TYPE; } char fill() const { return ' '; } }; // A width specifier. struct WidthSpec { unsigned width_; // Fill is always wchar_t and cast to char if necessary to avoid having // two specialization of WidthSpec and its subclasses. wchar_t fill_; WidthSpec(unsigned width, wchar_t fill) : width_(width), fill_(fill) {} unsigned width() const { return width_; } wchar_t fill() const { return fill_; } }; // An alignment specifier. struct AlignSpec : WidthSpec { Alignment align_; AlignSpec(unsigned width, wchar_t fill, Alignment align = ALIGN_DEFAULT) : WidthSpec(width, fill), align_(align) {} Alignment align() const { return align_; } int precision() const { return -1; } }; // An alignment and type specifier. template struct AlignTypeSpec : AlignSpec { AlignTypeSpec(unsigned width, wchar_t fill) : AlignSpec(width, fill) {} bool flag(unsigned) const { return false; } char type() const { return TYPE; } }; // A full format specifier. struct FormatSpec : AlignSpec { unsigned flags_; int precision_; char type_; FormatSpec( unsigned width = 0, char type = 0, wchar_t fill = ' ') : AlignSpec(width, fill), flags_(0), precision_(-1), type_(type) {} bool flag(unsigned f) const { return (flags_ & f) != 0; } int precision() const { return precision_; } char type() const { return type_; } }; // An integer format specifier. template , typename Char = char> class IntFormatSpec : public SpecT { private: T value_; public: IntFormatSpec(T val, const SpecT &spec = SpecT()) : SpecT(spec), value_(val) {} T value() const { return value_; } }; // A string format specifier. template class StrFormatSpec : public AlignSpec { private: const Char *str_; public: template StrFormatSpec(const Char *str, unsigned width, FillChar fill) : AlignSpec(width, fill), str_(str) { internal::CharTraits::convert(FillChar()); } const Char *str() const { return str_; } }; /** Returns an integer format specifier to format the value in base 2. */ IntFormatSpec > bin(int value); /** Returns an integer format specifier to format the value in base 8. */ IntFormatSpec > oct(int value); /** Returns an integer format specifier to format the value in base 16 using lower-case letters for the digits above 9. */ IntFormatSpec > hex(int value); /** Returns an integer formatter format specifier to format in base 16 using upper-case letters for the digits above 9. */ IntFormatSpec > hexu(int value); /** \rst Returns an integer format specifier to pad the formatted argument with the fill character to the specified width using the default (right) numeric alignment. **Example**:: MemoryWriter out; out << pad(hex(0xcafe), 8, '0'); // out.str() == "0000cafe" \endrst */ template IntFormatSpec, Char> pad( int value, unsigned width, Char fill = ' '); #define FMT_DEFINE_INT_FORMATTERS(TYPE) \ inline IntFormatSpec > bin(TYPE value) { \ return IntFormatSpec >(value, TypeSpec<'b'>()); \ } \ \ inline IntFormatSpec > oct(TYPE value) { \ return IntFormatSpec >(value, TypeSpec<'o'>()); \ } \ \ inline IntFormatSpec > hex(TYPE value) { \ return IntFormatSpec >(value, TypeSpec<'x'>()); \ } \ \ inline IntFormatSpec > hexu(TYPE value) { \ return IntFormatSpec >(value, TypeSpec<'X'>()); \ } \ \ template \ inline IntFormatSpec > pad( \ IntFormatSpec > f, unsigned width) { \ return IntFormatSpec >( \ f.value(), AlignTypeSpec(width, ' ')); \ } \ \ /* For compatibility with older compilers we provide two overloads for pad, */ \ /* one that takes a fill character and one that doesn't. In the future this */ \ /* can be replaced with one overload making the template argument Char */ \ /* default to char (C++11). */ \ template \ inline IntFormatSpec, Char> pad( \ IntFormatSpec, Char> f, \ unsigned width, Char fill) { \ return IntFormatSpec, Char>( \ f.value(), AlignTypeSpec(width, fill)); \ } \ \ inline IntFormatSpec > pad( \ TYPE value, unsigned width) { \ return IntFormatSpec >( \ value, AlignTypeSpec<0>(width, ' ')); \ } \ \ template \ inline IntFormatSpec, Char> pad( \ TYPE value, unsigned width, Char fill) { \ return IntFormatSpec, Char>( \ value, AlignTypeSpec<0>(width, fill)); \ } FMT_DEFINE_INT_FORMATTERS(int) FMT_DEFINE_INT_FORMATTERS(long) FMT_DEFINE_INT_FORMATTERS(unsigned) FMT_DEFINE_INT_FORMATTERS(unsigned long) FMT_DEFINE_INT_FORMATTERS(LongLong) FMT_DEFINE_INT_FORMATTERS(ULongLong) /** \rst Returns a string formatter that pads the formatted argument with the fill character to the specified width using the default (left) string alignment. **Example**:: std::string s = str(MemoryWriter() << pad("abc", 8)); // s == "abc " \endrst */ template inline StrFormatSpec pad( const Char *str, unsigned width, Char fill = ' ') { return StrFormatSpec(str, width, fill); } inline StrFormatSpec pad( const wchar_t *str, unsigned width, char fill = ' ') { return StrFormatSpec(str, width, fill); } namespace internal { template class ArgMap { private: typedef std::vector< std::pair, internal::Arg> > MapType; typedef typename MapType::value_type Pair; MapType map_; public: FMT_API void init(const ArgList &args); const internal::Arg* find(const fmt::BasicStringRef &name) const { // The list is unsorted, so just return the first matching name. for (typename MapType::const_iterator it = map_.begin(), end = map_.end(); it != end; ++it) { if (it->first == name) return &it->second; } return 0; } }; template class ArgFormatterBase : public ArgVisitor { private: BasicWriter &writer_; FormatSpec &spec_; FMT_DISALLOW_COPY_AND_ASSIGN(ArgFormatterBase); void write_pointer(const void *p) { spec_.flags_ = HASH_FLAG; spec_.type_ = 'x'; writer_.write_int(reinterpret_cast(p), spec_); } protected: BasicWriter &writer() { return writer_; } FormatSpec &spec() { return spec_; } void write(bool value) { const char *str_value = value ? "true" : "false"; Arg::StringValue str = { str_value, std::strlen(str_value) }; writer_.write_str(str, spec_); } void write(const char *value) { Arg::StringValue str = { value, value != 0 ? std::strlen(value) : 0 }; writer_.write_str(str, spec_); } public: ArgFormatterBase(BasicWriter &w, FormatSpec &s) : writer_(w), spec_(s) {} template void visit_any_int(T value) { writer_.write_int(value, spec_); } template void visit_any_double(T value) { writer_.write_double(value, spec_); } void visit_bool(bool value) { if (spec_.type_) return visit_any_int(value); write(value); } void visit_char(int value) { if (spec_.type_ && spec_.type_ != 'c') { spec_.flags_ |= CHAR_FLAG; writer_.write_int(value, spec_); return; } if (spec_.align_ == ALIGN_NUMERIC || spec_.flags_ != 0) FMT_THROW(FormatError("invalid format specifier for char")); typedef typename BasicWriter::CharPtr CharPtr; Char fill = internal::CharTraits::cast(spec_.fill()); CharPtr out = CharPtr(); const unsigned CHAR_SIZE = 1; if (spec_.width_ > CHAR_SIZE) { out = writer_.grow_buffer(spec_.width_); if (spec_.align_ == ALIGN_RIGHT) { std::uninitialized_fill_n(out, spec_.width_ - CHAR_SIZE, fill); out += spec_.width_ - CHAR_SIZE; } else if (spec_.align_ == ALIGN_CENTER) { out = writer_.fill_padding(out, spec_.width_, internal::const_check(CHAR_SIZE), fill); } else { std::uninitialized_fill_n(out + CHAR_SIZE, spec_.width_ - CHAR_SIZE, fill); } } else { out = writer_.grow_buffer(CHAR_SIZE); } *out = internal::CharTraits::cast(value); } void visit_cstring(const char *value) { if (spec_.type_ == 'p') return write_pointer(value); write(value); } void visit_string(Arg::StringValue value) { writer_.write_str(value, spec_); } using ArgVisitor::visit_wstring; void visit_wstring(Arg::StringValue value) { writer_.write_str(value, spec_); } void visit_pointer(const void *value) { if (spec_.type_ && spec_.type_ != 'p') report_unknown_type(spec_.type_, "pointer"); write_pointer(value); } }; class FormatterBase { private: ArgList args_; int next_arg_index_; // Returns the argument with specified index. FMT_API Arg do_get_arg(unsigned arg_index, const char *&error); protected: const ArgList &args() const { return args_; } explicit FormatterBase(const ArgList &args) { args_ = args; next_arg_index_ = 0; } // Returns the next argument. Arg next_arg(const char *&error) { if (next_arg_index_ >= 0) return do_get_arg(internal::to_unsigned(next_arg_index_++), error); error = "cannot switch from manual to automatic argument indexing"; return Arg(); } // Checks if manual indexing is used and returns the argument with // specified index. Arg get_arg(unsigned arg_index, const char *&error) { return check_no_auto_index(error) ? do_get_arg(arg_index, error) : Arg(); } bool check_no_auto_index(const char *&error) { if (next_arg_index_ > 0) { error = "cannot switch from automatic to manual argument indexing"; return false; } next_arg_index_ = -1; return true; } template void write(BasicWriter &w, const Char *start, const Char *end) { if (start != end) w << BasicStringRef(start, internal::to_unsigned(end - start)); } }; } // namespace internal /** \rst An argument formatter based on the `curiously recurring template pattern `_. To use `~fmt::BasicArgFormatter` define a subclass that implements some or all of the visit methods with the same signatures as the methods in `~fmt::ArgVisitor`, for example, `~fmt::ArgVisitor::visit_int()`. Pass the subclass as the *Impl* template parameter. When a formatting function processes an argument, it will dispatch to a visit method specific to the argument type. For example, if the argument type is ``double`` then the `~fmt::ArgVisitor::visit_double()` method of a subclass will be called. If the subclass doesn't contain a method with this signature, then a corresponding method of `~fmt::BasicArgFormatter` or its superclass will be called. \endrst */ template class BasicArgFormatter : public internal::ArgFormatterBase { private: BasicFormatter &formatter_; const Char *format_; public: /** \rst Constructs an argument formatter object. *formatter* is a reference to the main formatter object, *spec* contains format specifier information for standard argument types, and *fmt* points to the part of the format string being parsed for custom argument types. \endrst */ BasicArgFormatter(BasicFormatter &formatter, FormatSpec &spec, const Char *fmt) : internal::ArgFormatterBase(formatter.writer(), spec), formatter_(formatter), format_(fmt) {} /** Formats an argument of a custom (user-defined) type. */ void visit_custom(internal::Arg::CustomValue c) { c.format(&formatter_, c.value, &format_); } }; /** The default argument formatter. */ template class ArgFormatter : public BasicArgFormatter, Char> { public: /** Constructs an argument formatter object. */ ArgFormatter(BasicFormatter &formatter, FormatSpec &spec, const Char *fmt) : BasicArgFormatter, Char>(formatter, spec, fmt) {} }; /** This template formats data and writes the output to a writer. */ template class BasicFormatter : private internal::FormatterBase { public: /** The character type for the output. */ typedef CharType Char; private: BasicWriter &writer_; internal::ArgMap map_; FMT_DISALLOW_COPY_AND_ASSIGN(BasicFormatter); using internal::FormatterBase::get_arg; // Checks if manual indexing is used and returns the argument with // specified name. internal::Arg get_arg(BasicStringRef arg_name, const char *&error); // Parses argument index and returns corresponding argument. internal::Arg parse_arg_index(const Char *&s); // Parses argument name and returns corresponding argument. internal::Arg parse_arg_name(const Char *&s); public: /** \rst Constructs a ``BasicFormatter`` object. References to the arguments and the writer are stored in the formatter object so make sure they have appropriate lifetimes. \endrst */ BasicFormatter(const ArgList &args, BasicWriter &w) : internal::FormatterBase(args), writer_(w) {} /** Returns a reference to the writer associated with this formatter. */ BasicWriter &writer() { return writer_; } /** Formats stored arguments and writes the output to the writer. */ void format(BasicCStringRef format_str); // Formats a single argument and advances format_str, a format string pointer. const Char *format(const Char *&format_str, const internal::Arg &arg); }; // Generates a comma-separated list with results of applying f to // numbers 0..n-1. # define FMT_GEN(n, f) FMT_GEN##n(f) # define FMT_GEN1(f) f(0) # define FMT_GEN2(f) FMT_GEN1(f), f(1) # define FMT_GEN3(f) FMT_GEN2(f), f(2) # define FMT_GEN4(f) FMT_GEN3(f), f(3) # define FMT_GEN5(f) FMT_GEN4(f), f(4) # define FMT_GEN6(f) FMT_GEN5(f), f(5) # define FMT_GEN7(f) FMT_GEN6(f), f(6) # define FMT_GEN8(f) FMT_GEN7(f), f(7) # define FMT_GEN9(f) FMT_GEN8(f), f(8) # define FMT_GEN10(f) FMT_GEN9(f), f(9) namespace internal { inline uint64_t make_type() { return 0; } template inline uint64_t make_type(const T &arg) { return MakeValue< BasicFormatter >::type(arg); } template struct ArgArray; template struct ArgArray { typedef Value Type[N > 0 ? N : 1]; template static Value make(const T &value) { #ifdef __clang__ Value result = MakeValue(value); // Workaround a bug in Apple LLVM version 4.2 (clang-425.0.28) of clang: // https://github.com/fmtlib/fmt/issues/276 (void)result.custom.format; return result; #else return MakeValue(value); #endif } }; template struct ArgArray { typedef Arg Type[N + 1]; // +1 for the list end Arg::NONE template static Arg make(const T &value) { return MakeArg(value); } }; #if FMT_USE_VARIADIC_TEMPLATES template inline uint64_t make_type(const Arg &first, const Args & ... tail) { return make_type(first) | (make_type(tail...) << 4); } #else struct ArgType { uint64_t type; ArgType() : type(0) {} template ArgType(const T &arg) : type(make_type(arg)) {} }; # define FMT_ARG_TYPE_DEFAULT(n) ArgType t##n = ArgType() inline uint64_t make_type(FMT_GEN15(FMT_ARG_TYPE_DEFAULT)) { return t0.type | (t1.type << 4) | (t2.type << 8) | (t3.type << 12) | (t4.type << 16) | (t5.type << 20) | (t6.type << 24) | (t7.type << 28) | (t8.type << 32) | (t9.type << 36) | (t10.type << 40) | (t11.type << 44) | (t12.type << 48) | (t13.type << 52) | (t14.type << 56); } #endif } // namespace internal # define FMT_MAKE_TEMPLATE_ARG(n) typename T##n # define FMT_MAKE_ARG_TYPE(n) T##n # define FMT_MAKE_ARG(n) const T##n &v##n # define FMT_ASSIGN_char(n) \ arr[n] = fmt::internal::MakeValue< fmt::BasicFormatter >(v##n) # define FMT_ASSIGN_wchar_t(n) \ arr[n] = fmt::internal::MakeValue< fmt::BasicFormatter >(v##n) #if FMT_USE_VARIADIC_TEMPLATES // Defines a variadic function returning void. # define FMT_VARIADIC_VOID(func, arg_type) \ template \ void func(arg_type arg0, const Args & ... args) { \ typedef fmt::internal::ArgArray ArgArray; \ typename ArgArray::Type array{ \ ArgArray::template make >(args)...}; \ func(arg0, fmt::ArgList(fmt::internal::make_type(args...), array)); \ } // Defines a variadic constructor. # define FMT_VARIADIC_CTOR(ctor, func, arg0_type, arg1_type) \ template \ ctor(arg0_type arg0, arg1_type arg1, const Args & ... args) { \ typedef fmt::internal::ArgArray ArgArray; \ typename ArgArray::Type array{ \ ArgArray::template make >(args)...}; \ func(arg0, arg1, fmt::ArgList(fmt::internal::make_type(args...), array)); \ } #else # define FMT_MAKE_REF(n) \ fmt::internal::MakeValue< fmt::BasicFormatter >(v##n) # define FMT_MAKE_REF2(n) v##n // Defines a wrapper for a function taking one argument of type arg_type // and n additional arguments of arbitrary types. # define FMT_WRAP1(func, arg_type, n) \ template \ inline void func(arg_type arg1, FMT_GEN(n, FMT_MAKE_ARG)) { \ const fmt::internal::ArgArray::Type array = {FMT_GEN(n, FMT_MAKE_REF)}; \ func(arg1, fmt::ArgList( \ fmt::internal::make_type(FMT_GEN(n, FMT_MAKE_REF2)), array)); \ } // Emulates a variadic function returning void on a pre-C++11 compiler. # define FMT_VARIADIC_VOID(func, arg_type) \ inline void func(arg_type arg) { func(arg, fmt::ArgList()); } \ FMT_WRAP1(func, arg_type, 1) FMT_WRAP1(func, arg_type, 2) \ FMT_WRAP1(func, arg_type, 3) FMT_WRAP1(func, arg_type, 4) \ FMT_WRAP1(func, arg_type, 5) FMT_WRAP1(func, arg_type, 6) \ FMT_WRAP1(func, arg_type, 7) FMT_WRAP1(func, arg_type, 8) \ FMT_WRAP1(func, arg_type, 9) FMT_WRAP1(func, arg_type, 10) # define FMT_CTOR(ctor, func, arg0_type, arg1_type, n) \ template \ ctor(arg0_type arg0, arg1_type arg1, FMT_GEN(n, FMT_MAKE_ARG)) { \ const fmt::internal::ArgArray::Type array = {FMT_GEN(n, FMT_MAKE_REF)}; \ func(arg0, arg1, fmt::ArgList( \ fmt::internal::make_type(FMT_GEN(n, FMT_MAKE_REF2)), array)); \ } // Emulates a variadic constructor on a pre-C++11 compiler. # define FMT_VARIADIC_CTOR(ctor, func, arg0_type, arg1_type) \ FMT_CTOR(ctor, func, arg0_type, arg1_type, 1) \ FMT_CTOR(ctor, func, arg0_type, arg1_type, 2) \ FMT_CTOR(ctor, func, arg0_type, arg1_type, 3) \ FMT_CTOR(ctor, func, arg0_type, arg1_type, 4) \ FMT_CTOR(ctor, func, arg0_type, arg1_type, 5) \ FMT_CTOR(ctor, func, arg0_type, arg1_type, 6) \ FMT_CTOR(ctor, func, arg0_type, arg1_type, 7) \ FMT_CTOR(ctor, func, arg0_type, arg1_type, 8) \ FMT_CTOR(ctor, func, arg0_type, arg1_type, 9) \ FMT_CTOR(ctor, func, arg0_type, arg1_type, 10) #endif // Generates a comma-separated list with results of applying f to pairs // (argument, index). #define FMT_FOR_EACH1(f, x0) f(x0, 0) #define FMT_FOR_EACH2(f, x0, x1) \ FMT_FOR_EACH1(f, x0), f(x1, 1) #define FMT_FOR_EACH3(f, x0, x1, x2) \ FMT_FOR_EACH2(f, x0 ,x1), f(x2, 2) #define FMT_FOR_EACH4(f, x0, x1, x2, x3) \ FMT_FOR_EACH3(f, x0, x1, x2), f(x3, 3) #define FMT_FOR_EACH5(f, x0, x1, x2, x3, x4) \ FMT_FOR_EACH4(f, x0, x1, x2, x3), f(x4, 4) #define FMT_FOR_EACH6(f, x0, x1, x2, x3, x4, x5) \ FMT_FOR_EACH5(f, x0, x1, x2, x3, x4), f(x5, 5) #define FMT_FOR_EACH7(f, x0, x1, x2, x3, x4, x5, x6) \ FMT_FOR_EACH6(f, x0, x1, x2, x3, x4, x5), f(x6, 6) #define FMT_FOR_EACH8(f, x0, x1, x2, x3, x4, x5, x6, x7) \ FMT_FOR_EACH7(f, x0, x1, x2, x3, x4, x5, x6), f(x7, 7) #define FMT_FOR_EACH9(f, x0, x1, x2, x3, x4, x5, x6, x7, x8) \ FMT_FOR_EACH8(f, x0, x1, x2, x3, x4, x5, x6, x7), f(x8, 8) #define FMT_FOR_EACH10(f, x0, x1, x2, x3, x4, x5, x6, x7, x8, x9) \ FMT_FOR_EACH9(f, x0, x1, x2, x3, x4, x5, x6, x7, x8), f(x9, 9) /** An error returned by an operating system or a language runtime, for example a file opening error. */ class SystemError : public internal::RuntimeError { private: void init(int err_code, CStringRef format_str, ArgList args); protected: int error_code_; typedef char Char; // For FMT_VARIADIC_CTOR. SystemError() {} public: /** \rst Constructs a :class:`fmt::SystemError` object with a description formatted with `fmt::format_system_error`. *message* and additional arguments passed into the constructor are formatted similarly to `fmt::format`. **Example**:: // This throws a SystemError with the description // cannot open file 'madeup': No such file or directory // or similar (system message may vary). const char *filename = "madeup"; std::FILE *file = std::fopen(filename, "r"); if (!file) throw fmt::SystemError(errno, "cannot open file '{}'", filename); \endrst */ SystemError(int error_code, CStringRef message) { init(error_code, message, ArgList()); } FMT_VARIADIC_CTOR(SystemError, init, int, CStringRef) ~SystemError() throw(); int error_code() const { return error_code_; } }; /** \rst Formats an error returned by an operating system or a language runtime, for example a file opening error, and writes it to *out* in the following form: .. parsed-literal:: **: ** where ** is the passed message and ** is the system message corresponding to the error code. *error_code* is a system error code as given by ``errno``. If *error_code* is not a valid error code such as -1, the system message may look like "Unknown error -1" and is platform-dependent. \endrst */ FMT_API void format_system_error(fmt::Writer &out, int error_code, fmt::StringRef message) FMT_NOEXCEPT; /** \rst This template provides operations for formatting and writing data into a character stream. The output is stored in a buffer provided by a subclass such as :class:`fmt::BasicMemoryWriter`. You can use one of the following typedefs for common character types: +---------+----------------------+ | Type | Definition | +=========+======================+ | Writer | BasicWriter | +---------+----------------------+ | WWriter | BasicWriter | +---------+----------------------+ \endrst */ template class BasicWriter { private: // Output buffer. Buffer &buffer_; FMT_DISALLOW_COPY_AND_ASSIGN(BasicWriter); typedef typename internal::CharTraits::CharPtr CharPtr; #if FMT_SECURE_SCL // Returns pointer value. static Char *get(CharPtr p) { return p.base(); } #else static Char *get(Char *p) { return p; } #endif // Fills the padding around the content and returns the pointer to the // content area. static CharPtr fill_padding(CharPtr buffer, unsigned total_size, std::size_t content_size, wchar_t fill); // Grows the buffer by n characters and returns a pointer to the newly // allocated area. CharPtr grow_buffer(std::size_t n) { std::size_t size = buffer_.size(); buffer_.resize(size + n); return internal::make_ptr(&buffer_[size], n); } // Writes an unsigned decimal integer. template Char *write_unsigned_decimal(UInt value, unsigned prefix_size = 0) { unsigned num_digits = internal::count_digits(value); Char *ptr = get(grow_buffer(prefix_size + num_digits)); internal::format_decimal(ptr + prefix_size, value, num_digits); return ptr; } // Writes a decimal integer. template void write_decimal(Int value) { typedef typename internal::IntTraits::MainType MainType; MainType abs_value = static_cast(value); if (internal::is_negative(value)) { abs_value = 0 - abs_value; *write_unsigned_decimal(abs_value, 1) = '-'; } else { write_unsigned_decimal(abs_value, 0); } } // Prepare a buffer for integer formatting. CharPtr prepare_int_buffer(unsigned num_digits, const EmptySpec &, const char *prefix, unsigned prefix_size) { unsigned size = prefix_size + num_digits; CharPtr p = grow_buffer(size); std::uninitialized_copy(prefix, prefix + prefix_size, p); return p + size - 1; } template CharPtr prepare_int_buffer(unsigned num_digits, const Spec &spec, const char *prefix, unsigned prefix_size); // Formats an integer. template void write_int(T value, Spec spec); // Formats a floating-point number (double or long double). template void write_double(T value, const FormatSpec &spec); // Writes a formatted string. template CharPtr write_str(const StrChar *s, std::size_t size, const AlignSpec &spec); template void write_str(const internal::Arg::StringValue &str, const FormatSpec &spec); // This following methods are private to disallow writing wide characters // and strings to a char stream. If you want to print a wide string as a // pointer as std::ostream does, cast it to const void*. // Do not implement! void operator<<(typename internal::WCharHelper::Unsupported); void operator<<( typename internal::WCharHelper::Unsupported); // Appends floating-point length specifier to the format string. // The second argument is only used for overload resolution. void append_float_length(Char *&format_ptr, long double) { *format_ptr++ = 'L'; } template void append_float_length(Char *&, T) {} template friend class internal::ArgFormatterBase; template friend class BasicPrintfArgFormatter; protected: /** Constructs a ``BasicWriter`` object. */ explicit BasicWriter(Buffer &b) : buffer_(b) {} public: /** \rst Destroys a ``BasicWriter`` object. \endrst */ virtual ~BasicWriter() {} /** Returns the total number of characters written. */ std::size_t size() const { return buffer_.size(); } /** Returns a pointer to the output buffer content. No terminating null character is appended. */ const Char *data() const FMT_NOEXCEPT { return &buffer_[0]; } /** Returns a pointer to the output buffer content with terminating null character appended. */ const Char *c_str() const { std::size_t size = buffer_.size(); buffer_.reserve(size + 1); buffer_[size] = '\0'; return &buffer_[0]; } /** \rst Returns the content of the output buffer as an `std::string`. \endrst */ std::basic_string str() const { return std::basic_string(&buffer_[0], buffer_.size()); } /** \rst Writes formatted data. *args* is an argument list representing arbitrary arguments. **Example**:: MemoryWriter out; out.write("Current point:\n"); out.write("({:+f}, {:+f})", -3.14, 3.14); This will write the following output to the ``out`` object: .. code-block:: none Current point: (-3.140000, +3.140000) The output can be accessed using :func:`data()`, :func:`c_str` or :func:`str` methods. See also :ref:`syntax`. \endrst */ void write(BasicCStringRef format, ArgList args) { BasicFormatter(args, *this).format(format); } FMT_VARIADIC_VOID(write, BasicCStringRef) BasicWriter &operator<<(int value) { write_decimal(value); return *this; } BasicWriter &operator<<(unsigned value) { return *this << IntFormatSpec(value); } BasicWriter &operator<<(long value) { write_decimal(value); return *this; } BasicWriter &operator<<(unsigned long value) { return *this << IntFormatSpec(value); } BasicWriter &operator<<(LongLong value) { write_decimal(value); return *this; } /** \rst Formats *value* and writes it to the stream. \endrst */ BasicWriter &operator<<(ULongLong value) { return *this << IntFormatSpec(value); } BasicWriter &operator<<(double value) { write_double(value, FormatSpec()); return *this; } /** \rst Formats *value* using the general format for floating-point numbers (``'g'``) and writes it to the stream. \endrst */ BasicWriter &operator<<(long double value) { write_double(value, FormatSpec()); return *this; } /** Writes a character to the stream. */ BasicWriter &operator<<(char value) { buffer_.push_back(value); return *this; } BasicWriter &operator<<( typename internal::WCharHelper::Supported value) { buffer_.push_back(value); return *this; } /** \rst Writes *value* to the stream. \endrst */ BasicWriter &operator<<(fmt::BasicStringRef value) { const Char *str = value.data(); buffer_.append(str, str + value.size()); return *this; } BasicWriter &operator<<( typename internal::WCharHelper::Supported value) { const char *str = value.data(); buffer_.append(str, str + value.size()); return *this; } template BasicWriter &operator<<(IntFormatSpec spec) { internal::CharTraits::convert(FillChar()); write_int(spec.value(), spec); return *this; } template BasicWriter &operator<<(const StrFormatSpec &spec) { const StrChar *s = spec.str(); write_str(s, std::char_traits::length(s), spec); return *this; } void clear() FMT_NOEXCEPT{ buffer_.clear(); } Buffer &buffer() FMT_NOEXCEPT{ return buffer_; } }; template template typename BasicWriter::CharPtr BasicWriter::write_str( const StrChar *s, std::size_t size, const AlignSpec &spec) { CharPtr out = CharPtr(); if (spec.width() > size) { out = grow_buffer(spec.width()); Char fill = internal::CharTraits::cast(spec.fill()); if (spec.align() == ALIGN_RIGHT) { std::uninitialized_fill_n(out, spec.width() - size, fill); out += spec.width() - size; } else if (spec.align() == ALIGN_CENTER) { out = fill_padding(out, spec.width(), size, fill); } else { std::uninitialized_fill_n(out + size, spec.width() - size, fill); } } else { out = grow_buffer(size); } std::uninitialized_copy(s, s + size, out); return out; } template template void BasicWriter::write_str( const internal::Arg::StringValue &s, const FormatSpec &spec) { // Check if StrChar is convertible to Char. internal::CharTraits::convert(StrChar()); if (spec.type_ && spec.type_ != 's') internal::report_unknown_type(spec.type_, "string"); const StrChar *str_value = s.value; std::size_t str_size = s.size; if (str_size == 0) { if (!str_value) { FMT_THROW(FormatError("string pointer is null")); } } std::size_t precision = static_cast(spec.precision_); if (spec.precision_ >= 0 && precision < str_size) str_size = precision; write_str(str_value, str_size, spec); } template typename BasicWriter::CharPtr BasicWriter::fill_padding( CharPtr buffer, unsigned total_size, std::size_t content_size, wchar_t fill) { std::size_t padding = total_size - content_size; std::size_t left_padding = padding / 2; Char fill_char = internal::CharTraits::cast(fill); std::uninitialized_fill_n(buffer, left_padding, fill_char); buffer += left_padding; CharPtr content = buffer; std::uninitialized_fill_n(buffer + content_size, padding - left_padding, fill_char); return content; } template template typename BasicWriter::CharPtr BasicWriter::prepare_int_buffer( unsigned num_digits, const Spec &spec, const char *prefix, unsigned prefix_size) { unsigned width = spec.width(); Alignment align = spec.align(); Char fill = internal::CharTraits::cast(spec.fill()); if (spec.precision() > static_cast(num_digits)) { // Octal prefix '0' is counted as a digit, so ignore it if precision // is specified. if (prefix_size > 0 && prefix[prefix_size - 1] == '0') --prefix_size; unsigned number_size = prefix_size + internal::to_unsigned(spec.precision()); AlignSpec subspec(number_size, '0', ALIGN_NUMERIC); if (number_size >= width) return prepare_int_buffer(num_digits, subspec, prefix, prefix_size); buffer_.reserve(width); unsigned fill_size = width - number_size; if (align != ALIGN_LEFT) { CharPtr p = grow_buffer(fill_size); std::uninitialized_fill(p, p + fill_size, fill); } CharPtr result = prepare_int_buffer( num_digits, subspec, prefix, prefix_size); if (align == ALIGN_LEFT) { CharPtr p = grow_buffer(fill_size); std::uninitialized_fill(p, p + fill_size, fill); } return result; } unsigned size = prefix_size + num_digits; if (width <= size) { CharPtr p = grow_buffer(size); std::uninitialized_copy(prefix, prefix + prefix_size, p); return p + size - 1; } CharPtr p = grow_buffer(width); CharPtr end = p + width; if (align == ALIGN_LEFT) { std::uninitialized_copy(prefix, prefix + prefix_size, p); p += size; std::uninitialized_fill(p, end, fill); } else if (align == ALIGN_CENTER) { p = fill_padding(p, width, size, fill); std::uninitialized_copy(prefix, prefix + prefix_size, p); p += size; } else { if (align == ALIGN_NUMERIC) { if (prefix_size != 0) { p = std::uninitialized_copy(prefix, prefix + prefix_size, p); size -= prefix_size; } } else { std::uninitialized_copy(prefix, prefix + prefix_size, end - size); } std::uninitialized_fill(p, end - size, fill); p = end; } return p - 1; } template template void BasicWriter::write_int(T value, Spec spec) { unsigned prefix_size = 0; typedef typename internal::IntTraits::MainType UnsignedType; UnsignedType abs_value = static_cast(value); char prefix[4] = ""; if (internal::is_negative(value)) { prefix[0] = '-'; ++prefix_size; abs_value = 0 - abs_value; } else if (spec.flag(SIGN_FLAG)) { prefix[0] = spec.flag(PLUS_FLAG) ? '+' : ' '; ++prefix_size; } switch (spec.type()) { case 0: case 'd': { unsigned num_digits = internal::count_digits(abs_value); CharPtr p = prepare_int_buffer(num_digits, spec, prefix, prefix_size) + 1; internal::format_decimal(get(p), abs_value, 0); break; } case 'x': case 'X': { UnsignedType n = abs_value; if (spec.flag(HASH_FLAG)) { prefix[prefix_size++] = '0'; prefix[prefix_size++] = spec.type(); } unsigned num_digits = 0; do { ++num_digits; } while ((n >>= 4) != 0); Char *p = get(prepare_int_buffer( num_digits, spec, prefix, prefix_size)); n = abs_value; const char *digits = spec.type() == 'x' ? "0123456789abcdef" : "0123456789ABCDEF"; do { *p-- = digits[n & 0xf]; } while ((n >>= 4) != 0); break; } case 'b': case 'B': { UnsignedType n = abs_value; if (spec.flag(HASH_FLAG)) { prefix[prefix_size++] = '0'; prefix[prefix_size++] = spec.type(); } unsigned num_digits = 0; do { ++num_digits; } while ((n >>= 1) != 0); Char *p = get(prepare_int_buffer(num_digits, spec, prefix, prefix_size)); n = abs_value; do { *p-- = static_cast('0' + (n & 1)); } while ((n >>= 1) != 0); break; } case 'o': { UnsignedType n = abs_value; if (spec.flag(HASH_FLAG)) prefix[prefix_size++] = '0'; unsigned num_digits = 0; do { ++num_digits; } while ((n >>= 3) != 0); Char *p = get(prepare_int_buffer(num_digits, spec, prefix, prefix_size)); n = abs_value; do { *p-- = static_cast('0' + (n & 7)); } while ((n >>= 3) != 0); break; } case 'n': { unsigned num_digits = internal::count_digits(abs_value); fmt::StringRef sep = ""; #ifndef ANDROID sep = internal::thousands_sep(std::localeconv()); #endif unsigned size = static_cast( num_digits + sep.size() * ((num_digits - 1) / 3)); CharPtr p = prepare_int_buffer(size, spec, prefix, prefix_size) + 1; internal::format_decimal(get(p), abs_value, 0, internal::ThousandsSep(sep)); break; } default: internal::report_unknown_type( spec.type(), spec.flag(CHAR_FLAG) ? "char" : "integer"); break; } } template template void BasicWriter::write_double(T value, const FormatSpec &spec) { // Check type. char type = spec.type(); bool upper = false; switch (type) { case 0: type = 'g'; break; case 'e': case 'f': case 'g': case 'a': break; case 'F': #if FMT_MSC_VER // MSVC's printf doesn't support 'F'. type = 'f'; #endif // Fall through. case 'E': case 'G': case 'A': upper = true; break; default: internal::report_unknown_type(type, "double"); break; } char sign = 0; // Use isnegative instead of value < 0 because the latter is always // false for NaN. if (internal::FPUtil::isnegative(static_cast(value))) { sign = '-'; value = -value; } else if (spec.flag(SIGN_FLAG)) { sign = spec.flag(PLUS_FLAG) ? '+' : ' '; } if (internal::FPUtil::isnotanumber(value)) { // Format NaN ourselves because sprintf's output is not consistent // across platforms. std::size_t nan_size = 4; const char *nan = upper ? " NAN" : " nan"; if (!sign) { --nan_size; ++nan; } CharPtr out = write_str(nan, nan_size, spec); if (sign) *out = sign; return; } if (internal::FPUtil::isinfinity(value)) { // Format infinity ourselves because sprintf's output is not consistent // across platforms. std::size_t inf_size = 4; const char *inf = upper ? " INF" : " inf"; if (!sign) { --inf_size; ++inf; } CharPtr out = write_str(inf, inf_size, spec); if (sign) *out = sign; return; } std::size_t offset = buffer_.size(); unsigned width = spec.width(); if (sign) { buffer_.reserve(buffer_.size() + (width > 1u ? width : 1u)); if (width > 0) --width; ++offset; } // Build format string. enum { MAX_FORMAT_SIZE = 10 }; // longest format: %#-*.*Lg Char format[MAX_FORMAT_SIZE]; Char *format_ptr = format; *format_ptr++ = '%'; unsigned width_for_sprintf = width; if (spec.flag(HASH_FLAG)) *format_ptr++ = '#'; if (spec.align() == ALIGN_CENTER) { width_for_sprintf = 0; } else { if (spec.align() == ALIGN_LEFT) *format_ptr++ = '-'; if (width != 0) *format_ptr++ = '*'; } if (spec.precision() >= 0) { *format_ptr++ = '.'; *format_ptr++ = '*'; } append_float_length(format_ptr, value); *format_ptr++ = type; *format_ptr = '\0'; // Format using snprintf. Char fill = internal::CharTraits::cast(spec.fill()); unsigned n = 0; Char *start = 0; for (;;) { std::size_t buffer_size = buffer_.capacity() - offset; #if FMT_MSC_VER // MSVC's vsnprintf_s doesn't work with zero size, so reserve // space for at least one extra character to make the size non-zero. // Note that the buffer's capacity will increase by more than 1. if (buffer_size == 0) { buffer_.reserve(offset + 1); buffer_size = buffer_.capacity() - offset; } #endif start = &buffer_[offset]; int result = internal::CharTraits::format_float( start, buffer_size, format, width_for_sprintf, spec.precision(), value); if (result >= 0) { n = internal::to_unsigned(result); if (offset + n < buffer_.capacity()) break; // The buffer is large enough - continue with formatting. buffer_.reserve(offset + n + 1); } else { // If result is negative we ask to increase the capacity by at least 1, // but as std::vector, the buffer grows exponentially. buffer_.reserve(buffer_.capacity() + 1); } } if (sign) { if ((spec.align() != ALIGN_RIGHT && spec.align() != ALIGN_DEFAULT) || *start != ' ') { *(start - 1) = sign; sign = 0; } else { *(start - 1) = fill; } ++n; } if (spec.align() == ALIGN_CENTER && spec.width() > n) { width = spec.width(); CharPtr p = grow_buffer(width); std::memmove(get(p) + (width - n) / 2, get(p), n * sizeof(Char)); fill_padding(p, spec.width(), n, fill); return; } if (spec.fill() != ' ' || sign) { while (*start == ' ') *start++ = fill; if (sign) *(start - 1) = sign; } grow_buffer(n); } /** \rst This class template provides operations for formatting and writing data into a character stream. The output is stored in a memory buffer that grows dynamically. You can use one of the following typedefs for common character types and the standard allocator: +---------------+-----------------------------------------------------+ | Type | Definition | +===============+=====================================================+ | MemoryWriter | BasicMemoryWriter> | +---------------+-----------------------------------------------------+ | WMemoryWriter | BasicMemoryWriter> | +---------------+-----------------------------------------------------+ **Example**:: MemoryWriter out; out << "The answer is " << 42 << "\n"; out.write("({:+f}, {:+f})", -3.14, 3.14); This will write the following output to the ``out`` object: .. code-block:: none The answer is 42 (-3.140000, +3.140000) The output can be converted to an ``std::string`` with ``out.str()`` or accessed as a C string with ``out.c_str()``. \endrst */ template > class BasicMemoryWriter : public BasicWriter { private: internal::MemoryBuffer buffer_; public: explicit BasicMemoryWriter(const Allocator& alloc = Allocator()) : BasicWriter(buffer_), buffer_(alloc) {} #if FMT_USE_RVALUE_REFERENCES /** \rst Constructs a :class:`fmt::BasicMemoryWriter` object moving the content of the other object to it. \endrst */ BasicMemoryWriter(BasicMemoryWriter &&other) : BasicWriter(buffer_), buffer_(std::move(other.buffer_)) { } /** \rst Moves the content of the other ``BasicMemoryWriter`` object to this one. \endrst */ BasicMemoryWriter &operator=(BasicMemoryWriter &&other) { buffer_ = std::move(other.buffer_); return *this; } #endif }; typedef BasicMemoryWriter MemoryWriter; typedef BasicMemoryWriter WMemoryWriter; /** \rst This class template provides operations for formatting and writing data into a fixed-size array. For writing into a dynamically growing buffer use :class:`fmt::BasicMemoryWriter`. Any write method will throw ``std::runtime_error`` if the output doesn't fit into the array. You can use one of the following typedefs for common character types: +--------------+---------------------------+ | Type | Definition | +==============+===========================+ | ArrayWriter | BasicArrayWriter | +--------------+---------------------------+ | WArrayWriter | BasicArrayWriter | +--------------+---------------------------+ \endrst */ template class BasicArrayWriter : public BasicWriter { private: internal::FixedBuffer buffer_; public: /** \rst Constructs a :class:`fmt::BasicArrayWriter` object for *array* of the given size. \endrst */ BasicArrayWriter(Char *array, std::size_t size) : BasicWriter(buffer_), buffer_(array, size) {} /** \rst Constructs a :class:`fmt::BasicArrayWriter` object for *array* of the size known at compile time. \endrst */ template explicit BasicArrayWriter(Char(&array)[SIZE]) : BasicWriter(buffer_), buffer_(array, SIZE) {} }; typedef BasicArrayWriter ArrayWriter; typedef BasicArrayWriter WArrayWriter; // Reports a system error without throwing an exception. // Can be used to report errors from destructors. FMT_API void report_system_error(int error_code, StringRef message) FMT_NOEXCEPT; #if FMT_USE_WINDOWS_H /** A Windows error. */ class WindowsError : public SystemError { private: FMT_API void init(int error_code, CStringRef format_str, ArgList args); public: /** \rst Constructs a :class:`fmt::WindowsError` object with the description of the form .. parsed-literal:: **: ** where ** is the formatted message and ** is the system message corresponding to the error code. *error_code* is a Windows error code as given by ``GetLastError``. If *error_code* is not a valid error code such as -1, the system message will look like "error -1". **Example**:: // This throws a WindowsError with the description // cannot open file 'madeup': The system cannot find the file specified. // or similar (system message may vary). const char *filename = "madeup"; LPOFSTRUCT of = LPOFSTRUCT(); HFILE file = OpenFile(filename, &of, OF_READ); if (file == HFILE_ERROR) { throw fmt::WindowsError(GetLastError(), "cannot open file '{}'", filename); } \endrst */ WindowsError(int error_code, CStringRef message) { init(error_code, message, ArgList()); } FMT_VARIADIC_CTOR(WindowsError, init, int, CStringRef) }; // Reports a Windows error without throwing an exception. // Can be used to report errors from destructors. FMT_API void report_windows_error(int error_code, StringRef message) FMT_NOEXCEPT; #endif enum Color { BLACK, RED, GREEN, YELLOW, BLUE, MAGENTA, CYAN, WHITE }; /** Formats a string and prints it to stdout using ANSI escape sequences to specify color (experimental). Example: print_colored(fmt::RED, "Elapsed time: {0:.2f} seconds", 1.23); */ FMT_API void print_colored(Color c, CStringRef format, ArgList args); /** \rst Formats arguments and returns the result as a string. **Example**:: std::string message = format("The answer is {}", 42); \endrst */ inline std::string format(CStringRef format_str, ArgList args) { MemoryWriter w; w.write(format_str, args); return w.str(); } inline std::wstring format(WCStringRef format_str, ArgList args) { WMemoryWriter w; w.write(format_str, args); return w.str(); } /** \rst Prints formatted data to the file *f*. **Example**:: print(stderr, "Don't {}!", "panic"); \endrst */ FMT_API void print(std::FILE *f, CStringRef format_str, ArgList args); /** \rst Prints formatted data to ``stdout``. **Example**:: print("Elapsed time: {0:.2f} seconds", 1.23); \endrst */ FMT_API void print(CStringRef format_str, ArgList args); /** Fast integer formatter. */ class FormatInt { private: // Buffer should be large enough to hold all digits (digits10 + 1), // a sign and a null character. enum { BUFFER_SIZE = std::numeric_limits::digits10 + 3 }; mutable char buffer_[BUFFER_SIZE]; char *str_; // Formats value in reverse and returns the number of digits. char *format_decimal(ULongLong value) { char *buffer_end = buffer_ + BUFFER_SIZE - 1; while (value >= 100) { // Integer division is slow so do it for a group of two digits instead // of for every digit. The idea comes from the talk by Alexandrescu // "Three Optimization Tips for C++". See speed-test for a comparison. unsigned index = static_cast((value % 100) * 2); value /= 100; *--buffer_end = internal::Data::DIGITS[index + 1]; *--buffer_end = internal::Data::DIGITS[index]; } if (value < 10) { *--buffer_end = static_cast('0' + value); return buffer_end; } unsigned index = static_cast(value * 2); *--buffer_end = internal::Data::DIGITS[index + 1]; *--buffer_end = internal::Data::DIGITS[index]; return buffer_end; } void FormatSigned(LongLong value) { ULongLong abs_value = static_cast(value); bool negative = value < 0; if (negative) abs_value = 0 - abs_value; str_ = format_decimal(abs_value); if (negative) *--str_ = '-'; } public: explicit FormatInt(int value) { FormatSigned(value); } explicit FormatInt(long value) { FormatSigned(value); } explicit FormatInt(LongLong value) { FormatSigned(value); } explicit FormatInt(unsigned value) : str_(format_decimal(value)) {} explicit FormatInt(unsigned long value) : str_(format_decimal(value)) {} explicit FormatInt(ULongLong value) : str_(format_decimal(value)) {} /** Returns the number of characters written to the output buffer. */ std::size_t size() const { return internal::to_unsigned(buffer_ - str_ + BUFFER_SIZE - 1); } /** Returns a pointer to the output buffer content. No terminating null character is appended. */ const char *data() const { return str_; } /** Returns a pointer to the output buffer content with terminating null character appended. */ const char *c_str() const { buffer_[BUFFER_SIZE - 1] = '\0'; return str_; } /** \rst Returns the content of the output buffer as an ``std::string``. \endrst */ std::string str() const { return std::string(str_, size()); } }; // Formats a decimal integer value writing into buffer and returns // a pointer to the end of the formatted string. This function doesn't // write a terminating null character. template inline void format_decimal(char *&buffer, T value) { typedef typename internal::IntTraits::MainType MainType; MainType abs_value = static_cast(value); if (internal::is_negative(value)) { *buffer++ = '-'; abs_value = 0 - abs_value; } if (abs_value < 100) { if (abs_value < 10) { *buffer++ = static_cast('0' + abs_value); return; } unsigned index = static_cast(abs_value * 2); *buffer++ = internal::Data::DIGITS[index]; *buffer++ = internal::Data::DIGITS[index + 1]; return; } unsigned num_digits = internal::count_digits(abs_value); internal::format_decimal(buffer, abs_value, num_digits); buffer += num_digits; } /** \rst Returns a named argument for formatting functions. **Example**:: print("Elapsed time: {s:.2f} seconds", arg("s", 1.23)); \endrst */ template inline internal::NamedArgWithType arg(StringRef name, const T &arg) { return internal::NamedArgWithType(name, arg); } template inline internal::NamedArgWithType arg(WStringRef name, const T &arg) { return internal::NamedArgWithType(name, arg); } // The following two functions are deleted intentionally to disable // nested named arguments as in ``format("{}", arg("a", arg("b", 42)))``. template void arg(StringRef, const internal::NamedArg&) FMT_DELETED_OR_UNDEFINED; template void arg(WStringRef, const internal::NamedArg&) FMT_DELETED_OR_UNDEFINED; } #if FMT_GCC_VERSION // Use the system_header pragma to suppress warnings about variadic macros // because suppressing -Wvariadic-macros with the diagnostic pragma doesn't // work. It is used at the end because we want to suppress as little warnings // as possible. # pragma GCC system_header #endif // This is used to work around VC++ bugs in handling variadic macros. #define FMT_EXPAND(args) args // Returns the number of arguments. // Based on https://groups.google.com/forum/#!topic/comp.std.c/d-6Mj5Lko_s. #define FMT_NARG(...) FMT_NARG_(__VA_ARGS__, FMT_RSEQ_N()) #define FMT_NARG_(...) FMT_EXPAND(FMT_ARG_N(__VA_ARGS__)) #define FMT_ARG_N(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, N, ...) N #define FMT_RSEQ_N() 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 #define FMT_FOR_EACH_(N, f, ...) \ FMT_EXPAND(FMT_CONCAT(FMT_FOR_EACH, N)(f, __VA_ARGS__)) #define FMT_FOR_EACH(f, ...) \ FMT_EXPAND(FMT_FOR_EACH_(FMT_NARG(__VA_ARGS__), f, __VA_ARGS__)) #define FMT_ADD_ARG_NAME(type, index) type arg##index #define FMT_GET_ARG_NAME(type, index) arg##index #if FMT_USE_VARIADIC_TEMPLATES # define FMT_VARIADIC_(Char, ReturnType, func, call, ...) \ template \ ReturnType func(FMT_FOR_EACH(FMT_ADD_ARG_NAME, __VA_ARGS__), \ const Args & ... args) { \ typedef fmt::internal::ArgArray ArgArray; \ typename ArgArray::Type array{ \ ArgArray::template make >(args)...}; \ call(FMT_FOR_EACH(FMT_GET_ARG_NAME, __VA_ARGS__), \ fmt::ArgList(fmt::internal::make_type(args...), array)); \ } #else // Defines a wrapper for a function taking __VA_ARGS__ arguments // and n additional arguments of arbitrary types. # define FMT_WRAP(Char, ReturnType, func, call, n, ...) \ template \ inline ReturnType func(FMT_FOR_EACH(FMT_ADD_ARG_NAME, __VA_ARGS__), \ FMT_GEN(n, FMT_MAKE_ARG)) { \ fmt::internal::ArgArray::Type arr; \ FMT_GEN(n, FMT_ASSIGN_##Char); \ call(FMT_FOR_EACH(FMT_GET_ARG_NAME, __VA_ARGS__), fmt::ArgList( \ fmt::internal::make_type(FMT_GEN(n, FMT_MAKE_REF2)), arr)); \ } # define FMT_VARIADIC_(Char, ReturnType, func, call, ...) \ inline ReturnType func(FMT_FOR_EACH(FMT_ADD_ARG_NAME, __VA_ARGS__)) { \ call(FMT_FOR_EACH(FMT_GET_ARG_NAME, __VA_ARGS__), fmt::ArgList()); \ } \ FMT_WRAP(Char, ReturnType, func, call, 1, __VA_ARGS__) \ FMT_WRAP(Char, ReturnType, func, call, 2, __VA_ARGS__) \ FMT_WRAP(Char, ReturnType, func, call, 3, __VA_ARGS__) \ FMT_WRAP(Char, ReturnType, func, call, 4, __VA_ARGS__) \ FMT_WRAP(Char, ReturnType, func, call, 5, __VA_ARGS__) \ FMT_WRAP(Char, ReturnType, func, call, 6, __VA_ARGS__) \ FMT_WRAP(Char, ReturnType, func, call, 7, __VA_ARGS__) \ FMT_WRAP(Char, ReturnType, func, call, 8, __VA_ARGS__) \ FMT_WRAP(Char, ReturnType, func, call, 9, __VA_ARGS__) \ FMT_WRAP(Char, ReturnType, func, call, 10, __VA_ARGS__) \ FMT_WRAP(Char, ReturnType, func, call, 11, __VA_ARGS__) \ FMT_WRAP(Char, ReturnType, func, call, 12, __VA_ARGS__) \ FMT_WRAP(Char, ReturnType, func, call, 13, __VA_ARGS__) \ FMT_WRAP(Char, ReturnType, func, call, 14, __VA_ARGS__) \ FMT_WRAP(Char, ReturnType, func, call, 15, __VA_ARGS__) #endif // FMT_USE_VARIADIC_TEMPLATES /** \rst Defines a variadic function with the specified return type, function name and argument types passed as variable arguments to this macro. **Example**:: void print_error(const char *file, int line, const char *format, fmt::ArgList args) { fmt::print("{}: {}: ", file, line); fmt::print(format, args); } FMT_VARIADIC(void, print_error, const char *, int, const char *) ``FMT_VARIADIC`` is used for compatibility with legacy C++ compilers that don't implement variadic templates. You don't have to use this macro if you don't need legacy compiler support and can use variadic templates directly:: template void print_error(const char *file, int line, const char *format, const Args & ... args) { fmt::print("{}: {}: ", file, line); fmt::print(format, args...); } \endrst */ #define FMT_VARIADIC(ReturnType, func, ...) \ FMT_VARIADIC_(char, ReturnType, func, return func, __VA_ARGS__) #define FMT_VARIADIC_W(ReturnType, func, ...) \ FMT_VARIADIC_(wchar_t, ReturnType, func, return func, __VA_ARGS__) #define FMT_CAPTURE_ARG_(id, index) ::fmt::arg(#id, id) #define FMT_CAPTURE_ARG_W_(id, index) ::fmt::arg(L###id, id) /** \rst Convenient macro to capture the arguments' names and values into several ``fmt::arg(name, value)``. **Example**:: int x = 1, y = 2; print("point: ({x}, {y})", FMT_CAPTURE(x, y)); // same as: // print("point: ({x}, {y})", arg("x", x), arg("y", y)); \endrst */ #define FMT_CAPTURE(...) FMT_FOR_EACH(FMT_CAPTURE_ARG_, __VA_ARGS__) #define FMT_CAPTURE_W(...) FMT_FOR_EACH(FMT_CAPTURE_ARG_W_, __VA_ARGS__) namespace fmt { FMT_VARIADIC(std::string, format, CStringRef) FMT_VARIADIC_W(std::wstring, format, WCStringRef) FMT_VARIADIC(void, print, CStringRef) FMT_VARIADIC(void, print, std::FILE *, CStringRef) FMT_VARIADIC(void, print_colored, Color, CStringRef) namespace internal { template inline bool is_name_start(Char c) { return ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || '_' == c; } // Parses an unsigned integer advancing s to the end of the parsed input. // This function assumes that the first character of s is a digit. template unsigned parse_nonnegative_int(const Char *&s) { assert('0' <= *s && *s <= '9'); unsigned value = 0; do { unsigned new_value = value * 10 + (*s++ - '0'); // Check if value wrapped around. if (new_value < value) { value = (std::numeric_limits::max)(); break; } value = new_value; } while ('0' <= *s && *s <= '9'); // Convert to unsigned to prevent a warning. unsigned max_int = (std::numeric_limits::max)(); if (value > max_int) FMT_THROW(FormatError("number is too big")); return value; } inline void require_numeric_argument(const Arg &arg, char spec) { if (arg.type > Arg::LAST_NUMERIC_TYPE) { std::string message = fmt::format("format specifier '{}' requires numeric argument", spec); FMT_THROW(fmt::FormatError(message)); } } template void check_sign(const Char *&s, const Arg &arg) { char sign = static_cast(*s); require_numeric_argument(arg, sign); if (arg.type == Arg::UINT || arg.type == Arg::ULONG_LONG) { FMT_THROW(FormatError(fmt::format( "format specifier '{}' requires signed argument", sign))); } ++s; } } // namespace internal template inline internal::Arg BasicFormatter::get_arg( BasicStringRef arg_name, const char *&error) { if (check_no_auto_index(error)) { map_.init(args()); const internal::Arg *arg = map_.find(arg_name); if (arg) return *arg; error = "argument not found"; } return internal::Arg(); } template inline internal::Arg BasicFormatter::parse_arg_index(const Char *&s) { const char *error = 0; internal::Arg arg = *s < '0' || *s > '9' ? next_arg(error) : get_arg(internal::parse_nonnegative_int(s), error); if (error) { FMT_THROW(FormatError( *s != '}' && *s != ':' ? "invalid format string" : error)); } return arg; } template inline internal::Arg BasicFormatter::parse_arg_name(const Char *&s) { assert(internal::is_name_start(*s)); const Char *start = s; Char c; do { c = *++s; } while (internal::is_name_start(c) || ('0' <= c && c <= '9')); const char *error = 0; internal::Arg arg = get_arg(BasicStringRef(start, s - start), error); if (error) FMT_THROW(FormatError(error)); return arg; } template const Char *BasicFormatter::format( const Char *&format_str, const internal::Arg &arg) { using internal::Arg; const Char *s = format_str; FormatSpec spec; if (*s == ':') { if (arg.type == Arg::CUSTOM) { arg.custom.format(this, arg.custom.value, &s); return s; } ++s; // Parse fill and alignment. if (Char c = *s) { const Char *p = s + 1; spec.align_ = ALIGN_DEFAULT; do { switch (*p) { case '<': spec.align_ = ALIGN_LEFT; break; case '>': spec.align_ = ALIGN_RIGHT; break; case '=': spec.align_ = ALIGN_NUMERIC; break; case '^': spec.align_ = ALIGN_CENTER; break; } if (spec.align_ != ALIGN_DEFAULT) { if (p != s) { if (c == '}') break; if (c == '{') FMT_THROW(FormatError("invalid fill character '{'")); s += 2; spec.fill_ = c; } else ++s; if (spec.align_ == ALIGN_NUMERIC) require_numeric_argument(arg, '='); break; } } while (--p >= s); } // Parse sign. switch (*s) { case '+': check_sign(s, arg); spec.flags_ |= SIGN_FLAG | PLUS_FLAG; break; case '-': check_sign(s, arg); spec.flags_ |= MINUS_FLAG; break; case ' ': check_sign(s, arg); spec.flags_ |= SIGN_FLAG; break; } if (*s == '#') { require_numeric_argument(arg, '#'); spec.flags_ |= HASH_FLAG; ++s; } // Parse zero flag. if (*s == '0') { require_numeric_argument(arg, '0'); spec.align_ = ALIGN_NUMERIC; spec.fill_ = '0'; ++s; } // Parse width. if ('0' <= *s && *s <= '9') { spec.width_ = internal::parse_nonnegative_int(s); } else if (*s == '{') { ++s; Arg width_arg = internal::is_name_start(*s) ? parse_arg_name(s) : parse_arg_index(s); if (*s++ != '}') FMT_THROW(FormatError("invalid format string")); ULongLong value = 0; switch (width_arg.type) { case Arg::INT: if (width_arg.int_value < 0) FMT_THROW(FormatError("negative width")); value = width_arg.int_value; break; case Arg::UINT: value = width_arg.uint_value; break; case Arg::LONG_LONG: if (width_arg.long_long_value < 0) FMT_THROW(FormatError("negative width")); value = width_arg.long_long_value; break; case Arg::ULONG_LONG: value = width_arg.ulong_long_value; break; default: FMT_THROW(FormatError("width is not integer")); } if (value >(std::numeric_limits::max)()) FMT_THROW(FormatError("number is too big")); spec.width_ = static_cast(value); } // Parse precision. if (*s == '.') { ++s; spec.precision_ = 0; if ('0' <= *s && *s <= '9') { spec.precision_ = internal::parse_nonnegative_int(s); } else if (*s == '{') { ++s; Arg precision_arg = internal::is_name_start(*s) ? parse_arg_name(s) : parse_arg_index(s); if (*s++ != '}') FMT_THROW(FormatError("invalid format string")); ULongLong value = 0; switch (precision_arg.type) { case Arg::INT: if (precision_arg.int_value < 0) FMT_THROW(FormatError("negative precision")); value = precision_arg.int_value; break; case Arg::UINT: value = precision_arg.uint_value; break; case Arg::LONG_LONG: if (precision_arg.long_long_value < 0) FMT_THROW(FormatError("negative precision")); value = precision_arg.long_long_value; break; case Arg::ULONG_LONG: value = precision_arg.ulong_long_value; break; default: FMT_THROW(FormatError("precision is not integer")); } if (value >(std::numeric_limits::max)()) FMT_THROW(FormatError("number is too big")); spec.precision_ = static_cast(value); } else { FMT_THROW(FormatError("missing precision specifier")); } if (arg.type <= Arg::LAST_INTEGER_TYPE || arg.type == Arg::POINTER) { FMT_THROW(FormatError( fmt::format("precision not allowed in {} format specifier", arg.type == Arg::POINTER ? "pointer" : "integer"))); } } // Parse type. if (*s != '}' && *s) spec.type_ = static_cast(*s++); } if (*s++ != '}') FMT_THROW(FormatError("missing '}' in format string")); // Format argument. ArgFormatter(*this, spec, s - 1).visit(arg); return s; } template void BasicFormatter::format(BasicCStringRef format_str) { const Char *s = format_str.c_str(); const Char *start = s; while (*s) { Char c = *s++; if (c != '{' && c != '}') continue; if (*s == c) { write(writer_, start, s); start = ++s; continue; } if (c == '}') FMT_THROW(FormatError("unmatched '}' in format string")); write(writer_, start, s - 1); internal::Arg arg = internal::is_name_start(*s) ? parse_arg_name(s) : parse_arg_index(s); start = s = format(s, arg); } write(writer_, start, s); } } // namespace fmt #if FMT_USE_USER_DEFINED_LITERALS namespace fmt { namespace internal { template struct UdlFormat { const Char *str; template auto operator()(Args && ... args) const -> decltype(format(str, std::forward(args)...)) { return format(str, std::forward(args)...); } }; template struct UdlArg { const Char *str; template NamedArgWithType operator=(T &&value) const { return{ str, std::forward(value) }; } }; } // namespace internal inline namespace literals { /** \rst C++11 literal equivalent of :func:`fmt::format`. **Example**:: using namespace fmt::literals; std::string message = "The answer is {}"_format(42); \endrst */ inline internal::UdlFormat operator"" _format(const char *s, std::size_t) { return{ s }; } inline internal::UdlFormat operator"" _format(const wchar_t *s, std::size_t) { return{ s }; } /** \rst C++11 literal equivalent of :func:`fmt::arg`. **Example**:: using namespace fmt::literals; print("Elapsed time: {s:.2f} seconds", "s"_a=1.23); \endrst */ inline internal::UdlArg operator"" _a(const char *s, std::size_t) { return{ s }; } inline internal::UdlArg operator"" _a(const wchar_t *s, std::size_t) { return{ s }; } } // inline namespace literals } // namespace fmt #endif // FMT_USE_USER_DEFINED_LITERALS // Restore warnings. #if FMT_GCC_VERSION >= 406 # pragma GCC diagnostic pop #endif #if defined(__clang__) && !defined(FMT_ICC_VERSION) # pragma clang diagnostic pop #endif #ifdef FMT_HEADER_ONLY # define FMT_FUNC inline # include "format.cc" #else # define FMT_FUNC #endif #endif // FMT_FORMAT_H_gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/Utility/GmmLog/spdlog/fmt/bundled/ostream.cc000066400000000000000000000016331466655022700303570ustar00rootroot00000000000000/* Formatting library for C++ - std::ostream support Copyright (c) 2012 - 2016, Victor Zverovich All rights reserved. For the license information refer to format.h. */ #include "ostream.h" namespace fmt { namespace internal { FMT_FUNC void write(std::ostream &os, Writer &w) { const char *data = w.data(); typedef internal::MakeUnsigned::Type UnsignedStreamSize; UnsignedStreamSize size = w.size(); UnsignedStreamSize max_size = internal::to_unsigned((std::numeric_limits::max)()); do { UnsignedStreamSize n = size <= max_size ? size : max_size; os.write(data, static_cast(n)); data += n; size -= n; } while (size != 0); } } FMT_FUNC void print(std::ostream &os, CStringRef format_str, ArgList args) { MemoryWriter w; w.write(format_str, args); internal::write(os, w); } } // namespace fmtgmmlib-intel-gmmlib-22.5.2/Source/GmmLib/Utility/GmmLog/spdlog/fmt/bundled/ostream.h000066400000000000000000000053501466655022700302210ustar00rootroot00000000000000/* Formatting library for C++ - std::ostream support Copyright (c) 2012 - 2016, Victor Zverovich All rights reserved. For the license information refer to format.h. */ #ifndef FMT_OSTREAM_H_ #define FMT_OSTREAM_H_ // commented out by spdlog //#include "format.h" #include namespace fmt { namespace internal { template class FormatBuf : public std::basic_streambuf { private: typedef typename std::basic_streambuf::int_type int_type; typedef typename std::basic_streambuf::traits_type traits_type; Buffer &buffer_; Char *start_; public: FormatBuf(Buffer &buffer) : buffer_(buffer), start_(&buffer[0]) { this->setp(start_, start_ + buffer_.capacity()); } int_type overflow(int_type ch = traits_type::eof()) { if (!traits_type::eq_int_type(ch, traits_type::eof())) { size_t buf_size = size(); buffer_.resize(buf_size); buffer_.reserve(buf_size * 2); start_ = &buffer_[0]; start_[buf_size] = traits_type::to_char_type(ch); this->setp(start_ + buf_size + 1, start_ + buf_size * 2); } return ch; } size_t size() const { return to_unsigned(this->pptr() - start_); } }; Yes &convert(std::ostream &); struct DummyStream : std::ostream { DummyStream(); // Suppress a bogus warning in MSVC. // Hide all operator<< overloads from std::ostream. void operator<<(Null<>); }; No &operator<<(std::ostream &, int); template struct ConvertToIntImpl { // Convert to int only if T doesn't have an overloaded operator<<. enum { value = sizeof(convert(get() << get())) == sizeof(No) }; }; // Write the content of w to os. void write(std::ostream &os, Writer &w); } // namespace internal // Formats a value. template void format_arg(BasicFormatter &f, const Char *&format_str, const T &value) { internal::MemoryBuffer buffer; internal::FormatBuf format_buf(buffer); std::basic_ostream output(&format_buf); output << value; BasicStringRef str(&buffer[0], format_buf.size()); typedef internal::MakeArg< BasicFormatter > MakeArg; format_str = f.format(format_str, MakeArg(str)); } /** \rst Prints formatted data to the stream *os*. **Example**:: print(cerr, "Don't {}!", "panic"); \endrst */ FMT_API void print(std::ostream &os, CStringRef format_str, ArgList args); FMT_VARIADIC(void, print, std::ostream &, CStringRef) } // namespace fmt #ifdef FMT_HEADER_ONLY # include "ostream.cc" #endif #endif // FMT_OSTREAM_H_gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/Utility/GmmLog/spdlog/fmt/bundled/printf.h000066400000000000000000000420661466655022700300560ustar00rootroot00000000000000/* Formatting library for C++ Copyright (c) 2012 - 2016, Victor Zverovich All rights reserved. For the license information refer to format.h. */ #ifndef FMT_PRINTF_H_ #define FMT_PRINTF_H_ #include // std::fill_n #include // std::numeric_limits #include "ostream.h" namespace fmt { namespace internal { // Checks if a value fits in int - used to avoid warnings about comparing // signed and unsigned integers. template struct IntChecker { template static bool fits_in_int(T value) { unsigned max = std::numeric_limits::max(); return value <= max; } static bool fits_in_int(bool) { return true; } }; template <> struct IntChecker { template static bool fits_in_int(T value) { return value >= std::numeric_limits::min() && value <= std::numeric_limits::max(); } static bool fits_in_int(int) { return true; } }; class PrecisionHandler : public ArgVisitor { public: void report_unhandled_arg() { FMT_THROW(FormatError("precision is not integer")); } template int visit_any_int(T value) { if (!IntChecker::is_signed>::fits_in_int(value)) FMT_THROW(FormatError("number is too big")); return static_cast(value); } }; // IsZeroInt::visit(arg) returns true iff arg is a zero integer. class IsZeroInt : public ArgVisitor { public: template bool visit_any_int(T value) { return value == 0; } }; template struct is_same { enum { value = 0 }; }; template struct is_same { enum { value = 1 }; }; // An argument visitor that converts an integer argument to T for printf, // if T is an integral type. If T is void, the argument is converted to // corresponding signed or unsigned type depending on the type specifier: // 'd' and 'i' - signed, other - unsigned) template class ArgConverter : public ArgVisitor, void> { private: internal::Arg &arg_; wchar_t type_; FMT_DISALLOW_COPY_AND_ASSIGN(ArgConverter); public: ArgConverter(internal::Arg &arg, wchar_t type) : arg_(arg), type_(type) {} void visit_bool(bool value) { if (type_ != 's') visit_any_int(value); } template void visit_any_int(U value) { bool is_signed = type_ == 'd' || type_ == 'i'; using internal::Arg; typedef typename internal::Conditional< is_same::value, U, T>::type TargetType; if (sizeof(TargetType) <= sizeof(int)) { // Extra casts are used to silence warnings. if (is_signed) { arg_.type = Arg::INT; arg_.int_value = static_cast(static_cast(value)); } else { arg_.type = Arg::UINT; typedef typename internal::MakeUnsigned::Type Unsigned; arg_.uint_value = static_cast(static_cast(value)); } } else { if (is_signed) { arg_.type = Arg::LONG_LONG; // glibc's printf doesn't sign extend arguments of smaller types: // std::printf("%lld", -42); // prints "4294967254" // but we don't have to do the same because it's a UB. arg_.long_long_value = static_cast(value); } else { arg_.type = Arg::ULONG_LONG; arg_.ulong_long_value = static_cast::Type>(value); } } } }; // Converts an integer argument to char for printf. class CharConverter : public ArgVisitor { private: internal::Arg &arg_; FMT_DISALLOW_COPY_AND_ASSIGN(CharConverter); public: explicit CharConverter(internal::Arg &arg) : arg_(arg) {} template void visit_any_int(T value) { arg_.type = internal::Arg::CHAR; arg_.int_value = static_cast(value); } }; // Checks if an argument is a valid printf width specifier and sets // left alignment if it is negative. class WidthHandler : public ArgVisitor { private: FormatSpec &spec_; FMT_DISALLOW_COPY_AND_ASSIGN(WidthHandler); public: explicit WidthHandler(FormatSpec &spec) : spec_(spec) {} void report_unhandled_arg() { FMT_THROW(FormatError("width is not integer")); } template unsigned visit_any_int(T value) { typedef typename internal::IntTraits::MainType UnsignedType; UnsignedType width = static_cast(value); if (internal::is_negative(value)) { spec_.align_ = ALIGN_LEFT; width = 0 - width; } unsigned int_max = std::numeric_limits::max(); if (width > int_max) FMT_THROW(FormatError("number is too big")); return static_cast(width); } }; } // namespace internal /** \rst A ``printf`` argument formatter based on the `curiously recurring template pattern `_. To use `~fmt::BasicPrintfArgFormatter` define a subclass that implements some or all of the visit methods with the same signatures as the methods in `~fmt::ArgVisitor`, for example, `~fmt::ArgVisitor::visit_int()`. Pass the subclass as the *Impl* template parameter. When a formatting function processes an argument, it will dispatch to a visit method specific to the argument type. For example, if the argument type is ``double`` then the `~fmt::ArgVisitor::visit_double()` method of a subclass will be called. If the subclass doesn't contain a method with this signature, then a corresponding method of `~fmt::BasicPrintfArgFormatter` or its superclass will be called. \endrst */ template class BasicPrintfArgFormatter : public internal::ArgFormatterBase { private: void write_null_pointer() { this->spec().type_ = 0; this->write("(nil)"); } typedef internal::ArgFormatterBase Base; public: /** \rst Constructs an argument formatter object. *writer* is a reference to the output writer and *spec* contains format specifier information for standard argument types. \endrst */ BasicPrintfArgFormatter(BasicWriter &writer, FormatSpec &spec) : internal::ArgFormatterBase(writer, spec) {} /** Formats an argument of type ``bool``. */ void visit_bool(bool value) { FormatSpec &fmt_spec = this->spec(); if (fmt_spec.type_ != 's') return this->visit_any_int(value); fmt_spec.type_ = 0; this->write(value); } /** Formats a character. */ void visit_char(int value) { const FormatSpec &fmt_spec = this->spec(); BasicWriter &w = this->writer(); if (fmt_spec.type_ && fmt_spec.type_ != 'c') w.write_int(value, fmt_spec); typedef typename BasicWriter::CharPtr CharPtr; CharPtr out = CharPtr(); if (fmt_spec.width_ > 1) { Char fill = ' '; out = w.grow_buffer(fmt_spec.width_); if (fmt_spec.align_ != ALIGN_LEFT) { std::fill_n(out, fmt_spec.width_ - 1, fill); out += fmt_spec.width_ - 1; } else { std::fill_n(out + 1, fmt_spec.width_ - 1, fill); } } else { out = w.grow_buffer(1); } *out = static_cast(value); } /** Formats a null-terminated C string. */ void visit_cstring(const char *value) { if (value) Base::visit_cstring(value); else if (this->spec().type_ == 'p') write_null_pointer(); else this->write("(null)"); } /** Formats a pointer. */ void visit_pointer(const void *value) { if (value) return Base::visit_pointer(value); this->spec().type_ = 0; write_null_pointer(); } /** Formats an argument of a custom (user-defined) type. */ void visit_custom(internal::Arg::CustomValue c) { BasicFormatter formatter(ArgList(), this->writer()); const Char format_str[] = { '}', 0 }; const Char *format = format_str; c.format(&formatter, c.value, &format); } }; /** The default printf argument formatter. */ template class PrintfArgFormatter : public BasicPrintfArgFormatter, Char> { public: /** Constructs an argument formatter object. */ PrintfArgFormatter(BasicWriter &w, FormatSpec &s) : BasicPrintfArgFormatter, Char>(w, s) {} }; /** This template formats data and writes the output to a writer. */ template > class PrintfFormatter : private internal::FormatterBase { private: BasicWriter &writer_; void parse_flags(FormatSpec &spec, const Char *&s); // Returns the argument with specified index or, if arg_index is equal // to the maximum unsigned value, the next argument. internal::Arg get_arg( const Char *s, unsigned arg_index = (std::numeric_limits::max)()); // Parses argument index, flags and width and returns the argument index. unsigned parse_header(const Char *&s, FormatSpec &spec); public: /** \rst Constructs a ``PrintfFormatter`` object. References to the arguments and the writer are stored in the formatter object so make sure they have appropriate lifetimes. \endrst */ explicit PrintfFormatter(const ArgList &args, BasicWriter &w) : FormatterBase(args), writer_(w) {} /** Formats stored arguments and writes the output to the writer. */ FMT_API void format(BasicCStringRef format_str); }; template void PrintfFormatter::parse_flags(FormatSpec &spec, const Char *&s) { for (;;) { switch (*s++) { case '-': spec.align_ = ALIGN_LEFT; break; case '+': spec.flags_ |= SIGN_FLAG | PLUS_FLAG; break; case '0': spec.fill_ = '0'; break; case ' ': spec.flags_ |= SIGN_FLAG; break; case '#': spec.flags_ |= HASH_FLAG; break; default: --s; return; } } } template internal::Arg PrintfFormatter::get_arg(const Char *s, unsigned arg_index) { (void)s; const char *error = 0; internal::Arg arg = arg_index == std::numeric_limits::max() ? next_arg(error) : FormatterBase::get_arg(arg_index - 1, error); if (error) FMT_THROW(FormatError(!*s ? "invalid format string" : error)); return arg; } template unsigned PrintfFormatter::parse_header( const Char *&s, FormatSpec &spec) { unsigned arg_index = std::numeric_limits::max(); Char c = *s; if (c >= '0' && c <= '9') { // Parse an argument index (if followed by '$') or a width possibly // preceded with '0' flag(s). unsigned value = internal::parse_nonnegative_int(s); if (*s == '$') // value is an argument index { ++s; arg_index = value; } else { if (c == '0') spec.fill_ = '0'; if (value != 0) { // Nonzero value means that we parsed width and don't need to // parse it or flags again, so return now. spec.width_ = value; return arg_index; } } } parse_flags(spec, s); // Parse width. if (*s >= '0' && *s <= '9') { spec.width_ = internal::parse_nonnegative_int(s); } else if (*s == '*') { ++s; spec.width_ = internal::WidthHandler(spec).visit(get_arg(s)); } return arg_index; } template void PrintfFormatter::format(BasicCStringRef format_str) { const Char *start = format_str.c_str(); const Char *s = start; while (*s) { Char c = *s++; if (c != '%') continue; if (*s == c) { write(writer_, start, s); start = ++s; continue; } write(writer_, start, s - 1); FormatSpec spec; spec.align_ = ALIGN_RIGHT; // Parse argument index, flags and width. unsigned arg_index = parse_header(s, spec); // Parse precision. if (*s == '.') { ++s; if ('0' <= *s && *s <= '9') { spec.precision_ = static_cast(internal::parse_nonnegative_int(s)); } else if (*s == '*') { ++s; spec.precision_ = internal::PrecisionHandler().visit(get_arg(s)); } } using internal::Arg; Arg arg = get_arg(s, arg_index); if (spec.flag(HASH_FLAG) && internal::IsZeroInt().visit(arg)) spec.flags_ &= ~internal::to_unsigned(HASH_FLAG); if (spec.fill_ == '0') { if (arg.type <= Arg::LAST_NUMERIC_TYPE) spec.align_ = ALIGN_NUMERIC; else spec.fill_ = ' '; // Ignore '0' flag for non-numeric types. } // Parse length and convert the argument to the required type. using internal::ArgConverter; switch (*s++) { case 'h': if (*s == 'h') ArgConverter(arg, *++s).visit(arg); else ArgConverter(arg, *s).visit(arg); break; case 'l': if (*s == 'l') ArgConverter(arg, *++s).visit(arg); else ArgConverter(arg, *s).visit(arg); break; case 'j': ArgConverter(arg, *s).visit(arg); break; case 'z': ArgConverter(arg, *s).visit(arg); break; case 't': ArgConverter(arg, *s).visit(arg); break; case 'L': // printf produces garbage when 'L' is omitted for long double, no // need to do the same. break; default: --s; ArgConverter(arg, *s).visit(arg); } // Parse type. if (!*s) FMT_THROW(FormatError("invalid format string")); spec.type_ = static_cast(*s++); if (arg.type <= Arg::LAST_INTEGER_TYPE) { // Normalize type. switch (spec.type_) { case 'i': case 'u': spec.type_ = 'd'; break; case 'c': // TODO: handle wchar_t internal::CharConverter(arg).visit(arg); break; } } start = s; // Format argument. AF(writer_, spec).visit(arg); } write(writer_, start, s); } template void printf(BasicWriter &w, BasicCStringRef format, ArgList args) { PrintfFormatter(args, w).format(format); } /** \rst Formats arguments and returns the result as a string. **Example**:: std::string message = fmt::sprintf("The answer is %d", 42); \endrst */ inline std::string sprintf(CStringRef format, ArgList args) { MemoryWriter w; printf(w, format, args); return w.str(); } FMT_VARIADIC(std::string, sprintf, CStringRef) inline std::wstring sprintf(WCStringRef format, ArgList args) { WMemoryWriter w; printf(w, format, args); return w.str(); } FMT_VARIADIC_W(std::wstring, sprintf, WCStringRef) /** \rst Prints formatted data to the file *f*. **Example**:: fmt::fprintf(stderr, "Don't %s!", "panic"); \endrst */ FMT_API int fprintf(std::FILE *f, CStringRef format, ArgList args); FMT_VARIADIC(int, fprintf, std::FILE *, CStringRef) /** \rst Prints formatted data to ``stdout``. **Example**:: fmt::printf("Elapsed time: %.2f seconds", 1.23); \endrst */ inline int printf(CStringRef format, ArgList args) { return fprintf(stdout, format, args); } FMT_VARIADIC(int, printf, CStringRef) /** \rst Prints formatted data to the stream *os*. **Example**:: fprintf(cerr, "Don't %s!", "panic"); \endrst */ inline int fprintf(std::ostream &os, CStringRef format_str, ArgList args) { MemoryWriter w; printf(w, format_str, args); internal::write(os, w); return static_cast(w.size()); } FMT_VARIADIC(int, fprintf, std::ostream &, CStringRef) } // namespace fmt #endif // FMT_PRINTF_H_gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/Utility/GmmLog/spdlog/fmt/fmt.h000066400000000000000000000007601466655022700257200ustar00rootroot00000000000000// // Copyright(c) 2016 Gabi Melman. // Distributed under the MIT License (http://opensource.org/licenses/MIT) // #pragma once // // Include a bundled header-only copy of fmtlib or an external one. // By default spdlog include its own copy. // #if !defined(SPDLOG_FMT_EXTERNAL) #ifndef FMT_HEADER_ONLY #define FMT_HEADER_ONLY #endif #ifndef FMT_USE_WINDOWS_H #define FMT_USE_WINDOWS_H 0 #endif #include #else //external fmtlib #include #endif gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/Utility/GmmLog/spdlog/fmt/ostr.h000066400000000000000000000005221466655022700261150ustar00rootroot00000000000000// // Copyright(c) 2016 Gabi Melman. // Distributed under the MIT License (http://opensource.org/licenses/MIT) // #pragma once // include external or bundled copy of fmtlib's ostream support // #if !defined(SPDLOG_FMT_EXTERNAL) #include #include #else #include #endif gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/Utility/GmmLog/spdlog/formatter.h000066400000000000000000000016561466655022700263540ustar00rootroot00000000000000// // Copyright(c) 2015 Gabi Melman. // Distributed under the MIT License (http://opensource.org/licenses/MIT) // #pragma once #include #include #include #include namespace spdlog { namespace details { class flag_formatter; } class formatter { public: virtual ~formatter() {} virtual void format(details::log_msg& msg) = 0; }; class pattern_formatter : public formatter { public: explicit pattern_formatter(const std::string& pattern); pattern_formatter(const pattern_formatter&) = delete; pattern_formatter& operator=(const pattern_formatter&) = delete; void format(details::log_msg& msg) override; private: const std::string _pattern; std::vector> _formatters; void handle_flag(char flag); void compile_pattern(const std::string& pattern); }; } #include gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/Utility/GmmLog/spdlog/logger.h000066400000000000000000000062221466655022700256220ustar00rootroot00000000000000// // Copyright(c) 2015 Gabi Melman. // Distributed under the MIT License (http://opensource.org/licenses/MIT) // #pragma once // Thread safe logger // Has name, log level, vector of std::shared sink pointers and formatter // Upon each log write the logger: // 1. Checks if its log level is enough to log the message // 2. Format the message using the formatter function // 3. Pass the formatted message to its sinks to performa the actual logging #include #include #include #include #include namespace spdlog { class logger { public: logger(const std::string& logger_name, sink_ptr single_sink); logger(const std::string& name, sinks_init_list); template logger(const std::string& name, const It& begin, const It& end); virtual ~logger(); logger(const logger&) = delete; logger& operator=(const logger&) = delete; template void log(level::level_enum lvl, const char* fmt, const Args&... args); template void log(level::level_enum lvl, const char* msg); template void trace(const char* fmt, const Args&... args); template void debug(const char* fmt, const Args&... args); template void info(const char* fmt, const Args&... args); template void warn(const char* fmt, const Args&... args); template void error(const char* fmt, const Args&... args); template void critical(const char* fmt, const Args&... args); template void log(level::level_enum lvl, const T&); template void trace(const T&); template void debug(const T&); template void info(const T&); template void warn(const T&); template void error(const T&); template void critical(const T&); bool should_log(level::level_enum) const; void set_level(level::level_enum); level::level_enum level() const; const std::string& name() const; void set_pattern(const std::string&); void set_formatter(formatter_ptr); // error handler void set_error_handler(log_err_handler); log_err_handler error_handler(); // automatically call flush() if message level >= log_level void flush_on(level::level_enum log_level); virtual void flush(); const std::vector& sinks() const; protected: virtual void _sink_it(details::log_msg&); virtual void _set_pattern(const std::string&); virtual void _set_formatter(formatter_ptr); // default error handler: print the error to stderr with the max rate of 1 message/minute virtual void _default_err_handler(const std::string &msg); // return true if the given message level should trigger a flush bool _should_flush_on(const details::log_msg&); const std::string _name; std::vector _sinks; formatter_ptr _formatter; spdlog::level_t _level; spdlog::level_t _flush_level; log_err_handler _err_handler; std::atomic _last_err_time; }; } #include gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/Utility/GmmLog/spdlog/sinks/000077500000000000000000000000001466655022700253175ustar00rootroot00000000000000gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/Utility/GmmLog/spdlog/sinks/android_sink.h000066400000000000000000000032571466655022700301430ustar00rootroot00000000000000// // Copyright(c) 2015 Gabi Melman. // Distributed under the MIT License (http://opensource.org/licenses/MIT) // #pragma once #if defined(__ANDROID__) #include #include #include #include namespace spdlog { namespace sinks { /* * Android sink (logging using __android_log_write) * __android_log_write is thread-safe. No lock is needed. */ class android_sink : public sink { public: explicit android_sink(const std::string& tag = "spdlog"): _tag(tag) {} void log(const details::log_msg& msg) override { const android_LogPriority priority = convert_to_android(msg.level); // See system/core/liblog/logger_write.c for explanation of return value const int ret = __android_log_write( priority, _tag.c_str(), msg.formatted.c_str() ); if (ret < 0) { throw spdlog_ex("__android_log_write() failed", ret); } } void flush() override { } private: static android_LogPriority convert_to_android(spdlog::level::level_enum level) { switch(level) { case spdlog::level::trace: return ANDROID_LOG_VERBOSE; case spdlog::level::debug: return ANDROID_LOG_DEBUG; case spdlog::level::info: return ANDROID_LOG_INFO; case spdlog::level::warn: return ANDROID_LOG_WARN; case spdlog::level::err: return ANDROID_LOG_ERROR; case spdlog::level::critical: return ANDROID_LOG_FATAL; default: return ANDROID_LOG_DEFAULT; } } std::string _tag; }; } } #endif gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/Utility/GmmLog/spdlog/sinks/ansicolor_sink.h000066400000000000000000000063241466655022700305120ustar00rootroot00000000000000// // Copyright(c) 2016 Kevin M. Godby (a modified version by spdlog). // Distributed under the MIT License (http://opensource.org/licenses/MIT) // #pragma once #include #include #include #include namespace spdlog { namespace sinks { /** * @brief The ansi_color_sink is a decorator around another sink and prefixes * the output with an ANSI escape sequence color code depending on the severity * of the message. */ class ansicolor_sink : public sink { public: ansicolor_sink(sink_ptr wrapped_sink); virtual ~ansicolor_sink(); ansicolor_sink(const ansicolor_sink& other) = delete; ansicolor_sink& operator=(const ansicolor_sink& other) = delete; virtual void log(const details::log_msg& msg) override; virtual void flush() override; void set_color(level::level_enum color_level, const std::string& color); /// Formatting codes const std::string reset = "\033[00m"; const std::string bold = "\033[1m"; const std::string dark = "\033[2m"; const std::string underline = "\033[4m"; const std::string blink = "\033[5m"; const std::string reverse = "\033[7m"; const std::string concealed = "\033[8m"; // Foreground colors const std::string grey = "\033[30m"; const std::string red = "\033[31m"; const std::string green = "\033[32m"; const std::string yellow = "\033[33m"; const std::string blue = "\033[34m"; const std::string magenta = "\033[35m"; const std::string cyan = "\033[36m"; const std::string white = "\033[37m"; /// Background colors const std::string on_grey = "\033[40m"; const std::string on_red = "\033[41m"; const std::string on_green = "\033[42m"; const std::string on_yellow = "\033[43m"; const std::string on_blue = "\033[44m"; const std::string on_magenta = "\033[45m"; const std::string on_cyan = "\033[46m"; const std::string on_white = "\033[47m"; protected: sink_ptr sink_; std::map colors_; }; inline ansicolor_sink::ansicolor_sink(sink_ptr wrapped_sink) : sink_(wrapped_sink) { colors_[level::trace] = cyan; colors_[level::debug] = cyan; colors_[level::info] = bold; colors_[level::warn] = yellow + bold; colors_[level::err] = red + bold; colors_[level::critical] = bold + on_red; colors_[level::off] = reset; } inline void ansicolor_sink::log(const details::log_msg& msg) { // Wrap the originally formatted message in color codes const std::string& prefix = colors_[msg.level]; const std::string& s = msg.formatted.str(); const std::string& suffix = reset; details::log_msg m; m.level = msg.level; m.logger_name = msg.logger_name; m.time = msg.time; m.thread_id = msg.thread_id; m.formatted << prefix << s << suffix; sink_->log(m); } inline void ansicolor_sink::flush() { sink_->flush(); } inline void ansicolor_sink::set_color(level::level_enum color_level, const std::string& color) { colors_[color_level] = color; } inline ansicolor_sink::~ansicolor_sink() { flush(); } } // namespace sinks } // namespace spdlog gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/Utility/GmmLog/spdlog/sinks/base_sink.h000066400000000000000000000017141466655022700274310ustar00rootroot00000000000000// // Copyright(c) 2015 Gabi Melman. // Distributed under the MIT License (http://opensource.org/licenses/MIT) // #pragma once // // base sink templated over a mutex (either dummy or realy) // concrete implementation should only overrid the _sink_it method. // all locking is taken care of here so no locking needed by the implementers.. // #include #include #include #include #include namespace spdlog { namespace sinks { template class base_sink:public sink { public: base_sink():_mutex() {} virtual ~base_sink() = default; base_sink(const base_sink&) = delete; base_sink& operator=(const base_sink&) = delete; void log(const details::log_msg& msg) override { std::lock_guard lock(_mutex); _sink_it(msg); } protected: virtual void _sink_it(const details::log_msg& msg) = 0; Mutex _mutex; }; } } gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/Utility/GmmLog/spdlog/sinks/dist_sink.h000066400000000000000000000031721466655022700274620ustar00rootroot00000000000000// // Copyright (c) 2015 David Schury, Gabi Melman // Distributed under the MIT License (http://opensource.org/licenses/MIT) // #pragma once #include #include #include #include #include #include #include #include // Distribution sink (mux). Stores a vector of sinks which get called when log is called namespace spdlog { namespace sinks { template class dist_sink: public base_sink { public: explicit dist_sink() :_sinks() {} dist_sink(const dist_sink&) = delete; dist_sink& operator=(const dist_sink&) = delete; virtual ~dist_sink() = default; protected: std::vector> _sinks; void _sink_it(const details::log_msg& msg) override { for (auto &sink : _sinks) { if( sink->should_log( msg.level)) { sink->log(msg); } } } public: void flush() override { std::lock_guard lock(base_sink::_mutex); for (auto &sink : _sinks) sink->flush(); } void add_sink(std::shared_ptr sink) { std::lock_guard lock(base_sink::_mutex); _sinks.push_back(sink); } void remove_sink(std::shared_ptr sink) { std::lock_guard lock(base_sink::_mutex); _sinks.erase(std::remove(_sinks.begin(), _sinks.end(), sink), _sinks.end()); } }; typedef dist_sink dist_sink_mt; typedef dist_sink dist_sink_st; } } gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/Utility/GmmLog/spdlog/sinks/file_sinks.h000066400000000000000000000166751466655022700276350ustar00rootroot00000000000000// // Copyright(c) 2015 Gabi Melman. // Distributed under the MIT License (http://opensource.org/licenses/MIT) // #pragma once #include #include #include #include #include #include #include #include #include #include #include namespace spdlog { namespace sinks { /* * Trivial file sink with single file as target */ template class simple_file_sink : public base_sink < Mutex > { public: explicit simple_file_sink(const filename_t &filename, bool truncate = false):_force_flush(false) { _file_helper.open(filename, truncate); } void flush() override { _file_helper.flush(); } void set_force_flush(bool force_flush) { _force_flush = force_flush; } protected: void _sink_it(const details::log_msg& msg) override { _file_helper.write(msg); if(_force_flush) _file_helper.flush(); } private: details::file_helper _file_helper; bool _force_flush; }; typedef simple_file_sink simple_file_sink_mt; typedef simple_file_sink simple_file_sink_st; /* * Rotating file sink based on size */ template class rotating_file_sink : public base_sink < Mutex > { public: rotating_file_sink(const filename_t &base_filename, const filename_t &extension, std::size_t max_size, std::size_t max_files ) : _base_filename(base_filename), _extension(extension), _max_size(max_size), _max_files(max_files), _current_size(0), _file_helper() { _file_helper.open(calc_filename(_base_filename, 0, _extension)); _current_size = _file_helper.size(); //expensive. called only once } void flush() override { _file_helper.flush(); } protected: void _sink_it(const details::log_msg& msg) override { _current_size += msg.formatted.size(); if (_current_size > _max_size) { _rotate(); _current_size = msg.formatted.size(); } _file_helper.write(msg); } private: static filename_t calc_filename(const filename_t& filename, std::size_t index, const filename_t& extension) { std::conditional::value, fmt::MemoryWriter, fmt::WMemoryWriter>::type w; if (index) w.write(SPDLOG_FILENAME_T("{}.{}.{}"), filename, index, extension); else w.write(SPDLOG_FILENAME_T("{}.{}"), filename, extension); return w.str(); } // Rotate files: // log.txt -> log.1.txt // log.1.txt -> log2.txt // log.2.txt -> log3.txt // log.3.txt -> delete void _rotate() { using details::os::filename_to_str; _file_helper.close(); for (auto i = _max_files; i > 0; --i) { filename_t src = calc_filename(_base_filename, i - 1, _extension); filename_t target = calc_filename(_base_filename, i, _extension); if (details::file_helper::file_exists(target)) { if (details::os::remove(target) != 0) { throw spdlog_ex("rotating_file_sink: failed removing " + filename_to_str(target), errno); } } if (details::file_helper::file_exists(src) && details::os::rename(src, target)) { throw spdlog_ex("rotating_file_sink: failed renaming " + filename_to_str(src) + " to " + filename_to_str(target), errno); } } _file_helper.reopen(true); } filename_t _base_filename; filename_t _extension; std::size_t _max_size; std::size_t _max_files; std::size_t _current_size; details::file_helper _file_helper; }; typedef rotating_file_sink rotating_file_sink_mt; typedef rotating_file_sinkrotating_file_sink_st; /* * Default generator of daily log file names. */ struct default_daily_file_name_calculator { // Create filename for the form basename.YYYY-MM-DD_hh-mm.extension static filename_t calc_filename(const filename_t& basename, const filename_t& extension) { std::tm tm = spdlog::details::os::localtime(); std::conditional::value, fmt::MemoryWriter, fmt::WMemoryWriter>::type w; w.write(SPDLOG_FILENAME_T("{}_{:04d}-{:02d}-{:02d}_{:02d}-{:02d}.{}"), basename, tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, extension); return w.str(); } }; /* * Generator of daily log file names in format basename.YYYY-MM-DD.extension */ struct dateonly_daily_file_name_calculator { // Create filename for the form basename.YYYY-MM-DD.extension static filename_t calc_filename(const filename_t& basename, const filename_t& extension) { std::tm tm = spdlog::details::os::localtime(); std::conditional::value, fmt::MemoryWriter, fmt::WMemoryWriter>::type w; w.write(SPDLOG_FILENAME_T("{}_{:04d}-{:02d}-{:02d}.{}"), basename, tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, extension); return w.str(); } }; /* * Rotating file sink based on date. rotates at midnight */ template class daily_file_sink :public base_sink < Mutex > { public: //create daily file sink which rotates on given time daily_file_sink( const filename_t& base_filename, const filename_t& extension, int rotation_hour, int rotation_minute) : _base_filename(base_filename), _extension(extension), _rotation_h(rotation_hour), _rotation_m(rotation_minute) { if (rotation_hour < 0 || rotation_hour > 23 || rotation_minute < 0 || rotation_minute > 59) throw spdlog_ex("daily_file_sink: Invalid rotation time in ctor"); _rotation_tp = _next_rotation_tp(); _file_helper.open(FileNameCalc::calc_filename(_base_filename, _extension)); } void flush() override { _file_helper.flush(); } protected: void _sink_it(const details::log_msg& msg) override { if (std::chrono::system_clock::now() >= _rotation_tp) { _file_helper.open(FileNameCalc::calc_filename(_base_filename, _extension)); _rotation_tp = _next_rotation_tp(); } _file_helper.write(msg); } private: std::chrono::system_clock::time_point _next_rotation_tp() { auto now = std::chrono::system_clock::now(); time_t tnow = std::chrono::system_clock::to_time_t(now); tm date = spdlog::details::os::localtime(tnow); date.tm_hour = _rotation_h; date.tm_min = _rotation_m; date.tm_sec = 0; auto rotation_time = std::chrono::system_clock::from_time_t(std::mktime(&date)); if (rotation_time > now) return rotation_time; else return std::chrono::system_clock::time_point(rotation_time + std::chrono::hours(24)); } filename_t _base_filename; filename_t _extension; int _rotation_h; int _rotation_m; std::chrono::system_clock::time_point _rotation_tp; details::file_helper _file_helper; }; typedef daily_file_sink daily_file_sink_mt; typedef daily_file_sink daily_file_sink_st; } } gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/Utility/GmmLog/spdlog/sinks/msvc_sink.h000066400000000000000000000014141466655022700274640ustar00rootroot00000000000000// // Copyright(c) 2016 Alexander Dalshov. // Distributed under the MIT License (http://opensource.org/licenses/MIT) // #pragma once #if defined(_MSC_VER) #include #include #include #include #include namespace spdlog { namespace sinks { /* * MSVC sink (logging using OutputDebugStringA) */ template class msvc_sink : public base_sink < Mutex > { public: explicit msvc_sink() { } void flush() override { } protected: void _sink_it(const details::log_msg& msg) override { OutputDebugStringA(msg.formatted.c_str()); } }; typedef msvc_sink msvc_sink_mt; typedef msvc_sink msvc_sink_st; } } #endif gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/Utility/GmmLog/spdlog/sinks/null_sink.h000066400000000000000000000010361466655022700274660ustar00rootroot00000000000000// // Copyright(c) 2015 Gabi Melman. // Distributed under the MIT License (http://opensource.org/licenses/MIT) // #pragma once #include #include #include namespace spdlog { namespace sinks { template class null_sink : public base_sink < Mutex > { protected: void _sink_it(const details::log_msg&) override {} void flush() override {} }; typedef null_sink null_sink_st; typedef null_sink null_sink_mt; } } gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/Utility/GmmLog/spdlog/sinks/ostream_sink.h000066400000000000000000000020331466655022700301640ustar00rootroot00000000000000// // Copyright(c) 2015 Gabi Melman. // Distributed under the MIT License (http://opensource.org/licenses/MIT) // #pragma once #include #include #include #include namespace spdlog { namespace sinks { template class ostream_sink: public base_sink { public: explicit ostream_sink(std::ostream& os, bool force_flush=false) :_ostream(os), _force_flush(force_flush) {} ostream_sink(const ostream_sink&) = delete; ostream_sink& operator=(const ostream_sink&) = delete; virtual ~ostream_sink() = default; protected: void _sink_it(const details::log_msg& msg) override { _ostream.write(msg.formatted.data(), msg.formatted.size()); if (_force_flush) _ostream.flush(); } void flush() override { _ostream.flush(); } std::ostream& _ostream; bool _force_flush; }; typedef ostream_sink ostream_sink_mt; typedef ostream_sink ostream_sink_st; } } gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/Utility/GmmLog/spdlog/sinks/sink.h000066400000000000000000000016301466655022700264340ustar00rootroot00000000000000// // Copyright(c) 2015 Gabi Melman. // Distributed under the MIT License (http://opensource.org/licenses/MIT) // #pragma once #include namespace spdlog { namespace sinks { class sink { public: sink(): _level( level::trace ) {} virtual ~sink() {} virtual void log(const details::log_msg& msg) = 0; virtual void flush() = 0; bool should_log(level::level_enum msg_level) const; void set_level(level::level_enum log_level); level::level_enum level() const; private: level_t _level; }; inline bool sink::should_log(level::level_enum msg_level) const { return msg_level >= _level.load(std::memory_order_relaxed); } inline void sink::set_level(level::level_enum log_level) { _level.store(log_level); } inline level::level_enum sink::level() const { return static_cast(_level.load(std::memory_order_relaxed)); } } } gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/Utility/GmmLog/spdlog/sinks/stdout_sinks.h000066400000000000000000000030611466655022700302210ustar00rootroot00000000000000// // Copyright(c) 2015 Gabi Melman. // Distributed under the MIT License (http://opensource.org/licenses/MIT) // #pragma once #include #include #include #include #include namespace spdlog { namespace sinks { template class stdout_sink: public base_sink { using MyType = stdout_sink; public: stdout_sink() {} static std::shared_ptr instance() { static std::shared_ptr instance = std::make_shared(); return instance; } void _sink_it(const details::log_msg& msg) override { fwrite(msg.formatted.data(), sizeof(char), msg.formatted.size(), stdout); flush(); } void flush() override { fflush(stdout); } }; typedef stdout_sink stdout_sink_st; typedef stdout_sink stdout_sink_mt; template class stderr_sink: public base_sink { using MyType = stderr_sink; public: stderr_sink() {} static std::shared_ptr instance() { static std::shared_ptr instance = std::make_shared(); return instance; } void _sink_it(const details::log_msg& msg) override { fwrite(msg.formatted.data(), sizeof(char), msg.formatted.size(), stderr); flush(); } void flush() override { fflush(stderr); } }; typedef stderr_sink stderr_sink_mt; typedef stderr_sink stderr_sink_st; } } gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/Utility/GmmLog/spdlog/sinks/syslog_sink.h000066400000000000000000000037261466655022700300440ustar00rootroot00000000000000// // Copyright(c) 2015 Gabi Melman. // Distributed under the MIT License (http://opensource.org/licenses/MIT) // #pragma once #include #ifdef SPDLOG_ENABLE_SYSLOG #include #include #include #include #include namespace spdlog { namespace sinks { /** * Sink that write to syslog using the `syscall()` library call. * * Locking is not needed, as `syslog()` itself is thread-safe. */ class syslog_sink : public sink { public: // syslog_sink(const std::string& ident = "", int syslog_option=0, int syslog_facility=LOG_USER): _ident(ident) { _priorities[static_cast(level::trace)] = LOG_DEBUG; _priorities[static_cast(level::debug)] = LOG_DEBUG; _priorities[static_cast(level::info)] = LOG_INFO; _priorities[static_cast(level::warn)] = LOG_WARNING; _priorities[static_cast(level::err)] = LOG_ERR; _priorities[static_cast(level::critical)] = LOG_CRIT; _priorities[static_cast(level::off)] = LOG_INFO; //set ident to be program name if empty ::openlog(_ident.empty()? nullptr:_ident.c_str(), syslog_option, syslog_facility); } ~syslog_sink() { ::closelog(); } syslog_sink(const syslog_sink&) = delete; syslog_sink& operator=(const syslog_sink&) = delete; void log(const details::log_msg &msg) override { ::syslog(syslog_prio_from_level(msg), "%s", msg.raw.str().c_str()); } void flush() override { } private: std::array _priorities; //must store the ident because the man says openlog might use the pointer as is and not a string copy const std::string _ident; // // Simply maps spdlog's log level to syslog priority level. // int syslog_prio_from_level(const details::log_msg &msg) const { return _priorities[static_cast(msg.level)]; } }; } } #endif gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/Utility/GmmLog/spdlog/sinks/wincolor_sink.h000066400000000000000000000062271466655022700303570ustar00rootroot00000000000000// // Copyright(c) 2016 spdlog // Distributed under the MIT License (http://opensource.org/licenses/MIT) // #pragma once #include #include #include #include #include #include #include namespace spdlog { namespace sinks { /* * Windows color console sink. Uses WriteConsoleA to write to the console with colors */ template class wincolor_sink: public base_sink { public: const WORD BOLD = FOREGROUND_INTENSITY; const WORD RED = FOREGROUND_RED; const WORD CYAN = FOREGROUND_GREEN | FOREGROUND_BLUE; const WORD WHITE = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE; const WORD YELLOW = FOREGROUND_RED | FOREGROUND_GREEN; wincolor_sink(HANDLE std_handle): out_handle_(std_handle) { colors_[level::trace] = CYAN; colors_[level::debug] = CYAN; colors_[level::info] = WHITE | BOLD; colors_[level::warn] = YELLOW | BOLD; colors_[level::err] = RED | BOLD; // red bold colors_[level::critical] = BACKGROUND_RED | WHITE | BOLD; // white bold on red background colors_[level::off] = 0; } virtual ~wincolor_sink() { flush(); } wincolor_sink(const wincolor_sink& other) = delete; wincolor_sink& operator=(const wincolor_sink& other) = delete; virtual void _sink_it(const details::log_msg& msg) override { auto color = colors_[msg.level]; auto orig_attribs = set_console_attribs(color); WriteConsoleA(out_handle_, msg.formatted.data(), static_cast(msg.formatted.size()), nullptr, nullptr); SetConsoleTextAttribute(out_handle_, orig_attribs); //reset to orig colors } virtual void flush() override { // windows console always flushed? } // change the color for the given level void set_color(level::level_enum level, WORD color) { std::lock_guard lock(_mutex); colors_[level] = color; } private: HANDLE out_handle_; std::map colors_; // set color and return the orig console attributes (for resetting later) WORD set_console_attribs(WORD attribs) { CONSOLE_SCREEN_BUFFER_INFO orig_buffer_info; GetConsoleScreenBufferInfo(out_handle_, &orig_buffer_info); SetConsoleTextAttribute(out_handle_, attribs); return orig_buffer_info.wAttributes; //return orig attribs } }; // // windows color console to stdout // template class wincolor_stdout_sink: public wincolor_sink { public: wincolor_stdout_sink():wincolor_sink(GetStdHandle(STD_OUTPUT_HANDLE)) {} }; typedef wincolor_stdout_sink wincolor_stdout_sink_mt; typedef wincolor_stdout_sink wincolor_stdout_sink_st; // // windows color console to stderr // template class wincolor_stderr_sink: public wincolor_sink { public: wincolor_stderr_sink():wincolor_sink(GetStdHandle(STD_ERROR_HANDLE)) {} }; typedef wincolor_stderr_sink wincolor_stderr_sink_mt; typedef wincolor_stderr_sink wincolor_stderr_sink_st; } } gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/Utility/GmmLog/spdlog/spdlog.h000066400000000000000000000145261466655022700256410ustar00rootroot00000000000000// // Copyright(c) 2015 Gabi Melman. // Distributed under the MIT License (http://opensource.org/licenses/MIT) // // spdlog main header file. // see example.cpp for usage example #pragma once #include #include #include #include #include #include #include namespace spdlog { // // Return an existing logger or nullptr if a logger with such name doesn't exist. // example: spdlog::get("my_logger")->info("hello {}", "world"); // std::shared_ptr get(const std::string& name); // // Set global formatting // example: spdlog::set_pattern("%Y-%m-%d %H:%M:%S.%e %l : %v"); // void set_pattern(const std::string& format_string); void set_formatter(formatter_ptr f); // // Set global logging level for // void set_level(level::level_enum log_level); // // Set global error handler // void set_error_handler(log_err_handler); // // Turn on async mode (off by default) and set the queue size for each async_logger. // effective only for loggers created after this call. // queue_size: size of queue (must be power of 2): // Each logger will pre-allocate a dedicated queue with queue_size entries upon construction. // // async_overflow_policy (optional, block_retry by default): // async_overflow_policy::block_retry - if queue is full, block until queue has room for the new log entry. // async_overflow_policy::discard_log_msg - never block and discard any new messages when queue overflows. // // worker_warmup_cb (optional): // callback function that will be called in worker thread upon start (can be used to init stuff like thread affinity) // // worker_teardown_cb (optional): // callback function that will be called in worker thread upon exit // void set_async_mode(size_t queue_size, const async_overflow_policy overflow_policy = async_overflow_policy::block_retry, const std::function& worker_warmup_cb = nullptr, const std::chrono::milliseconds& flush_interval_ms = std::chrono::milliseconds::zero(), const std::function& worker_teardown_cb = nullptr); // Turn off async mode void set_sync_mode(); // // Create and register multi/single threaded basic file logger. // Basic logger simply writes to given file without any limitatons or rotations. // std::shared_ptr basic_logger_mt(const std::string& logger_name, const filename_t& filename, bool truncate = false); std::shared_ptr basic_logger_st(const std::string& logger_name, const filename_t& filename, bool truncate = false); // // Create and register multi/single threaded rotating file logger // std::shared_ptr rotating_logger_mt(const std::string& logger_name, const filename_t& filename, size_t max_file_size, size_t max_files); std::shared_ptr rotating_logger_st(const std::string& logger_name, const filename_t& filename, size_t max_file_size, size_t max_files); // // Create file logger which creates new file on the given time (default in midnight): // std::shared_ptr daily_logger_mt(const std::string& logger_name, const filename_t& filename, int hour=0, int minute=0); std::shared_ptr daily_logger_st(const std::string& logger_name, const filename_t& filename, int hour=0, int minute=0); // // Create and register stdout/stderr loggers // std::shared_ptr stdout_logger_mt(const std::string& logger_name); std::shared_ptr stdout_logger_st(const std::string& logger_name); std::shared_ptr stderr_logger_mt(const std::string& logger_name); std::shared_ptr stderr_logger_st(const std::string& logger_name); // // Create and register colored stdout/stderr loggers // std::shared_ptr stdout_color_mt(const std::string& logger_name); std::shared_ptr stdout_color_st(const std::string& logger_name); std::shared_ptr stderr_color_mt(const std::string& logger_name); std::shared_ptr stderr_color_st(const std::string& logger_name); // // Create and register a syslog logger // #ifdef SPDLOG_ENABLE_SYSLOG std::shared_ptr syslog_logger(const std::string& logger_name, const std::string& ident = "", int syslog_option = 0); #endif #if defined(__ANDROID__) std::shared_ptr android_logger(const std::string& logger_name, const std::string& tag = "spdlog"); #endif // Create and register a logger a single sink std::shared_ptr create(const std::string& logger_name, const sink_ptr& sink); // Create and register a logger with multiple sinks std::shared_ptr create(const std::string& logger_name, sinks_init_list sinks); template std::shared_ptr create(const std::string& logger_name, const It& sinks_begin, const It& sinks_end); // Create and register a logger with templated sink type // Example: // spdlog::create("mylog", "dailylog_filename", "txt"); template std::shared_ptr create(const std::string& logger_name, Args...); // Register the given logger with the given name void register_logger(std::shared_ptr logger); // Apply a user defined function on all registered loggers // Example: // spdlog::apply_all([&](std::shared_ptr l) {l->flush();}); void apply_all(std::function)> fun); // Drop the reference to the given logger void drop(const std::string &name); // Drop all references from the registry void drop_all(); /////////////////////////////////////////////////////////////////////////////// // // Trace & Debug can be switched on/off at compile time for zero cost debug statements. // Uncomment SPDLOG_DEBUG_ON/SPDLOG_TRACE_ON in teakme.h to enable. // SPDLOG_TRACE(..) will also print current file and line. // // Example: // spdlog::set_level(spdlog::level::trace); // SPDLOG_TRACE(my_logger, "some trace message"); // SPDLOG_TRACE(my_logger, "another trace message {} {}", 1, 2); // SPDLOG_DEBUG(my_logger, "some debug message {} {}", 3, 4); /////////////////////////////////////////////////////////////////////////////// #ifdef SPDLOG_TRACE_ON #define SPDLOG_STR_H(x) #x #define SPDLOG_STR_HELPER(x) SPDLOG_STR_H(x) #define SPDLOG_TRACE(logger, ...) logger->trace("[" __FILE__ " line #" SPDLOG_STR_HELPER(__LINE__) "] " __VA_ARGS__) #else #define SPDLOG_TRACE(logger, ...) #endif #ifdef SPDLOG_DEBUG_ON #define SPDLOG_DEBUG(logger, ...) logger->debug(__VA_ARGS__) #else #define SPDLOG_DEBUG(logger, ...) #endif } #include gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/Utility/GmmLog/spdlog/tweakme.h000066400000000000000000000104151466655022700257770ustar00rootroot00000000000000// // Copyright(c) 2015 Gabi Melman. // Distributed under the MIT License (http://opensource.org/licenses/MIT) // #pragma once /////////////////////////////////////////////////////////////////////////////// // // Edit this file to squeeze more performance, and to customize supported features // /////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// // Under Linux, the much faster CLOCK_REALTIME_COARSE clock can be used. // This clock is less accurate - can be off by dozens of millis - depending on the kernel HZ. // Uncomment to use it instead of the regular clock. // // #define SPDLOG_CLOCK_COARSE /////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// // Uncomment if date/time logging is not needed and never appear in the log pattern. // This will prevent spdlog from quering the clock on each log call. // // WARNING: If the log pattern contains any date/time while this flag is on, the result is undefined. // You must set new pattern(spdlog::set_pattern(..") without any date/time in it // // #define SPDLOG_NO_DATETIME /////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// // Uncomment if thread id logging is not needed (i.e. no %t in the log pattern). // This will prevent spdlog from quering the thread id on each log call. // // WARNING: If the log pattern contains thread id (i.e, %t) while this flag is on, the result is undefined. // // #define SPDLOG_NO_THREAD_ID /////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// // Uncomment if logger name logging is not needed. // This will prevent spdlog from copying the logger name on each log call. // #define SPDLOG_NO_NAME /////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// // Uncomment to enable the SPDLOG_DEBUG/SPDLOG_TRACE macros. // // #define SPDLOG_DEBUG_ON // #define SPDLOG_TRACE_ON /////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// // Uncomment to avoid locking in the registry operations (spdlog::get(), spdlog::drop() spdlog::register()). // Use only if your code never modifes concurrently the registry. // Note that upon creating a logger the registry is modified by spdlog.. // // #define SPDLOG_NO_REGISTRY_MUTEX /////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// // Uncomment to avoid spdlog's usage of atomic log levels // Use only if your code never modifies a logger's log levels concurrently by different threads. // // #define SPDLOG_NO_ATOMIC_LEVELS /////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// // Uncomment to enable usage of wchar_t for file names on Windows. // // #define SPDLOG_WCHAR_FILENAMES /////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// // Uncomment to override default eol ("\n" or "\r\n" under Linux/Windows) // // #define SPDLOG_EOL ";-)\n" /////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// // Uncomment to use your own copy of the fmt library instead of spdlog's copy. // In this case spdlog will try to include so set your -I flag accordingly. // // #define SPDLOG_FMT_EXTERNAL /////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// // Uncomment to enable syslog (disabled by default) // #if __linux__ #define SPDLOG_ENABLE_SYSLOG #endif /////////////////////////////////////////////////////////////////////////////// gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/Utility/GmmUtility.cpp000066400000000000000000000557211466655022700243400ustar00rootroot00000000000000/*============================================================================== Copyright(c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ============================================================================*/ #include "Internal/Common/GmmLibInc.h" #ifdef _WIN32 #include #endif //64KB Undefined Swizzle Descriptors ######################################### // !! TODO (critical): Provide mapping helper function to UMD to map in non-TR // Undefined64KBSwizzle resources. Also check if support // for it is needed in GmmResCpuBlt. // // Note: These 64KB swizzles are not really hardware tile swizzles, so leave // them out of the CpuSwizzleBlt.c /* On systems that do not support Std Swizzle (IGFX_GEN7_5_CORE / IGFX_GEN8_CORE), we still have to support 64KB tiles. These 64KB tiles will be made of 16 4KB tiles -- we'll be using TileY to create these 64KB tiles. The table below shows how the 64KB tile shape changes depending on the bpp and how we need to arrange (in columns X rows) the 4KB tiles to fit that shape. bpp Tile Size (in pixels) Tile Size (in bytes) 4K tile config --- -------------------- -------------------- -------------- 8bpp 256x256 256x256 2x8 16bpp 256x128 512x128 4x4 32bpp 128x128 512x128 4x4 64bpp 128x64 1024x64 8x2 128bpp 64x64 1024x64 8x2 We need 3 different swizzle pattern to support all configs above. The swizzle patterns are: |-Rows-| |-Column-| |-TileY Swizzle-| 8bpp: YYY X XXXYYYYYXXXX 16/32bpp: YY XX XXXYYYYYXXXX 64/128bpp: Y XXX XXXYYYYYXXXX The translation of these Xs and Ys to bitmap is shown below */ extern const SWIZZLE_DESCRIPTOR INTEL_64KB_UNDEFINED_8bpp = {0x1E0F, 0xE1F0, 0}; extern const SWIZZLE_DESCRIPTOR INTEL_64KB_UNDEFINED_16_32bpp = {0x3E0F, 0xC1F0, 0}; extern const SWIZZLE_DESCRIPTOR INTEL_64KB_UNDEFINED_64_128bpp = {0x7E0F, 0x81F0, 0}; //############################################################################# //============================================================================= // Function: // GmmIsRedecribedPlanes // // Description: // Checks if the resource has redescribed planes // // Arguments: GetResFlags().Info.RedecribedPlanes; } //============================================================================= // Function: // GmmGetLosslessCompressionType // // Description: // Returns the format's E2E compression format. // // Arguments: GMM_FORMAT_INVALID) && (Format < GMM_RESOURCE_FORMATS)); return pGmmLibContext->GetPlatformInfo().FormatTable[Format].CompressionFormat.AuxL1eFormat; } //============================================================================= // Function: // GmmIsUVPacked // // Description: // Checks if format has packed UV plane // // Arguments: GMM_FORMAT_INVALID) && (Format < GMM_RESOURCE_FORMATS) && pGmmLibContext->GetPlatformInfo().FormatTable[Format].Compressed; } //============================================================================= // Function: // GmmGetCacheSizes // // Description: // This function returns the L3, LLC and EDRAM cache sizes. // // Arguments: // pCacheSizes ==> ptr to GMM_CACHE_SIZES struct // // Return: // void // //----------------------------------------------------------------------------- void GMM_STDCALL GmmGetCacheSizes(GMM_LIB_CONTEXT *pGmmLibContext, GMM_CACHE_SIZES *pCacheSizes) { const GT_SYSTEM_INFO *pGtSysInfo; __GMM_ASSERT(pCacheSizes != NULL); __GMM_ASSERT(pGmmLibContext != NULL); GMM_DPF_ENTER; pGtSysInfo = pGmmLibContext->GetGtSysInfoPtr(); pCacheSizes->TotalEDRAM = GMM_KBYTE(pGtSysInfo->EdramSizeInKb); pCacheSizes->TotalLLCCache = GMM_KBYTE(pGtSysInfo->LLCCacheSizeInKb); pCacheSizes->TotalL3Cache = GMM_KBYTE(pGtSysInfo->L3CacheSizeInKb); GMM_DPF_EXIT; } namespace GmmLib { namespace Utility { //============================================================================= // Function: // GmmGetNumPlanes // // Description: // Returns number of planes for given format // // Arguments: Must be power of 2 // // Returns: // See desc. // Example Value = 8 => Log2(Value) = 3 // Example Value = 32 => Log2(Value) = 5 //----------------------------------------------------------------------------- uint32_t __GmmLog2(uint32_t Value) { uint32_t FirstSetBit = 0; // bit # of first set bit in Bpp. #if _MSC_VER // Check that Value is pow2 __GMM_ASSERT(__popcnt(Value) <= 1); _BitScanReverse((DWORD *)&FirstSetBit, (DWORD)Value); #else // Check that Value is pow2 __GMM_ASSERT(__builtin_popcount(Value) <= 1); FirstSetBit = __builtin_ctz(Value); #endif // Log2(Value) = FirstSetBit. return FirstSetBit; }; // Table for converting the tile layout of DirectX tiled resources // to TileY. const uint32_t __GmmTileYConversionTable[5][2] = { //WxH 256x256, of 64KB tile in texels, BPP = 8 {2, 8}, // = (W * (BPP >> 3)) / 128, H / 32 //WxH 256x128, BPP = 16 {4, 4}, //WxH 128x128, BPP = 32 {4, 4}, //WxH 128x64, BPP = 64 {8, 2}, //WxH 64x64, BPP = 128 {8, 2}}; // With MSAA, modify DirectX tile dimensions // MSAA Divide Tile Dimensions (WxH) by // 1 1x1 // 2 2x1 // 4 2x2 // 8 4x2 //16 4x4 const uint32_t __GmmMSAAConversion[5][2] = { // MSAA 1x {1, 1}, // MSAA 2x {2, 1}, // MSAA 4x {2, 2}, // MSAA 8x {4, 2}, // MSAA 16x {4, 4}}; gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/Utility/GmmUtility.h000066400000000000000000000050211466655022700237710ustar00rootroot00000000000000/*============================================================================== Copyright(c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ============================================================================*/ #pragma once #if __cplusplus namespace GmmLib { namespace Utility { uint32_t GMM_STDCALL GmmGetNumPlanes(GMM_RESOURCE_FORMAT Format); GMM_RESOURCE_FORMAT GMM_STDCALL GmmGetFormatForASTC(uint8_t HDR, uint8_t Float, uint32_t BlockWidth, uint32_t BlockHeight, uint32_t BlockDepth); } } #endif #ifndef __GMM_KMD__ #define GMM_MALLOC(size) malloc(size) #define GMM_FREE(p) free(p) #define GMM_COMPR_FORMAT_INVALID(pGmmLibContext) \ ((pGmmLibContext->GetSkuTable().FtrXe2Compression != 0) ? static_cast(GMM_XE2_UNIFIED_COMP_FORMAT_INVALID) : \ (pGmmLibContext->GetSkuTable().FtrFlatPhysCCS != 0) ? static_cast(GMM_FLATCCS_FORMAT_INVALID) : \ static_cast(GMM_E2ECOMP_FORMAT_INVALID)) #else #define GMM_COMPR_FORMAT_INVALID GMM_E2ECOMP_FORMAT_INVALID #endif void GMM_STDCALL GmmGetCacheSizes(GMM_CACHE_SIZES* pCacheSizes); /* Internal functions */ uint32_t __GmmLog2(uint32_t Value); gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/igdgmm.h.in000066400000000000000000000024041466655022700220750ustar00rootroot00000000000000/* * Copyright (c) 2018, Intel Corporation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ #ifndef IGDGMM_H #define IGDGMM_H #cmakedefine GMM_UMD_DLL "${CMAKE_SHARED_LIBRARY_PREFIX}${GMM_UMD_DLL}${CMAKE_SHARED_LIBRARY_SUFFIX}" #endif /* IGDGMM_H */ gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/igdgmm.pc.in000066400000000000000000000006771466655022700222620ustar00rootroot00000000000000prefix=@CMAKE_INSTALL_PREFIX@ execprefix=${prefix} includedir=@CMAKE_INSTALL_FULL_INCLUDEDIR@/igdgmm libdir=@CMAKE_INSTALL_FULL_LIBDIR@ Name: igdgmm Description: Intel(R) Graphics Memory Management Library Version: @MAJOR_VERSION@.@MINOR_VERSION@.@PATCH_VERSION@ Cflags: -DGMM_LIB_DLL -I${includedir} -I${includedir}/GmmLib -I${includedir}/GmmLib/inc -I${includedir}/inc -I${includedir}/inc/common -I${includedir}/util Libs: -L${libdir} -ligdgmm gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/igdgmm.rc000077500000000000000000000035331466655022700216540ustar00rootroot00000000000000/*============================================================================== Copyright(c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. File Name: igdgmm.rc Abstract: Notes: ============================================================================*/ #ifdef _WIN32 #include #include <..\..\..\install\intcver.h> #endif #define VER_FILETYPE VFT_DLL #define VER_FILESUBTYPE VFT2_DRV_INSTALLABLE #define VER_FILEOS VOS_NT_WINDOWS32 #define VER_FILEDESCRIPTION "User Mode Driver for Intel(R) Graphics Technology\0" #ifdef _WIN64 #define VER_INTERNALNAME "igdgmm64.dll" #define VER_ORIGINALNAME "igdgmm64.dll" #else #define VER_INTERNALNAME "igdgmm32.dll" #define VER_ORIGINALNAME "igdgmm32.dll" #endif #ifdef _WIN32 #include <..\..\..\inc\verinfo.ver> #endif gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/inc/000077500000000000000000000000001466655022700206245ustar00rootroot00000000000000gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/inc/External/000077500000000000000000000000001466655022700224065ustar00rootroot00000000000000gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/inc/External/Common/000077500000000000000000000000001466655022700236365ustar00rootroot00000000000000gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/inc/External/Common/CachePolicy/000077500000000000000000000000001466655022700260215ustar00rootroot00000000000000gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/inc/External/Common/CachePolicy/GmmCachePolicyGen10.h000066400000000000000000000037711466655022700316210ustar00rootroot00000000000000/*============================================================================== Copyright(c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ============================================================================*/ #pragma once #ifdef __cplusplus #include "../GmmCachePolicyCommon.h" namespace GmmLib { class NON_PAGED_SECTION GmmGen10CachePolicy : public GmmGen9CachePolicy { protected: /* Function prototypes */ uint32_t BestMatchingPATIdx(GMM_CACHE_POLICY_ELEMENT CachePolicy); public: /* Constructors */ GmmGen10CachePolicy(GMM_CACHE_POLICY_ELEMENT *pCachePolicy, Context *pGmmLibContext) : GmmGen9CachePolicy(pCachePolicy, pGmmLibContext) { } virtual ~GmmGen10CachePolicy() { } /* Function prototypes */ GMM_STATUS InitCachePolicy(); GMM_STATUS SetPATInitWA(); GMM_STATUS SetupPAT(); }; } #endif // #ifdef __cplusplus gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/inc/External/Common/CachePolicy/GmmCachePolicyGen11.h000066400000000000000000000042021466655022700316100ustar00rootroot00000000000000/*============================================================================== Copyright(c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ============================================================================*/ #pragma once #ifdef __cplusplus #include "../GmmCachePolicyCommon.h" namespace GmmLib { class NON_PAGED_SECTION GmmGen11CachePolicy : public GmmGen10CachePolicy { public: uint32_t CurrentMaxSpecialMocsIndex; /* Constructors */ GmmGen11CachePolicy(GMM_CACHE_POLICY_ELEMENT *pCachePolicy, Context *pGmmLibContext) : GmmGen10CachePolicy(pCachePolicy, pGmmLibContext) { CurrentMaxSpecialMocsIndex = 0; } virtual ~GmmGen11CachePolicy() { } virtual uint32_t GetMaxSpecialMocsIndex() { return CurrentMaxSpecialMocsIndex; } int32_t IsSpecialMOCSUsage(GMM_RESOURCE_USAGE_TYPE Usage, bool &UpdateMOCS); /* Function prototypes */ GMM_STATUS InitCachePolicy(); void SetUpMOCSTable(); }; } #endif // #ifdef __cplusplus gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/inc/External/Common/CachePolicy/GmmCachePolicyGen12.h000066400000000000000000000052201466655022700316120ustar00rootroot00000000000000/*============================================================================== Copyright(c) 2019 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ============================================================================*/ #pragma once #ifdef __cplusplus #include "../GmmCachePolicyCommon.h" #define GMM_GEN12_MAX_NUMBER_MOCS_INDEXES (60) // On TGL last four (#60-#63) are reserved by h/w, few? are sw configurable though (#60) namespace GmmLib { class NON_PAGED_SECTION GmmGen12CachePolicy : public GmmGen11CachePolicy { public: /* Constructors */ GmmGen12CachePolicy(GMM_CACHE_POLICY_ELEMENT *pCachePolicyContext, Context *pGmmLibContext) : GmmGen11CachePolicy(pCachePolicyContext, pGmmLibContext) { #if(defined(__GMM_KMD__)) { // Set the WA's needed for Private PAT initialization SetPATInitWA(); SetupPAT(); } #endif } virtual ~GmmGen12CachePolicy() { } virtual uint32_t GetMaxSpecialMocsIndex() { return CurrentMaxSpecialMocsIndex; } int32_t IsSpecialMOCSUsage(GMM_RESOURCE_USAGE_TYPE Usage, bool& UpdateMOCS); /* Function prototypes */ GMM_STATUS InitCachePolicy(); uint8_t SelectNewPATIdx(GMM_GFX_MEMORY_TYPE WantedMT, GMM_GFX_MEMORY_TYPE MT1, GMM_GFX_MEMORY_TYPE MT2); uint32_t BestMatchingPATIdx(GMM_CACHE_POLICY_ELEMENT CachePolicy); GMM_STATUS SetPATInitWA(); GMM_STATUS SetupPAT(); void SetUpMOCSTable(); }; } #endif // #ifdef __cplusplus gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/inc/External/Common/CachePolicy/GmmCachePolicyGen12dGPU.h000066400000000000000000000044601466655022700323370ustar00rootroot00000000000000/*============================================================================== Copyright(c) 2020 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ============================================================================*/ #pragma once #ifdef __cplusplus #include "../GmmCachePolicyCommon.h" #define GMM_NUM_PAT_ENTRIES_Xe_HPC (8) namespace GmmLib { class NON_PAGED_SECTION GmmGen12dGPUCachePolicy : public GmmGen12CachePolicy { protected: uint32_t CurrentMaxPATIndex; public: /* Constructors */ GmmGen12dGPUCachePolicy(GMM_CACHE_POLICY_ELEMENT *pCachePolicy, Context *pGmmLibContext) : GmmGen12CachePolicy(pCachePolicy, pGmmLibContext) { NumPATRegisters = GMM_NUM_PAT_ENTRIES_Xe_HPC; CurrentMaxPATIndex = 0; } virtual ~GmmGen12dGPUCachePolicy() { } /* Function prototypes */ GMM_STATUS InitCachePolicy(); void SetUpMOCSTable(); int32_t IsSpecialMOCSUsage(GMM_RESOURCE_USAGE_TYPE Usage, bool& UpdateMOCS); GMM_STATUS SetupPAT(); uint32_t GMM_STDCALL CachePolicyGetPATIndex(GMM_RESOURCE_INFO *pResInfo, GMM_RESOURCE_USAGE_TYPE Usage, bool *pCompressionEnable, bool IsCpuCacheable); }; } #endif // #ifdef __cplusplus gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/inc/External/Common/CachePolicy/GmmCachePolicyGen8.h000066400000000000000000000061361466655022700315460ustar00rootroot00000000000000/*============================================================================== Copyright(c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ============================================================================*/ #pragma once #ifdef __cplusplus #include "../GmmCachePolicyCommon.h" namespace GmmLib { class NON_PAGED_SECTION GmmGen8CachePolicy : public GmmCachePolicyCommon { protected: /* Function prototypes */ GMM_PRIVATE_PAT GetPrivatePATEntry(uint32_t PATIdx); bool SetPrivatePATEntry(uint32_t PATIdx, GMM_PRIVATE_PAT Entry); bool SelectNewPATIdx(GMM_GFX_MEMORY_TYPE WantedMT, GMM_GFX_TARGET_CACHE WantedTC, GMM_GFX_MEMORY_TYPE MT1, GMM_GFX_TARGET_CACHE TC1, GMM_GFX_MEMORY_TYPE MT2, GMM_GFX_TARGET_CACHE TC2); bool GetUsagePTEValue(GMM_CACHE_POLICY_ELEMENT CachePolicy, uint32_t Usage, uint64_t *pPTEDwordValue); /* Virtual function prototypes */ virtual uint32_t BestMatchingPATIdx(GMM_CACHE_POLICY_ELEMENT CachePolicy); public: /* Constructors */ GmmGen8CachePolicy(GMM_CACHE_POLICY_ELEMENT *pCachePolicyContext, Context *pGmmLibContext) : GmmCachePolicyCommon(pCachePolicyContext, pGmmLibContext) { #if(defined(__GMM_KMD__)) //if (GFX_IS_SKU(pGmmLibContext, FtrIA32eGfxPTEs)) { // Set the WA's needed for Private PAT initialization SetPATInitWA(); SetupPAT(); } #endif } virtual ~GmmGen8CachePolicy() { } /* Function prototypes */ GMM_STATUS InitCachePolicy(); GMM_STATUS SetPATInitWA(); GMM_STATUS SetupPAT(); uint8_t GMM_STDCALL CachePolicyIsUsagePTECached(GMM_RESOURCE_USAGE_TYPE Usage); }; } #endif // #ifdef __cplusplus gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/inc/External/Common/CachePolicy/GmmCachePolicyGen9.h000066400000000000000000000037441466655022700315510ustar00rootroot00000000000000/*============================================================================== Copyright(c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ============================================================================*/ #pragma once #ifdef __cplusplus #include "../GmmCachePolicyCommon.h" namespace GmmLib { class NON_PAGED_SECTION GmmGen9CachePolicy : public GmmGen8CachePolicy { public: uint32_t CurrentMaxMocsIndex; uint32_t CurrentMaxL1HdcMocsIndex; /* Constructors */ GmmGen9CachePolicy(GMM_CACHE_POLICY_ELEMENT *pCachePolicy, Context *pGmmLibContext) : GmmGen8CachePolicy(pCachePolicy, pGmmLibContext) { CurrentMaxMocsIndex = 0; CurrentMaxL1HdcMocsIndex = 0; } virtual ~GmmGen9CachePolicy() { } /* Function prototypes */ GMM_STATUS InitCachePolicy(); GMM_STATUS SetupPAT(); }; } #endif // #ifdef __cplusplus gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/inc/External/Common/CachePolicy/GmmCachePolicyXe2_LPG.h000066400000000000000000000071661466655022700321110ustar00rootroot00000000000000/*============================================================================== Copyright(c) 2024 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ============================================================================*/ #pragma once #ifdef __cplusplus #include "../GmmCachePolicyCommon.h" #define GMM_XE2_NUM_MOCS_ENTRIES (16) #define GMM_XE2_DEFAULT_PAT_INDEX (PAT2) #ifdef __cplusplus extern "C" { #endif /*__cplusplus*/ typedef enum GMM_GFX_PHY_L4_MEMORY_TYPE_REC { GMM_GFX_PHY_L4_MT_WB = 0x0, GMM_GFX_PHY_L4_MT_WT = 0x1, GMM_GFX_PHY_L4_MT_UC = 0x3, } GMM_GFX_PHY_L4_MEMORY_TYPE; typedef enum GMM_GFX_PHY_L3_MEMORY_TYPE_REC { GMM_GFX_PHY_L3_MT_WB = 0x0, GMM_GFX_PHY_L3_MT_WB_XD = 0x1, // Transient Flush Display GMM_GFX_PHY_L3_MT_UC = 0x3, } GMM_GFX_PHY_L3_MEMORY_TYPE; typedef enum GMM_GFX_PHY_CACHE_COHERENCY_TYPE_REC { GMM_GFX_PHY_NON_COHERENT_NO_SNOOP = 0x0, GMM_GFX_PHY_NON_COHERENT = 0x1, GMM_GFX_PHY_COHERENT_ONE_WAY_IA_SNOOP = 0x2, GMM_GFX_PHY_COHERENT_TWO_WAY_IA_GPU_SNOOP = 0x3 } GMM_GFX_PHY_CACHE_COHERENCY_TYPE; typedef union GMM_XE2_PRIVATE_PAT_REC { struct { uint32_t Coherency : 2; uint32_t L4CC : 2; uint32_t L3CC : 2; uint32_t L3CLOS : 2; uint32_t Reserved1 : 1; uint32_t LosslessCompressionEn: 1; uint32_t Reserved2 : 22; } Xe2; uint32_t Value; } GMM_XE2_PRIVATE_PAT; namespace GmmLib { class NON_PAGED_SECTION GmmXe2_LPGCachePolicy : public GmmXe_LPGCachePolicy { protected: public: /* Constructors */ GmmXe2_LPGCachePolicy(GMM_CACHE_POLICY_ELEMENT *pCachePolicyContext, Context *pGmmLibContext) : GmmXe_LPGCachePolicy(pCachePolicyContext, pGmmLibContext) { NumPATRegisters = GMM_NUM_PAT_ENTRIES; NumMOCSRegisters = GMM_XE2_NUM_MOCS_ENTRIES; CurrentMaxPATIndex = 0; CurrentMaxMocsIndex = 0; } virtual ~GmmXe2_LPGCachePolicy() { } /* Function prototypes */ GMM_STATUS InitCachePolicy(); GMM_STATUS SetupPAT(); void SetUpMOCSTable(); void GetL3L4(GMM_CACHE_POLICY_TBL_ELEMENT *pUsageEle, GMM_XE2_PRIVATE_PAT *pUsagePATElement, uint32_t Usage); uint32_t GMM_STDCALL CachePolicyGetPATIndex(GMM_RESOURCE_INFO *pResInfo, GMM_RESOURCE_USAGE_TYPE Usage, bool *pCompressionEnable, bool IsCpuCacheable); }; } // namespace GmmLib #endif // #ifdef __cplusplus #ifdef __cplusplus } #endif /* end__cplusplus*/ gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/inc/External/Common/CachePolicy/GmmCachePolicyXe_LPG.h000066400000000000000000000051601466655022700320170ustar00rootroot00000000000000/*============================================================================== Copyright(c) 2022 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ============================================================================*/ #pragma once #ifdef __cplusplus #include "../GmmCachePolicyCommon.h" #define GMM_NUM_PAT_ENTRIES_Xe_LPG (16) namespace GmmLib { class NON_PAGED_SECTION GmmXe_LPGCachePolicy : public GmmGen12CachePolicy { protected: uint32_t CurrentMaxPATIndex; public: /* Constructors */ GmmXe_LPGCachePolicy(GMM_CACHE_POLICY_ELEMENT *pCachePolicyContext, Context *pGmmLibContext) : GmmGen12CachePolicy(pCachePolicyContext, pGmmLibContext) { NumPATRegisters = GMM_NUM_PAT_ENTRIES_Xe_LPG; CurrentMaxPATIndex = 0; } virtual ~GmmXe_LPGCachePolicy() { } /* Function prototypes */ GMM_STATUS InitCachePolicy(); uint32_t GMM_STDCALL CachePolicyGetPATIndex(GMM_RESOURCE_INFO *pResInfo, GMM_RESOURCE_USAGE_TYPE Usage, bool *pCompressionEnable, bool IsCpuCacheable); GMM_STATUS SetupPAT(); void SetUpMOCSTable(); void GMM_STDCALL SetL1CachePolicy(uint32_t Usage); virtual uint32_t GMM_STDCALL GetSurfaceStateL1CachePolicy(GMM_RESOURCE_USAGE_TYPE Usage); virtual MEMORY_OBJECT_CONTROL_STATE GMM_STDCALL CachePolicyGetMemoryObject(GMM_RESOURCE_INFO *pResInfo, GMM_RESOURCE_USAGE_TYPE Usage); }; } #endif // #ifdef __cplusplus gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/inc/External/Common/GmmCachePolicy.h000066400000000000000000000600101466655022700266300ustar00rootroot00000000000000/*============================================================================== Copyright(c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ============================================================================*/ #pragma once #ifdef __cplusplus extern "C" { #endif #include "GmmCachePolicyExt.h" #define ALWAYS_OVERRIDE 0xffffffff #define NEVER_OVERRIDE 0x0 // IA PAT MSR Register #define GMM_IA32e_PAT_MSR 0x277 #define GMM_PAT_ERROR ((uint32_t)-1) typedef struct GMM_CACHE_POLICY_ELEMENT_REC { uint32_t IDCode; union { struct{ uint64_t LLC : 1; uint64_t ELLC : 1; uint64_t L3 : 1; uint64_t WT : 1; uint64_t AGE : 2; uint64_t AOM : 1; uint64_t LeCC_SCC : 3; uint64_t L3_SCC : 3; uint64_t SCF : 1; // Snoop Control Field for BXT uint64_t CoS : 2; // Class of Service, driver default to Class 0 uint64_t SSO : 2; // Self Snoop Override control and value uint64_t HDCL1 : 1; // HDC L1 caching enable/disable uint64_t L3Eviction : 2; // Specify L3-eviction type (NA, ReadOnly, Standard, Special) uint64_t SegOv : 3; // Override seg-pref (none, local-only, sys-only, etc) uint64_t GlbGo : 1; // Global GO point - L3 or Memory uint64_t UcLookup : 1; // Snoop L3 for uncached uint64_t L1CC : 3; // L1 Cache Control uint64_t Initialized : 1; uint64_t L2CC : 2; // media internal cache 0:UC, 1:WB uint64_t L4CC : 2; // L4 memory cache 0: UC, 1:WB, 2: WT uint64_t Coherency : 2; // 0 non-coh, 1: 1 way coh IA snoop 2: 2 way coh IA GPU snopp uint64_t CoherentPATIndex : 5; uint64_t CoherentPATIndexHigherBit : 1; // From Xe2 onwards it requires 6 bit to represent PATIndex. Hence using this single bit (MSB) as extension of the above field CoherentPATIndex:5 uint64_t PATIndexCompressed : 6; uint64_t L3CC : 2; // 0:UC, 1:WB 2:WB_T_Display, 3:WB_T_App uint64_t L3CLOS : 2; // Class of service uint64_t IgnorePAT : 1; // Ignore PAT 1 = Override by MOCS, 0 = Defer to PAT uint64_t Reserved : 11; }; uint64_t Value; }; MEMORY_OBJECT_CONTROL_STATE MemoryObjectOverride; union { MEMORY_OBJECT_CONTROL_STATE MemoryObjectNoOverride; uint32_t PATIndex; }; GMM_PTE_CACHE_CONTROL_BITS PTE; uint32_t Override; uint32_t IsOverridenByRegkey; // Flag to indicate If usage settings are overridden by regkey }GMM_CACHE_POLICY_ELEMENT; // One entry in the SKL/CNL cache lookup table typedef struct GMM_CACHE_POLICY_TBL_ELEMENT_REC { union { struct { uint32_t Cacheability : 2; // LLC/eDRAM Cacheability Control (LeCC). uint32_t TargetCache : 2; // Target Cache (TC). uint32_t LRUM : 2; // LRU (Cache Replacement) Management (LRUM). uint32_t AOM : 1; // Do Not Allocate on Miss (AOM) - Not used uint32_t ESC : 1; // Enable Skip Caching (ESC) on LLC uint32_t SCC : 3; // Skip Caching Control (SCC). uint32_t PFM : 3; // Page Fault Mode (PFM) uint32_t SCF : 1; // Snoop Control Field (SCF) uint32_t CoS : 2; // Class of Service (COS)- CNL+ uint32_t SelfSnoop : 2; // Self Snoop override or not MIDI settings - CNL+ uint32_t Reserved : 13; } ; uint32_t DwordValue; union { struct { uint32_t Reserved0 : 2; uint32_t L4CC : 2; uint32_t Reserved1 : 2; uint32_t Reserved2 : 2; uint32_t igPAT : 1; // selection between MOCS and PAT uint32_t Reserved3 : 23; }; uint32_t DwordValue; } Xe_LPG; } LeCC; union { struct { uint16_t ESC : 1; // Enable Skip Caching (ESC) for L3. uint16_t SCC : 3; // Skip Caching Control (SCC) for L3. uint16_t Cacheability : 2; // L3 Cacheability Control (L3CC). uint16_t GlobalGo : 1; // Global Go (GLBGO). uint16_t UCLookup : 1; // UC L3 Lookup (UcL3Lookup). uint16_t Reserved : 8; } ; uint16_t UshortValue; union { struct { uint16_t Reserved : 2; uint16_t L4CC : 2; uint16_t L3CC : 2; uint16_t L3CLOS : 2; uint16_t igPAT : 1; // selection between MOCS and PAT uint16_t Reserved0: 7; }; } PhysicalL3; } L3; uint8_t HDCL1; } GMM_CACHE_POLICY_TBL_ELEMENT; typedef enum GMM_IA32e_MEMORY_TYPE_REC { GMM_IA32e_UC = 0x0, GMM_IA32e_WC = 0x1, GMM_IA32e_WT = 0x4, GMM_IA32e_WP = 0x5, GMM_IA32e_WB = 0x6, GMM_IA32e_UCMINUS = 0x7 } GMM_IA32e_MEMORY_TYPE; typedef enum GMM_GFX_MEMORY_TYPE_REC { GMM_GFX_UC_WITH_FENCE = 0x0, GMM_GFX_WC = 0x1, GMM_GFX_WT = 0x2, GMM_GFX_WB = 0x3 } GMM_GFX_MEMORY_TYPE; typedef enum GMM_L4_CACHING_POLICY_REC { GMM_CP_COHERENT_WB = 0x0, GMM_CP_NON_COHERENT_WB = 0x0, GMM_CP_NON_COHERENT_WT = 0x1, GMM_CP_NON_COHERENT_UC = 0x3, } GMM_L4_CACHING_POLICY; // This Enums represent the GMM indicative values for L1/L3/L4 cache attributes. typedef enum GMM_CACHING_POLICY_REC { GMM_UC = 0x0, //uncached GMM_WB = 0x1, // Write back GMM_WT = 0x2, // write-through GMM_WBTD = 0x3, // WB_T_Display GMM_WBTA = 0x4, // WB_T_App GMM_WBP = 0x5, // write bypass mode GMM_WS = 0x6, // Write-Streaming } GMM_CACHING_POLICY; typedef enum GMM_COHERENCY_TYPE_REC { GMM_NON_COHERENT_NO_SNOOP = 0x0, GMM_COHERENT_ONE_WAY_IA_SNOOP = 0x1, GMM_COHERENT_TWO_WAY_IA_GPU_SNOOP = 0x2 } GMM_COHERENCY_TYPE; typedef enum GMM_GFX_COHERENCY_TYPE_REC { GMM_GFX_NON_COHERENT_NO_SNOOP = 0x0, GMM_GFX_NON_COHERENT = 0x1, GMM_GFX_COHERENT_ONE_WAY_IA_SNOOP = 0x2, GMM_GFX_COHERENT_TWO_WAY_IA_GPU_SNOOP = 0x3 } GMM_GFX_COHERENCY_TYPE; typedef enum GMM_GFX_PAT_TYPE_REC { GMM_GFX_PAT_WB_COHERENT = 0x0, // WB + Snoop : Atom GMM_GFX_PAT_WC = 0x1, GMM_GFX_PAT_WB_MOCSLESS = 0x2, // WB + eLLC/LLC : MOCSLess Resource (PageTables) GMM_GFX_PAT_WB = 0x3, GMM_GFX_PAT_WT = 0x4, GMM_GFX_PAT_UC = 0x5 } GMM_GFX_PAT_TYPE; typedef enum GMM_GFX_PAT_IDX_REC { PAT0 = 0x0, // Will be tied to GMM_GFX_PAT_WB_COHERENT or GMM_GFX_PAT_UC depending on WaGttPat0WB PAT1, // Will be tied to GMM_GFX_PAT_UC or GMM_GFX_PAT_WB_COHERENT depending on WaGttPat0WB PAT2, // Will be tied to GMM_GFX_PAT_WB_MOCSLESS PAT3, // Will be tied to GMM_GFX_PAT_WB PAT4, // Will be tied to GMM_GFX_PAT_WT PAT5, // Will be tied to GMM_GFX_PAT_WC PAT6, // Will be tied to GMM_GFX_PAT_WC PAT7, // Will be tied to GMM_GFX_PAT_WC // Additional registers PAT8, PAT9, PAT10, PAT11, PAT12, PAT13, PAT14, PAT15 } GMM_GFX_PAT_IDX; #define GFX_IS_ATOM_PLATFORM(pGmmLibContext) (GmmGetSkuTable(pGmmLibContext)->FtrLCIA) typedef enum GMM_GFX_TARGET_CACHE_REC { GMM_GFX_TC_ELLC_ONLY = 0x0, GMM_GFX_TC_LLC_ONLY = 0x1, GMM_GFX_TC_ELLC_LLC = 0x3 } GMM_GFX_TARGET_CACHE; typedef union GMM_PRIVATE_PAT_REC { struct { uint32_t MemoryType : 2; uint32_t TargetCache : 2; uint32_t Age : 2; uint32_t Snoop : 1; uint32_t Reserved : 1; }PreGen10; #if (IGFX_GEN >= IGFX_GEN10) struct { uint32_t MemoryType : 2; uint32_t TargetCache : 2; uint32_t Age : 2; uint32_t Reserved1 : 2; uint32_t CoS : 2; uint32_t Reserved2 : 22; }Gen10; #endif struct { uint32_t MemoryType : 2; uint32_t Reserved : 30; }Gen12; struct { uint32_t MemoryType : 2; //L3 uint32_t L3CLOS : 2; uint32_t Reserved : 28; } Xe_HPC; struct { uint32_t Coherency : 2; uint32_t L4CC : 2; uint32_t Reserved : 28; }Xe_LPG; struct { uint32_t Coherency : 2; uint32_t L4CC : 2; uint32_t L3CC : 2; uint32_t L3CLOS : 2; uint32_t Reserved1 : 1; uint32_t LosslessCompressionEn: 1; uint32_t NoCachingPromote : 1; uint32_t Reserved2 : 21; } Xe2; uint32_t Value; } GMM_PRIVATE_PAT; #ifdef _WIN32 #define GMM_CACHE_POLICY_OVERRIDE_REGISTY_PATH_REGISTRY_UMD "SOFTWARE\\Intel\\IGFX\\CachePolicy\\" #define GMM_CACHE_POLICY_OVERRIDE_REGISTY_PATH_REGISTRY_KMD "\\REGISTRY\\MACHINE\\" GMM_CACHE_POLICY_OVERRIDE_REGISTY_PATH_REGISTRY_UMD // No local variables or ternary (?:) operators should be defined in the // REG_OVERRIDE macro block. This block will generate hundreds of instances // of itself in the OverrideCachePolicy, each of which will geneate a // copy of these local variables on the stack. The ternary operator will // also generate local temparoary stack variables, and all these add up and // can cause a stack overflow. #define READOVERRIDES(Usage) \ if (!REGISTRY_OVERRIDE_READ(Usage,LLC)) LLC = -1; \ if (!REGISTRY_OVERRIDE_READ(Usage,ELLC)) ELLC = -1; \ if (!REGISTRY_OVERRIDE_READ(Usage,L3)) L3 = -1; \ if (!REGISTRY_OVERRIDE_READ(Usage,Age)) Age = -1; \ if (!REGISTRY_OVERRIDE_READ(Usage,WT)) WT = -1; \ if (!REGISTRY_OVERRIDE_READ(Usage,AOM)) AOM = -1; \ if (!REGISTRY_OVERRIDE_READ(Usage,LeCC_SCC)) LeCC_SCC = -1; \ if (!REGISTRY_OVERRIDE_READ(Usage,L3_SCC)) L3_SCC = -1; \ if (!REGISTRY_OVERRIDE_READ(Usage,SCF)) SCF = -1; \ if (!REGISTRY_OVERRIDE_READ(Usage,SSO)) SSO = -1; \ if (!REGISTRY_OVERRIDE_READ(Usage,CoS)) CoS = -1; \ if (!REGISTRY_OVERRIDE_READ(Usage,HDCL1)) HDCL1 = -1; \ if (!REGISTRY_OVERRIDE_READ(Usage,L3Eviction)) L3Eviction = -1; \ if (!REGISTRY_OVERRIDE_READ(Usage,GlbGo)) GlbGo = -1; \ if (!REGISTRY_OVERRIDE_READ(Usage,UcLookup)) UcLookup = -1; \ #define SETOVERRIDES(Usage) \ if (LLC != -1) \ { \ pCachePolicy[Usage].LLC = LLC; \ } \ if (ELLC != -1) \ { \ pCachePolicy[Usage].ELLC = ELLC; \ } \ if (L3 != -1) \ { \ pCachePolicy[Usage].L3 = L3; \ } \ if (WT != -1) \ { \ pCachePolicy[Usage].WT = WT; \ } \ if (Age != -1) \ { \ pCachePolicy[Usage].AGE = Age; \ } \ if (AOM != -1) \ { \ pCachePolicy[Usage].AOM = AOM; \ } \ if (LeCC_SCC != -1) \ { \ pCachePolicy[Usage].LeCC_SCC = LeCC_SCC; \ } \ if (L3_SCC != -1) \ { \ pCachePolicy[Usage].L3_SCC = L3_SCC; \ } \ if (SCF != -1) \ { \ pCachePolicy[Usage].SCF = SCF; \ } \ if (SSO != -1) \ { \ pCachePolicy[Usage].SSO = SSO; \ } \ if (CoS != -1) \ { \ pCachePolicy[Usage].CoS = CoS; \ } \ if (HDCL1 != -1) \ { \ pCachePolicy[Usage].HDCL1 = HDCL1; \ } \ if (L3Eviction != -1) \ { \ pCachePolicy[Usage].L3Eviction = L3Eviction; \ } \ if (GlbGo != -1) \ { \ pCachePolicy[Usage].GlbGo = GlbGo; \ } \ if (UcLookup != -1) \ { \ pCachePolicy[Usage].UcLookup = UcLookup; \ } \ { \ pCachePolicy[Usage].IsOverridenByRegkey = 1; \ } #ifdef __GMM_KMD__ #define REG_OVERRIDE(Usage) \ { \ enum {IGNORED = 0, CURRENT, DEFAULT, UNCACHED}; \ \ REGISTRY_OVERRIDE_READ(Usage,Enable); \ \ if (Enable && (GenerateKeys != UNCACHED)) \ { \ READOVERRIDES(Usage) \ } \ \ if (GenerateKeys == DEFAULT || (GenerateKeys == CURRENT && !Enable)) \ { \ REGISTRY_OVERRIDE_WRITE(Usage,LLC, pCachePolicy[Usage].LLC); \ REGISTRY_OVERRIDE_WRITE(Usage,ELLC,pCachePolicy[Usage].ELLC); \ REGISTRY_OVERRIDE_WRITE(Usage,L3, pCachePolicy[Usage].L3); \ REGISTRY_OVERRIDE_WRITE(Usage,WT, pCachePolicy[Usage].WT); \ REGISTRY_OVERRIDE_WRITE(Usage,Age, pCachePolicy[Usage].AGE); \ REGISTRY_OVERRIDE_WRITE(Usage,AOM, pCachePolicy[Usage].AOM); \ REGISTRY_OVERRIDE_WRITE(Usage,LeCC_SCC, pCachePolicy[Usage].LeCC_SCC); \ REGISTRY_OVERRIDE_WRITE(Usage,L3_SCC, pCachePolicy[Usage].L3_SCC); \ REGISTRY_OVERRIDE_WRITE(Usage,SCF, pCachePolicy[Usage].SCF); \ REGISTRY_OVERRIDE_WRITE(Usage,SSO, pCachePolicy[Usage].SSO); \ REGISTRY_OVERRIDE_WRITE(Usage,CoS, pCachePolicy[Usage].CoS); \ REGISTRY_OVERRIDE_WRITE(Usage,HDCL1, pCachePolicy[Usage].HDCL1); \ REGISTRY_OVERRIDE_WRITE(Usage,L3Eviction, pCachePolicy[Usage].L3Eviction); \ REGISTRY_OVERRIDE_WRITE(Usage,Enable,0); \ REGISTRY_OVERRIDE_WRITE(Usage,GlbGo, pCachePolicy[Usage].GlbGo); \ REGISTRY_OVERRIDE_WRITE(Usage,UcLookup, pCachePolicy[Usage].UcLookup); \ } \ else if (GenerateKeys == UNCACHED || GenerateKeys == CURRENT) \ { \ if (GenerateKeys == UNCACHED) \ { \ Enable = 1; \ } \ REGISTRY_OVERRIDE_WRITE(Usage,LLC, LLC); \ REGISTRY_OVERRIDE_WRITE(Usage,ELLC,ELLC); \ REGISTRY_OVERRIDE_WRITE(Usage,L3, L3); \ REGISTRY_OVERRIDE_WRITE(Usage,WT, WT); \ REGISTRY_OVERRIDE_WRITE(Usage,Age, Age); \ REGISTRY_OVERRIDE_WRITE(Usage,AOM, AOM); \ REGISTRY_OVERRIDE_WRITE(Usage,LeCC_SCC, LeCC_SCC); \ REGISTRY_OVERRIDE_WRITE(Usage,L3_SCC, L3_SCC); \ REGISTRY_OVERRIDE_WRITE(Usage,SCF, SCF); \ REGISTRY_OVERRIDE_WRITE(Usage,SSO, SSO); \ REGISTRY_OVERRIDE_WRITE(Usage,CoS, CoS); \ REGISTRY_OVERRIDE_WRITE(Usage,HDCL1, HDCL1); \ REGISTRY_OVERRIDE_WRITE(Usage,L3Eviction, L3Eviction); \ REGISTRY_OVERRIDE_WRITE(Usage,Enable,Enable); \ REGISTRY_OVERRIDE_WRITE(Usage,GlbGo, GlbGo); \ REGISTRY_OVERRIDE_WRITE(Usage,UcLookup, UcLookup); \ } \ \ if (Enable) \ { \ SETOVERRIDES(Usage) \ } \ \ UsageCount++; \ } #else #define REG_OVERRIDE(Usage) \ { \ REGISTRY_OVERRIDE_READ(Usage,Enable); \ if (Enable) \ { \ READOVERRIDES(Usage) \ SETOVERRIDES(Usage) \ } \ UsageCount++; \ } #endif #endif // #if _WIN32 #if __cplusplus #include "GmmCachePolicyCommon.h" #include "CachePolicy/GmmCachePolicyGen8.h" #include "CachePolicy/GmmCachePolicyGen9.h" #endif // Function Prototypes GMM_STATUS GmmInitializeCachePolicy(); GMM_GFX_MEMORY_TYPE GmmGetWantedMemoryType(void *pLibContext, GMM_CACHE_POLICY_ELEMENT CachePolicy); // Used for GMM ULT testing. #ifdef __GMM_ULT extern void __GmmULTCachePolicy(GMM_CACHE_POLICY_ELEMENT *pCachePolicy); #endif #ifdef __cplusplus } #endif gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/inc/External/Common/GmmCachePolicyCommon.h000066400000000000000000000176551466655022700300220ustar00rootroot00000000000000/*============================================================================== Copyright(c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ============================================================================*/ #pragma once #ifdef __cplusplus #include "GmmMemAllocator.hpp" #include "GmmResourceInfoExt.h" #if LHDM // Applicable upto Gen9, Gen11+ gmmlib provides Cross-OS Fixed MOCS table as default support. #define GMM_DYNAMIC_MOCS_TABLE #define GMM_FIXED_MOCS_TABLE // Use for Gen11+ #endif ///////////////////////////////////////////////////////////////////////////////////// /// @file GmmCachePolicyCommon.h /// @brief This file contains Gmm Cache Policy functions ///////////////////////////////////////////////////////////////////////////////////// namespace GmmLib { ///////////////////////////////////////////////////////////////////////// /// Contains the Gmm Cache Policy functions common for Linux and Windows /// implementation. This class is inherited by gen specific class so /// so clients shouldn't have to ever interact with this class directly. ///////////////////////////////////////////////////////////////////////// class Context; class NON_PAGED_SECTION GmmCachePolicyCommon : public GmmMemAllocator { protected: Context * pGmmLibContext; uint32_t NumPATRegisters; uint32_t NumMOCSRegisters; public: GMM_CACHE_POLICY_ELEMENT *pCachePolicy; /* Constructor */ GmmCachePolicyCommon(GMM_CACHE_POLICY_ELEMENT *pCachePolicy, Context *pGmmLibContext); /* Function prototypes */ GMM_GFX_MEMORY_TYPE GetWantedMemoryType(GMM_CACHE_POLICY_ELEMENT CachePolicy); #define DEFINE_CP_ELEMENT(Usage, llc, ellc, l3, wt, age, aom, lecc_scc, l3_scc, scf, sso, cos, hdcl1, l3evict, segov, glbgo, uclookup, l1cc, l2cc, l4cc, coherency, l3cc, l3clos, igPAT)\ do { \ pCachePolicy[Usage].LLC = (llc); \ pCachePolicy[Usage].ELLC = (ellc); \ pCachePolicy[Usage].L3 = (l3); \ pCachePolicy[Usage].WT = (wt); \ pCachePolicy[Usage].AGE = (age); \ pCachePolicy[Usage].AOM = (aom); \ pCachePolicy[Usage].LeCC_SCC = (lecc_scc); \ pCachePolicy[Usage].L3_SCC = (l3_scc); \ pCachePolicy[Usage].SCF = (scf); \ pCachePolicy[Usage].SSO = (sso); \ pCachePolicy[Usage].CoS = (cos); \ pCachePolicy[Usage].HDCL1 = (hdcl1); \ pCachePolicy[Usage].L3Eviction = (l3evict); \ pCachePolicy[Usage].SegOv = (segov); \ pCachePolicy[Usage].GlbGo = (glbgo); \ pCachePolicy[Usage].UcLookup = (uclookup); \ pCachePolicy[Usage].L1CC = (l1cc); \ pCachePolicy[Usage].Initialized = 1; \ pCachePolicy[Usage].L2CC = (l2cc); \ pCachePolicy[Usage].L4CC = (l4cc); \ pCachePolicy[Usage].Coherency = (coherency); \ pCachePolicy[Usage].L3CC = (l3cc); \ pCachePolicy[Usage].L3CLOS = (l3clos); \ pCachePolicy[Usage].IgnorePAT = (igPAT); \ } while (0) MEMORY_OBJECT_CONTROL_STATE GMM_STDCALL CachePolicyGetOriginalMemoryObject(GMM_RESOURCE_INFO *pResInfo); MEMORY_OBJECT_CONTROL_STATE GMM_STDCALL CachePolicyGetMemoryObject(GMM_RESOURCE_INFO *pResInfo, GMM_RESOURCE_USAGE_TYPE Usage); GMM_PTE_CACHE_CONTROL_BITS GMM_STDCALL CachePolicyGetPteType(GMM_RESOURCE_USAGE_TYPE Usage); /* Virtual functions prototype*/ virtual uint8_t GMM_STDCALL CachePolicyIsUsagePTECached(GMM_RESOURCE_USAGE_TYPE Usage) = 0; virtual GMM_STATUS InitCachePolicy() = 0; virtual uint32_t GetMaxSpecialMocsIndex() { return 0; } virtual ~GmmCachePolicyCommon() { } virtual uint32_t GMM_STDCALL CachePolicyGetPATIndex(GMM_RESOURCE_INFO *pResInfo, GMM_RESOURCE_USAGE_TYPE Usage, bool *pCompressionEnable, bool IsCpuCacheable); uint32_t GMM_STDCALL CachePolicyGetNumPATRegisters(); virtual uint32_t GMM_STDCALL GetSurfaceStateL1CachePolicy(GMM_RESOURCE_USAGE_TYPE Usage); }; } #endif // #ifdef __cplusplus gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/inc/External/Common/GmmCachePolicyExt.h000066400000000000000000000112761466655022700273230ustar00rootroot00000000000000/*============================================================================== Copyright(c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ============================================================================*/ #pragma once //=========================================================================== // typedef: // GMM_RESOURCE_USAGE // // Description: // Defines Usage types for different Resources //---------------------------------------------------------------------------- typedef enum GMM_RESOURCE_USAGE_TYPE_ENUM { //Generic Usage GMM_RESOURCE_USAGE_UNKNOWN = 0, // <== MUST EQUAL 0 #define DEFINE_RESOURCE_USAGE(Usage) Usage, #include "../../../CachePolicy/GmmCachePolicyResourceUsageDefinitions.h" #undef DEFINE_RESOURCE_USAGE GMM_RESOURCE_USAGE_MAX // <== MUST BE LAST ELEMENT }GMM_RESOURCE_USAGE_TYPE; typedef union GMM_PTE_CACHE_CONTROL_BITS_REC { struct { uint64_t Valid : 1; uint64_t CacheControl : 2; uint64_t GFDT : 1; uint64_t : 28; uint64_t : 32; } Gen6; struct { uint64_t Valid : 1; uint64_t CacheControlLo : 3; uint64_t : 7; uint64_t CacheControlHi : 1; uint64_t : 20; uint64_t : 32; } Gen7_5; struct { uint64_t Valid : 1; uint64_t : 2; uint64_t PWT : 1; uint64_t PCD : 1; uint64_t : 2; uint64_t PAT : 1; uint64_t : 24; uint64_t : 32; } Gen8; struct { uint64_t Valid : 1; uint64_t : 2; uint64_t PAT0 : 1; uint64_t PAT1 : 1; uint64_t : 2; uint64_t PAT2 : 1; uint64_t : 24; uint64_t : 30; uint64_t PAT3 : 1; uint64_t : 1; } XE_LPG; struct { uint32_t DwordValue; uint32_t HighDwordValue; }; } GMM_PTE_CACHE_CONTROL_BITS; typedef union MEMORY_OBJECT_CONTROL_STATE_REC { struct { uint32_t CacheControl : 2; uint32_t GFDT : 1; uint32_t : 1; uint32_t : 28; } Gen6; struct { uint32_t L3 : 1; uint32_t CacheControl : 1; uint32_t GFDT : 1; uint32_t EncryptedData : 1; uint32_t : 28; } Gen7; struct { uint32_t L3 : 1; uint32_t CacheControl : 2; uint32_t EncryptedData : 1; uint32_t : 28; } Gen7_5; struct { uint32_t Age : 2; uint32_t EncryptedData : 1; uint32_t TargetCache : 2; uint32_t CacheControl : 2; uint32_t : 25; } Gen8; struct { uint32_t EncryptedData : 1; uint32_t Index : 6; uint32_t : 25; } Gen9, Gen10, Gen11, Gen12, XE_HP, XE_LPG; uint32_t DwordValue; } MEMORY_OBJECT_CONTROL_STATE; // typedef: // GMM_CACHE_POLICY // // Description: // This struct is used for accessing Cache Policy functions. // Forward Declaration: Defined in GmmCachePolicy.h //--------------------------------------------------------------------------- #ifdef __cplusplus namespace GmmLib { class GmmCachePolicyCommon; } typedef GmmLib::GmmCachePolicyCommon GMM_CACHE_POLICY; #else struct GmmCachePolicyCommon; typedef struct GmmCachePolicyCommon GMM_CACHE_POLICY; #endif gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/inc/External/Common/GmmClientContext.h000066400000000000000000000303561466655022700272420ustar00rootroot00000000000000/*============================================================================== Copyright(c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ============================================================================*/ #pragma once #include "GmmCommonExt.h" #include "GmmInfo.h" ////////////////////////////////////////////////////////////////// // Memory Allocators and DeAllocators for Gmm Create Objects // This is needed for Clients who want to construct using their // own memory allocators ////////////////////////////////////////////////////////////////// typedef void* (GMM_STDCALL *PFN_ClientAllocationFunction)( void* pUserData, uint32_t size, uint32_t alignment); typedef void (GMM_STDCALL *PFN_ClientFreeFunction)( void* pUserData, void* pMemory); typedef struct _GmmClientAllocationCallbacks_ { void* pUserData; uint32_t size; uint32_t alignment; PFN_ClientAllocationFunction pfnAllocation; PFN_ClientFreeFunction pfnFree; } GmmClientAllocationCallbacks; //=========================================================================== // typedef: // GMM_DEVICE_OPERATION // // Description: // Decribes compoents required for device operations. //---------------------------------------------- ------------------------------ typedef struct _GMM_DEVICE_INFO_REC { GMM_DEVICE_CALLBACKS_INT *pDeviceCb; }GMM_DEVICE_INFO; #ifdef __cplusplus #include "GmmMemAllocator.hpp" ///////////////////////////////////////////////////////////////////////////////////// /// @file GmmClientContext.h /// @brief This file contains the functions and members of GmmClientContext that is /// common for both Linux and Windows. /// ///////////////////////////////////////////////////////////////////////////////////// namespace GmmLib { ///////////////////////////////////////////////////////////////////////// /// Contains functions and members that are common between Linux and /// Windows implementation. This class members will hold data that /// are specific to each client. ///////////////////////////////////////////////////////////////////////// class Context; class GMM_LIB_API NON_PAGED_SECTION GmmClientContext : public GmmMemAllocator { protected: GMM_CLIENT ClientType; ///< Placeholders for storing UMD context. Actual UMD context that needs to be stored here is void *pUmdAdapter; GMM_UMD_CONTEXT *pGmmUmdContext; GMM_DEVICE_CALLBACKS_INT DeviceCB; //OS-specific defn: Will be used by Clients to send as input arguments. // Flag to indicate Device_callbacks received. uint8_t IsDeviceCbReceived; Context *pGmmLibContext; public: /* Constructor */ GmmClientContext(GMM_CLIENT ClientType); GmmClientContext(GMM_CLIENT ClientType, Context* pLibContext); /* Virtual destructor */ virtual ~GmmClientContext(); /* Inline functions */ ///////////////////////////////////////////////////////////////////////////////////// /// Returns the GMM_CLIENT Type that has created this ClientContext. /// @return GMM_CLIENT ///////////////////////////////////////////////////////////////////////////////////// GMM_INLINE_VIRTUAL GMM_INLINE_EXPORTED GMM_CLIENT GMM_STDCALL GetClientType() { return (ClientType); } GMM_INLINE_VIRTUAL GMM_LIB_CONTEXT *GetLibContext() { return pGmmLibContext; } /* Function prototypes */ /* CachePolicy Related Exported Functions from GMM Lib */ GMM_VIRTUAL MEMORY_OBJECT_CONTROL_STATE GMM_STDCALL CachePolicyGetMemoryObject(GMM_RESOURCE_INFO *pResInfo, GMM_RESOURCE_USAGE_TYPE Usage); GMM_VIRTUAL GMM_PTE_CACHE_CONTROL_BITS GMM_STDCALL CachePolicyGetPteType(GMM_RESOURCE_USAGE_TYPE Usage); GMM_VIRTUAL MEMORY_OBJECT_CONTROL_STATE GMM_STDCALL CachePolicyGetOriginalMemoryObject(GMM_RESOURCE_INFO *pResInfo); GMM_VIRTUAL uint8_t GMM_STDCALL CachePolicyIsUsagePTECached(GMM_RESOURCE_USAGE_TYPE Usage); GMM_VIRTUAL uint8_t GMM_STDCALL GetSurfaceStateL1CachePolicy(GMM_RESOURCE_USAGE_TYPE Usage); GMM_VIRTUAL uint32_t GMM_STDCALL CachePolicyGetMaxMocsIndex(); GMM_VIRTUAL uint32_t GMM_STDCALL CachePolicyGetMaxL1HdcMocsIndex(); GMM_VIRTUAL uint32_t GMM_STDCALL CachePolicyGetMaxSpecialMocsIndex(); GMM_VIRTUAL GMM_CACHE_POLICY_ELEMENT* GMM_STDCALL GetCachePolicyUsage(); GMM_VIRTUAL void GMM_STDCALL GetCacheSizes(GMM_CACHE_SIZES *pCacheSizes); GMM_VIRTUAL GMM_CACHE_POLICY_ELEMENT GMM_STDCALL GetCachePolicyElement(GMM_RESOURCE_USAGE_TYPE Usage); GMM_VIRTUAL GMM_CACHE_POLICY_TBL_ELEMENT GMM_STDCALL GetCachePolicyTlbElement(uint32_t MocsIdx); GMM_VIRTUAL GMM_PLATFORM_INFO& GMM_STDCALL GetPlatformInfo(); GMM_VIRTUAL const SKU_FEATURE_TABLE& GMM_STDCALL GetSkuTable(); GMM_VIRTUAL void GMM_STDCALL GetExtendedTextureAlign(uint32_t Mode, ALIGNMENT &UnitAlign); GMM_VIRTUAL uint8_t GMM_STDCALL IsPlanar(GMM_RESOURCE_FORMAT Format); GMM_VIRTUAL uint8_t GMM_STDCALL IsP0xx(GMM_RESOURCE_FORMAT Format); GMM_VIRTUAL uint8_t GMM_STDCALL IsUVPacked(GMM_RESOURCE_FORMAT Format); GMM_VIRTUAL uint8_t GMM_STDCALL IsCompressed(GMM_RESOURCE_FORMAT Format); GMM_VIRTUAL uint8_t GMM_STDCALL IsYUVPacked(GMM_RESOURCE_FORMAT Format); GMM_VIRTUAL GMM_SURFACESTATE_FORMAT GMM_STDCALL GetSurfaceStateFormat(GMM_RESOURCE_FORMAT Format); GMM_VIRTUAL uint8_t GMM_STDCALL GetSurfaceStateCompressionFormat(GMM_RESOURCE_FORMAT Format); GMM_VIRTUAL uint8_t GMM_STDCALL GetMediaSurfaceStateCompressionFormat(GMM_RESOURCE_FORMAT Format); GMM_VIRTUAL GMM_E2ECOMP_FORMAT GMM_STDCALL GetLosslessCompressionType(GMM_RESOURCE_FORMAT Format); GMM_VIRTUAL uint64_t GMM_STDCALL GetInternalGpuVaRangeLimit(); /* ResourceInfo Creation and Destroy API's */ GMM_VIRTUAL GMM_RESOURCE_INFO* GMM_STDCALL CreateResInfoObject(GMM_RESCREATE_PARAMS *pCreateParams); GMM_VIRTUAL GMM_RESOURCE_INFO* GMM_STDCALL CopyResInfoObject(GMM_RESOURCE_INFO *pSrcRes); GMM_VIRTUAL void GMM_STDCALL ResMemcpy(void *pDst, void *pSrc); GMM_VIRTUAL void GMM_STDCALL DestroyResInfoObject(GMM_RESOURCE_INFO *pResInfo); /* PageTableMgr Creation and Destroy API's */ GMM_VIRTUAL GMM_PAGETABLE_MGR* GMM_STDCALL CreatePageTblMgrObject(GMM_DEVICE_CALLBACKS_INT* pDevCb, uint32_t TTFlags); GMM_VIRTUAL GMM_PAGETABLE_MGR* GMM_STDCALL CreatePageTblMgrObject(uint32_t TTFlags); /* PageTableMgr Creation and Destroy API's */ GMM_VIRTUAL void GMM_STDCALL DestroyPageTblMgrObject(GMM_PAGETABLE_MGR* pPageTableMgr); #ifdef GMM_LIB_DLL /* ResourceInfo and PageTableMgr Create and Destroy APIs with Client provided Memory Allocators */ GMM_VIRTUAL GMM_RESOURCE_INFO* GMM_STDCALL CreateResInfoObject(GMM_RESCREATE_PARAMS *pCreateParams, GmmClientAllocationCallbacks *pAllocCbs); GMM_VIRTUAL void GMM_STDCALL DestroyResInfoObject(GMM_RESOURCE_INFO *pResInfo, GmmClientAllocationCallbacks *pAllocCbs); #endif GMM_VIRTUAL GMM_PAGETABLE_MGR* GMM_STDCALL CreatePageTblMgrObject( GMM_DEVICE_CALLBACKS_INT* pDevCb, uint32_t TTFlags, GmmClientAllocationCallbacks* pAllocCbs); GMM_VIRTUAL GMM_PAGETABLE_MGR* GMM_STDCALL CreatePageTblMgrObject( uint32_t TTFlags, GmmClientAllocationCallbacks* pAllocCbs); GMM_VIRTUAL void GMM_STDCALL DestroyPageTblMgrObject(GMM_PAGETABLE_MGR* pPageTableMgr, GmmClientAllocationCallbacks* pAllocCbs); GMM_VIRTUAL GMM_STATUS GMM_STDCALL GmmSetDeviceInfo(GMM_DEVICE_INFO* DeviceInfo); GMM_VIRTUAL GMM_RESOURCE_INFO* GMM_STDCALL CreateCustomResInfoObject(GMM_RESCREATE_CUSTOM_PARAMS* pCreateParams); #ifndef __GMM_KMD__ GMM_VIRTUAL GMM_RESOURCE_INFO *GMM_STDCALL CreateCustomResInfoObject_2(GMM_RESCREATE_CUSTOM_PARAMS_2 *pCreateParams); #endif GMM_VIRTUAL uint32_t GMM_STDCALL CachePolicyGetPATIndex(GMM_RESOURCE_INFO *pResInfo, GMM_RESOURCE_USAGE_TYPE Usage, bool *pCompressionEnable, bool IsCpuCacheable); GMM_VIRTUAL const SWIZZLE_DESCRIPTOR *GMM_STDCALL GetSwizzleDesc(EXTERNAL_SWIZZLE_NAME ExternalSwizzleName, EXTERNAL_RES_TYPE ResType, uint8_t bpe, bool isStdSwizzle = false); }; } typedef GmmLib::GmmClientContext GMM_CLIENT_CONTEXT; #else struct GmmClientContext; typedef struct GmmClientContext GMM_CLIENT_CONTEXT; #endif #ifdef __cplusplus extern "C" { #endif /* ClientContext will be unique to each client */ GMM_CLIENT_CONTEXT* GMM_STDCALL GmmCreateClientContextForAdapter(GMM_CLIENT ClientType, ADAPTER_BDF sBdf); void GMM_STDCALL GmmDeleteClientContext(GMM_CLIENT_CONTEXT *pGmmClientContext); #if GMM_LIB_DLL #ifdef _WIN32 GMM_STATUS GMM_STDCALL GmmCreateLibContext(const PLATFORM Platform, const SKU_FEATURE_TABLE *pSkuTable, const WA_TABLE * pWaTable, const GT_SYSTEM_INFO * pGtSysInfo, ADAPTER_BDF sBdf); #else GMM_STATUS GMM_STDCALL GmmCreateLibContext(const PLATFORM Platform, const void * pSkuTable, const void * pWaTable, const void * pGtSysInfo, ADAPTER_BDF sBdf, const GMM_CLIENT ClientType); #endif void GMM_STDCALL GmmLibContextFree(ADAPTER_BDF sBdf); GMM_LIB_API_CONSTRUCTOR void GmmCreateMultiAdapterContext(); GMM_LIB_API_DESTRUCTOR void GmmDestroyMultiAdapterContext(); #endif //GMM_LIB_DLL #ifdef __cplusplus } #endif gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/inc/External/Common/GmmCommonExt.h000066400000000000000000000632411466655022700263670ustar00rootroot00000000000000/*============================================================================== Copyright(c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ============================================================================*/ #pragma once //=========================================================================== // Macros to be defined for GMM Lib DLL //=========================================================================== #ifdef GMM_LIB_DLL /* To be defined by Clients if GMMlib needs to be in DLL/so */ #define GMM_INLINE_VIRTUAL virtual #define GMM_VIRTUAL virtual #define GMM_INLINE_EXPORTED /* Macro To avoid inlining of exported member functions in ClientÂ’s code in DLL mode*/ #define GMM_LIB_DLL_MA 1 // Macro to indicate whether GMM Lib DLL is Multi-Adapter capable. Todo: Make this a build macro #ifdef _WIN32 #ifdef GMM_LIB_DLL_EXPORTS #define GMM_LIB_API __declspec(dllexport) /* Macro to define GMM Lib DLL exports */ #else #define GMM_LIB_API __declspec(dllimport) /* Macro to define GMM Lib DLL imports */ #endif /* GMM_LIB_DLL_EXPORTS */ #define GMM_LIB_API_CONSTRUCTOR #define GMM_LIB_API_DESTRUCTOR #else // Linux #ifdef GMM_LIB_DLL_EXPORTS #define GMM_LIB_API __attribute__ ((visibility ("default"))) #else #define GMM_LIB_API #endif #define GMM_LIB_API_CONSTRUCTOR __attribute__((constructor)) #define GMM_LIB_API_DESTRUCTOR __attribute__((destructor)) #endif #else // !GMM_LIB_DLL #define GMM_INLINE_VIRTUAL #define GMM_VIRTUAL #define GMM_LIB_API #define GMM_INLINE_EXPORTED __inline #endif /* GMM_LIB_DLL */ #define INCLUDE_CpuSwizzleBlt_c_AS_HEADER #include "../../../Utility/CpuSwizzleBlt/CpuSwizzleBlt.c" extern const SWIZZLE_DESCRIPTOR INTEL_64KB_UNDEFINED_8bpp; extern const SWIZZLE_DESCRIPTOR INTEL_64KB_UNDEFINED_16_32bpp; extern const SWIZZLE_DESCRIPTOR INTEL_64KB_UNDEFINED_64_128bpp; // Set packing alignment #pragma pack(push, 8) #if defined(__ARM_ARCH) #define GMM_STDCALL // GMM function calling convention #else #define GMM_STDCALL __stdcall // GMM function calling convention #endif #define GMM_NO_FENCE_REG 0xDEADBEEF #define GMM_MAX_DISPLAYS 3 #if defined __linux__ typedef void* HANDLE; #endif //=========================================================================== // typedef: // GMM_GFX_ADDRESS/etc. // // Description: // The GMM GfxAddr/Size and related types and casting functions. //---------------------------------------------------------------------------- // Always use x64 (D3D11.2 Tiled Resources needs >32 bit gfx address space) typedef uint64_t GMM_GFX_ADDRESS, GMM_GFX_SIZE_T, GMM_VOIDPTR64; #define GMM_GFX_ADDRESS_MAX ((GMM_GFX_ADDRESS) 0xffffffffffffffff) typedef uint32_t GMM_GLOBAL_GFX_ADDRESS, GMM_GLOBAL_GFX_SIZE_T; #define GMM_GLOBAL_GFX_ADDRESS_MAX ((GMM_GLOBAL_GFX_ADDRESS) 0xffffffff) #ifdef _DEBUG #define GMM_GFX_ADDRESS_CAST(x) \ ( \ ((x) <= GMM_GFX_ADDRESS_MAX) ? \ 1 : __debugbreak(), \ (GMM_GFX_ADDRESS)(x) \ ) #define GMM_GFX_SIZE_T_CAST GMM_GFX_ADDRESS_CAST #define GMM_GLOBAL_GFX_ADDRESS_CAST(x) \ ( \ ((x) <= GMM_GLOBAL_GFX_ADDRESS_MAX) ? \ 1 : __debugbreak(), \ (GMM_GLOBAL_GFX_ADDRESS)(x) \ ) #define GMM_GLOBAL_GFX_SIZE_T_CAST GMM_GLOBAL_GFX_ADDRESS_CAST #else #define GMM_GFX_ADDRESS_CAST(x) ((GMM_GFX_ADDRESS)(x)) #define GMM_GFX_SIZE_T_CAST(x) ((GMM_GFX_SIZE_T)(x)) #define GMM_GLOBAL_GFX_ADDRESS_CAST(x) ((GMM_GLOBAL_GFX_ADDRESS)(x)) #define GMM_GLOBAL_GFX_SIZE_T_CAST(x) ((GMM_GLOBAL_GFX_SIZE_T)(x)) #endif #define GMM_GFX_ADDRESS_CANONIZE(a) (((int64_t)(a) << (64 - 48)) >> (64 - 48)) // TODO(Minor): When GMM adds platform-dependent VA size caps, change from 48. #define GMM_GFX_ADDRESS_DECANONIZE(a) ((uint64_t)(a) & (((uint64_t) 1 << 48) - 1)) // " #define GMM_GFX_PLATFORM_VA_SIZE(pClientContext) (((pClientContext)->GetLibContext()->GetSkuTable().Ftr57bGPUAddressing) ? 57 : 48) #define VASize(pCC) GMM_GFX_PLATFORM_VA_SIZE(pCC) #define GMM_BIT_RANGE(endbit, startbit) ((endbit) - (startbit) + 1) #define GMM_BIT(bit) (1) #define GMM_GET_PTE_BITS_FROM_PAT_IDX(idx) ((((idx)&__BIT(4)) ? __BIT64(61) : 0) | \ (((idx)&__BIT(3)) ? __BIT64(62) : 0) | \ (((idx)&__BIT(2)) ? __BIT64(7) : 0) | \ (((idx)&__BIT(1)) ? __BIT64(4) : 0) | \ (((idx)&__BIT(0)) ? __BIT64(3) : 0) ) #define GMM_GET_PAT_IDX_FROM_PTE_BITS(Entry) ((((Entry) & __BIT64(61)) ? __BIT(4) : 0) | \ (((Entry) & __BIT64(62)) ? __BIT(3) : 0) | \ (((Entry) & __BIT64(7)) ? __BIT(2) : 0) | \ (((Entry) & __BIT64(4)) ? __BIT(1) : 0) | \ (((Entry) & __BIT64(3)) ? __BIT(0) : 0) ) #define GMM_GET_PAT_IDX_FROM_PTE_BITS_GGTT(Entry) ((((Entry) & __BIT64(53)) ? __BIT(1) : 0) | \ (((Entry) & __BIT64(52)) ? __BIT(0) : 0) ) #define GMM_GET_PTE_BITS_FROM_PAT_IDX(idx) ((((idx)&__BIT(4)) ? __BIT64(61) : 0) | \ (((idx)&__BIT(3)) ? __BIT64(62) : 0) | \ (((idx)&__BIT(2)) ? __BIT64(7) : 0) | \ (((idx)&__BIT(1)) ? __BIT64(4) : 0) | \ (((idx)&__BIT(0)) ? __BIT64(3) : 0) ) #define GMM_GET_PTE_BITS_FROM_PAT_IDX_LEAF_PD(idx) ((((idx)&__BIT(4)) ? __BIT64(61) : 0) | \ (((idx)&__BIT(3)) ? __BIT64(62) : 0) | \ (((idx)&__BIT(2)) ? __BIT64(12) : 0) | \ (((idx)&__BIT(1)) ? __BIT64(4) : 0) | \ (((idx)&__BIT(0)) ? __BIT64(3) : 0) ) #define GMM_GET_PTE_BITS_FROM_PAT_IDX_GGTT(idx) ((((idx)&__BIT(1)) ? __BIT64(53) : 0) | \ (((idx)&__BIT(0)) ? __BIT64(52) : 0) ) //=========================================================================== // typedef: // GMM_STATUS_ENUM // // Description: // Decribes GMM lib function return values //---------------------------------------------------------------------------- typedef enum GMM_STATUS_ENUM { GMM_SUCCESS, GMM_ERROR, GMM_INVALIDPARAM, GMM_OUT_OF_MEMORY, } GMM_STATUS; //=========================================================================== // typedef: // GMM_CLIENT // // Description: // Decribes who is linking GMM lib. Allow Kernel mode driver to detect // origin of resource allocations. //---------------------------------------------------------------------------- typedef enum GMM_CLIENT_ENUM { GMM_KMD_VISTA = 0, GMM_OGL_VISTA = 1, GMM_D3D9_VISTA = 2, GMM_D3D10_VISTA = 3, GMM_XP = 4, GMM_D3D12_VISTA = 5, GMM_OCL_VISTA = 6, GMM_VK_VISTA = 7, GMM_EXCITE_VISTA = 8, GMM_UNDEFINED_CLIENT = 9, }GMM_CLIENT; // Macros related to GMM_CLIENT Enum #define USE_KMT_API(ClientType) ((ClientType == GMM_OGL_VISTA) || (ClientType == GMM_OCL_VISTA) || (ClientType == GMM_VK_VISTA) || (ClientType == GMM_EXCITE_VISTA)) #define USE_DX12_API(ClientType) (ClientType == GMM_D3D12_VISTA) #define USE_DX10_API(ClientType) (ClientType == GMM_D3D10_VISTA) #define USE_DX_API(ClientType) ((ClientType == GMM_D3D12_VISTA) || (ClientType == GMM_D3D10_VISTA) || (ClientType == GMM_D3D9_VISTA)) #define GET_GMM_CLIENT_TYPE(pContext, ClientType) \ if(pContext) \ { \ ClientType = ((GmmClientContext*)pContext)->GetClientType(); \ } \ else \ { \ ClientType = GMM_UNDEFINED_CLIENT; \ } \ #define GET_RES_CLIENT_TYPE(pResourceInfo, ClientType) \ if(pResourceInfo) \ { \ ClientType = (pResourceInfo)->GetClientType(); \ } \ else \ { \ ClientType = GMM_UNDEFINED_CLIENT; \ } \ //=========================================================================== // typedef: // GMM_TEXTURE_LAYOUT // // Description: // This enum details HW tile walk (i.e. X or Y walk) //--------------------------------------------------------------------------- typedef enum GMM_TEXTURE_LAYOUT_REC { GMM_2D_LAYOUT_BELOW = 0, // <- This should stay zero to be the default for all surfaces (including 3D, etc), since texture layout can be queried for 3D/etc surfaces. TODO: Is that querying proper behavior?! GMM_2D_LAYOUT_RIGHT = 1, }GMM_TEXTURE_LAYOUT; //=========================================================================== // typedef: // GMM_TILE_TYPE_ENUM // // Description: // This enum details tile walk (i.e. X or Y walk, or not tiled) //--------------------------------------------------------------------------- typedef enum GMM_TILE_TYPE_ENUM { GMM_TILED_X, GMM_TILED_Y, GMM_TILED_W, GMM_NOT_TILED, GMM_TILED_4, GMM_TILED_64 }GMM_TILE_TYPE; //=========================================================================== // typedef: // GMM_E2E_COMPRESSION_TYPE_ENUM // // Description: // This enum details compression type (i.e. render or media compressed, or uncompressed ) //--------------------------------------------------------------------------- typedef enum GMM_E2E_COMPRESSION_TYPE_ENUM { GMM_UNCOMPRESSED, GMM_RENDER_COMPRESSED, GMM_MEDIA_COMPRESSED }GMM_E2E_COMPRESSION_TYPE; //=========================================================================== // typedef: // GMM_CPU_CACHE_TYPE_ENUM // // Description: // This enum details the type of cacheable attributes for the memory //--------------------------------------------------------------------------- typedef enum GMM_CPU_CACHE_TYPE_ENUM { GMM_NOTCACHEABLE, GMM_CACHEABLE }GMM_CPU_CACHE_TYPE; //=========================================================================== // typedef: // GMM_GPU_CACHE_SETTINGS // // Description: // This struct details the type of cacheable attributes for the memory //--------------------------------------------------------------------------- typedef struct GMM_GPU_CACHE_SETTINGS_REC { uint32_t ELLC : 1; // Gen7.5+ uint32_t Age : 2; // Gen7.5+ uint32_t WriteThrough : 1; // Gen7.5+ uint32_t GFDT : 1; // Gen6,7 (Graphics Flush Data Type) uint32_t L3 : 1; // Gen7+ uint32_t LLC : 1; // Gen6+ uint32_t UsePteSettings : 1; // Gen6+ }GMM_GPU_CACHE_SETTINGS; //=========================================================================== // typedef: // GMM_CACHE_SIZE // // Description: // This struct details the size of the L3 and EDram caches //--------------------------------------------------------------------------- typedef struct GMM_CACHE_SIZES_REC { GMM_GFX_SIZE_T TotalL3Cache; // L3 Cache Size in Bytes GMM_GFX_SIZE_T TotalLLCCache; // LLC Cache Size in Bytes GMM_GFX_SIZE_T TotalEDRAM; // eDRAM Size in Bytes } GMM_CACHE_SIZES; //------------------------------------------------------------------------ // GMM Legacy Flags //------------------------------------------------------------------------ // GMM_TILE_W & GMM_TILE_X & GMM_TILE_Y are for internal use. Clients should use GMM_TILE_TYPE_ENUM #define GMM_TILE_W (__BIT(1)) // Tile W type #define GMM_TILE_X (__BIT(2)) // Tile X type #define GMM_TILE_Y (__BIT(3)) // Tile Y type #if !defined(GHAL3D_ULT) #define GMM_LINEAR (__BIT(4)) // Linear type #define GMM_TILED (GMM_TILE_W | GMM_TILE_X | GMM_TILE_Y) // Tiled bit #endif #define GMM_HEAP_EXTERNAL_SYNC (__BIT(7)) // Indicates GMM_HEAP should not use its internal sync protection. #define GMM_UTILIZEFENCE (__BIT(8)) #define GMM_NOT_OS_ADDR 0xA1B3C5D7 //=========================================================================== // typedef: // GMM_TILE_INFO // // Description: // This structure represents a tile type //-------------------------------------------------------------------------- typedef struct GMM_TILE_INFO_REC { uint32_t LogicalTileWidth; // width of tile in bytes uint32_t LogicalTileHeight; // Height of tile in rows [texels] uint32_t LogicalTileDepth; // Depth of tile uint32_t LogicalSize; // Size of the tile in bytes uint32_t MaxPitch; // Maximum pitch in bytes uint32_t MaxMipTailStartWidth; // Max mip tail start width in pixels uint32_t MaxMipTailStartHeight; // Max mip tail start height in rows uint32_t MaxMipTailStartDepth; // Max mip tail start depth in slices } GMM_TILE_INFO; //=========================================================================== // typedef: // GMM_CUBE_FACE_REC // // Description: // ENUM detailing cube map faces //--------------------------------------------------------------------------- typedef enum GMM_CUBE_FACE_ENUM { __GMM_CUBE_FACE_POS_X, __GMM_CUBE_FACE_NEG_X, __GMM_CUBE_FACE_POS_Y, __GMM_CUBE_FACE_NEG_Y, __GMM_CUBE_FACE_POS_Z, __GMM_CUBE_FACE_NEG_Z, __GMM_MAX_CUBE_FACE, __GMM_NO_CUBE_MAP, } GMM_CUBE_FACE_ENUM; //=========================================================================== // typedef: // GMM_YUV_PLANE_REC // // Description: // //-------------------------------------------------------------------------- typedef enum GMM_YUV_PLANE_ENUM { GMM_NO_PLANE = 0, GMM_PLANE_Y = 1, GMM_PLANE_U = 2, GMM_PLANE_V = 3, GMM_MAX_PLANE = 4, // GmmLib internal use only GMM_PLANE_3D_Y0 = 0, GMM_PLANE_3D_Y1 = 1, GMM_PLANE_3D_UV0 = 2, GMM_PLANE_3D_UV1 = 3 // No internal use >= GMM_MAX_PLANE! }GMM_YUV_PLANE; // GMM_RESOURCE_FORMAT // // Description: // Enumeration of GMM supported resource formats. //--------------------------------------------------------------------------- typedef enum GMM_RESOURCE_FORMAT_ENUM { GMM_FORMAT_INVALID = 0, // <-- This stays zero! (For boolean and valid range checks.) #define GMM_FORMAT(Name, bpe, Width, Height, Depth, IsRT, IsASTC, RcsSurfaceFormat, SSCompressionFmt, Availability) \ GMM_FORMAT_##Name, \ GMM_FORMAT_##Name##_TYPE = GMM_FORMAT_##Name, // TODO(Minor): Remove _TYPE suffix from every GMM_FORMAT_ reference throughout driver and delete this aliasing. (And remove the \ from the line above.) #include "GmmFormatTable.h" GMM_RESOURCE_FORMATS } GMM_RESOURCE_FORMAT; C_ASSERT(GMM_FORMAT_INVALID == 0); // GMM_FORMAT_INVALID needs to stay zero--How did it end-up not...? // Legacy GMM Aliases... #define GMM_FORMAT_UYVY GMM_FORMAT_YCRCB_SWAPY #define GMM_FORMAT_VYUY GMM_FORMAT_YCRCB_SWAPUVY #define GMM_FORMAT_YUY2 GMM_FORMAT_YCRCB_NORMAL #define GMM_FORMAT_YVYU GMM_FORMAT_YCRCB_SWAPUV #define GMM_UNIFIED_CMF_INVALID 0xD //=========================================================================== // typedef: // GMM_SURFACESTATE_FORMAT // // Description: // Enumeration of RCS SURFACE_STATE.Formats. //--------------------------------------------------------------------------- typedef enum GMM_SURFACESTATE_FORMAT_ENUM { GMM_SURFACESTATE_FORMAT_INVALID = -1, // Can't use zero since that's an actual enum value. #define GMM_FORMAT_INCLUDE_SURFACESTATE_FORMATS_ONLY #define GMM_FORMAT(Name, bpe, Width, Height, Depth, IsRT, IsASTC, RcsSurfaceFormat, SSCompressionFmt, Availability) \ GMM_SURFACESTATE_FORMAT_##Name = RcsSurfaceFormat, #include "GmmFormatTable.h" } GMM_SURFACESTATE_FORMAT; typedef enum GMM_E2ECOMP_FORMAT_ENUM { GMM_E2ECOMP_FORMAT_INVALID = 0, GMM_E2ECOMP_FORMAT_ML8 = GMM_E2ECOMP_FORMAT_INVALID, GMM_E2ECOMP_FORMAT_RGB64, //1h - Reserved GMM_E2ECOMP_FORMAT_RGB32, //2h - Reserved GMM_E2ECOMP_MIN_FORMAT = GMM_E2ECOMP_FORMAT_RGB32, GMM_E2ECOMP_FORMAT_YUY2, //3h GMM_E2ECOMP_FORMAT_Y410, //4h GMM_E2ECOMP_FORMAT_Y210, //5h GMM_E2ECOMP_FORMAT_Y216 = GMM_E2ECOMP_FORMAT_Y210, GMM_E2ECOMP_FORMAT_Y416, //6h GMM_E2ECOMP_FORMAT_P010, //7h GMM_E2ECOMP_FORMAT_P010_L = GMM_E2ECOMP_FORMAT_P010, GMM_E2ECOMP_FORMAT_P010_C = GMM_E2ECOMP_FORMAT_P010, GMM_E2ECOMP_FORMAT_P016, //8h GMM_E2ECOMP_FORMAT_P016_L = GMM_E2ECOMP_FORMAT_P016, GMM_E2ECOMP_FORMAT_P016_C = GMM_E2ECOMP_FORMAT_P016, GMM_E2ECOMP_FORMAT_AYUV, //9h GMM_E2ECOMP_FORMAT_ARGB8b, //Ah GMM_E2ECOMP_FORMAT_RGB5A1 = GMM_E2ECOMP_FORMAT_ARGB8b, GMM_E2ECOMP_FORMAT_RGBA4 = GMM_E2ECOMP_FORMAT_ARGB8b, GMM_E2ECOMP_FORMAT_B5G6R5 = GMM_E2ECOMP_FORMAT_ARGB8b, GMM_E2ECOMP_FORMAT_SWAPY, //Bh GMM_E2ECOMP_FORMAT_SWAPUV, //Ch GMM_E2ECOMP_FORMAT_SWAPUVY, //Dh GMM_E2ECOMP_FORMAT_YCRCB_SWAPUV = GMM_E2ECOMP_FORMAT_SWAPY, GMM_E2ECOMP_FORMAT_YCRCB_SWAPUVY = GMM_E2ECOMP_FORMAT_SWAPUV, GMM_E2ECOMP_FORMAT_YCRCB_SWAPY = GMM_E2ECOMP_FORMAT_SWAPUVY, GMM_E2ECOMP_FORMAT_RGB10b, //Eh --Which media format is it? GMM_E2ECOMP_FORMAT_NV12, //Fh GMM_E2ECOMP_FORMAT_NV12_L = GMM_E2ECOMP_FORMAT_NV12, GMM_E2ECOMP_FORMAT_NV12_C = GMM_E2ECOMP_FORMAT_NV12, GMM_E2ECOMP_FORMAT_RGBAFLOAT16, //0x10h GMM_E2ECOMP_FORMAT_R32G32B32A32_FLOAT, //0x11h GMM_E2ECOMP_FORMAT_R32G32B32A32_SINT, //0x12h GMM_E2ECOMP_FORMAT_R32G32B32A32_UINT, //0x13h GMM_E2ECOMP_FORMAT_R16G16B16A16_UNORM, //0x14h GMM_E2ECOMP_FORMAT_R16G16B16A16_SNORM, //0x15h GMM_E2ECOMP_FORMAT_R16G16B16A16_SINT, //0x16h GMM_E2ECOMP_FORMAT_R16G16B16A16_UINT, //0x17h GMM_E2ECOMP_FORMAT_R10G10B10A2_UNORM, //0x18h GMM_E2ECOMP_FORMAT_RGB10A2 = GMM_E2ECOMP_FORMAT_R10G10B10A2_UNORM, GMM_E2ECOMP_FORMAT_R10G10B10FLOAT_A2_UNORM, //0x19h GMM_E2ECOMP_FORMAT_R10G10B10A2_UINT, //0x1Ah GMM_E2ECOMP_FORMAT_R8G8B8A8_SNORM, //0x1Bh GMM_E2ECOMP_FORMAT_R8G8B8A8_SINT, //0x1Ch GMM_E2ECOMP_FORMAT_R8G8B8A8_UINT, //0x1Dh GMM_E2ECOMP_FORMAT_R11G11B10_FLOAT, //0x1Eh GMM_E2ECOMP_FORMAT_RG11B10 = GMM_E2ECOMP_FORMAT_R11G11B10_FLOAT, GMM_E2ECOMP_MAX_FORMAT = GMM_E2ECOMP_FORMAT_R11G11B10_FLOAT, //should always be equal to last format encoding GMM_E2ECOMP_FORMAT_RGBA = GMM_E2ECOMP_FORMAT_INVALID, GMM_E2ECOMP_FORMAT_R = GMM_E2ECOMP_FORMAT_INVALID, GMM_E2ECOMP_FORMAT_RG = GMM_E2ECOMP_FORMAT_INVALID, GMM_E2ECOMP_FORMAT_D = GMM_E2ECOMP_FORMAT_INVALID, } GMM_E2ECOMP_FORMAT; //=========================================================================== // typedef: // GMM_TILE_WALK // // Description: // This enum details HW tile walk (i.e. X or Y walk), used to program the // hardware. //--------------------------------------------------------------------------- typedef enum GMM_TILE_WALK_REC { GMM_HW_TILED_X_WALK = 0, GMM_HW_TILED_Y_WALK = 1, GMM_HW_TILED_W_WALK = 2, GMM_HW_TILED_YF_WALK = 3, GMM_HW_TILED_YS_WALK = 4, GMM_HW_TILED_4_WALK = 5, GMM_HW_TILED_64_WALK = 6, GMM_HW_NOT_TILED = 7 } GMM_TILE_WALK; //=========================================================================== // typedef: // GMM_DISPLAY_FRAME_ENUM // // Description: // This enum details the type of display frame (for S3D resources). //--------------------------------------------------------------------------- typedef enum GMM_DISPLAY_FRAME_ENUM { GMM_DISPLAY_BASE = 0, // Legacy non-S3D display resource GMM_DISPLAY_L = GMM_DISPLAY_BASE, GMM_DISPLAY_R = 1, GMM_DISPLAY_BLANK_AREA = 2, GMM_DISPLAY_FRAME_MAX } GMM_DISPLAY_FRAME; //=========================================================================== // typedef: // GMM_REQ_OFFSET_INFO // // Description: // This structure is used to request offset information to a surface mip // level or video plane. //--------------------------------------------------------------------------- typedef struct GMM_REQ_OFFSET_INFO_REC { uint32_t ReqRender :1; uint32_t ReqLock :1; uint32_t ReqStdLayout :1; uint32_t Reserved :29; uint32_t ArrayIndex; uint32_t MipLevel; uint32_t Slice; GMM_CUBE_FACE_ENUM CubeFace; GMM_YUV_PLANE Plane; GMM_DISPLAY_FRAME Frame; struct { union { uint32_t Offset; GMM_GFX_SIZE_T Offset64; }; uint32_t Pitch; union { uint32_t Mip0SlicePitch; uint32_t Gen9PlusSlicePitch; }; } Lock; struct { union { uint32_t Offset; GMM_GFX_SIZE_T Offset64; }; uint32_t XOffset; uint32_t YOffset; uint32_t ZOffset; } Render; struct { GMM_GFX_SIZE_T Offset; GMM_GFX_SIZE_T TileRowPitch; GMM_GFX_SIZE_T TileDepthPitch; } StdLayout; }GMM_REQ_OFFSET_INFO; //=========================================================================== // typedef: // GMM_HW_COMMAND_STREAMER // // Description: Enumeration to allow callers to specify a command streamer. // //--------------------------------------------------------------------------- typedef enum GMM_HW_COMMAND_STREAMER_ENUM { GMM_HW_COMMAND_STREAMER_NULL = 0, // <-- This stays zero. GMM_CS, // Render Command Streamer GMM_BCS, // Blitter (BLT) Command Streamer GMM_VCS, // Video Codec (MFX) Command Streamer GMM_VECS, // Video Enhancement (VEBOX) Command Streamer GMM_VCS2, // Video Codec (MFX) Command Streamer 2 GMM_COMPUTE, // Compute Only Command Streamer GMM_PICS, // Pinning Command Streamer GMM_CAPTURE, // Capture Command Streamer GMM_HW_COMMAND_STREAMERS // <-- This stays last. } GMM_HW_COMMAND_STREAMER; // Reset packing alignment to project default #pragma pack(pop) //=========================================================================== // typedef: // GMM_RESOURCE_TYPE // // Description: // This enum describe type of resource requested //--------------------------------------------------------------------------- typedef enum GMM_RESOURCE_TYPE_ENUM { RESOURCE_INVALID, // User-mode use RESOURCE_1D, RESOURCE_2D, RESOURCE_3D, RESOURCE_CUBE, RESOURCE_SCRATCH, RESOURCE_BUFFER, //Kernel-mode use only RESOURCE_KMD_CHECK_START, RESOURCE_PRIMARY, RESOURCE_SHADOW, RESOURCE_STAGING, RESOURCE_CURSOR, RESOURCE_FBC, RESOURCE_PWR_CONTEXT, RESOURCE_PERF_DATA_QUEUE, RESOURCE_KMD_BUFFER, RESOURCE_HW_CONTEXT, RESOURCE_TAG_PAGE, RESOURCE_NNDI, RESOURCE_HARDWARE_MBM, RESOURCE_OVERLAY_DMA, RESOURCE_OVERLAY_INTERMEDIATE_SURFACE, RESOURCE_GTT_TRANSFER_REGION, RESOURCE_GLOBAL_BUFFER, RESOURCE_GDI, RESOURCE_NULL_CONTEXT_INDIRECT_STATE, RESOURCE_GFX_CLIENT_BUFFER, RESOURCE_KMD_CHECK_END, RESOURCE_SEGMENT, RESOURCE_IFFS_MAPTOGTT, #if _WIN32 RESOURCE_WGBOX_ENCODE_STATE, RESOURCE_WGBOX_ENCODE_DISPLAY, RESOURCE_WGBOX_ENCODE_REFERENCE, RESOURCE_WGBOX_ENCODE_TFD, #endif // only used for allocation of context specific SVM Present kernels buffer RESOURCE_SVM_KERNELS_BUFFER, GMM_MAX_HW_RESOURCE_TYPE } GMM_RESOURCE_TYPE; gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/inc/External/Common/GmmConst.h000066400000000000000000000066111466655022700255420ustar00rootroot00000000000000/*============================================================================== Copyright(c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ============================================================================*/ #pragma once //------------------------------------------------------------------------ // Texture Values //------------------------------------------------------------------------ #define __GMM_MIN_TEXTURE_WIDTH 0x1 #define __GMM_EVEN_ROW 0x2 #define __GMM_LINEAR_RENDER_ALIGNMENT 0x4 // need DWORD aligned #define __GMM_8BPP_LINEAR_RENDER_ALIGNMENT 0x8 // need QWORD aligned (HW workaround) #define GMM_IMCx_PLANE_ROW_ALIGNMENT 16 //------------------------------------------------------------------------ // Misc //------------------------------------------------------------------------ #define GMM_MDL_PAGE_SHIFT 12 // Size of bit-shift to convert btween MDL page NUMBER and page ADDRESS. #define GMM_FIELD_NA 0xFFFFFFFF #define GMM_INTERNAL_RESOURCE 0 // Used for Alloc Tag Mapping #define GMM_MAX_NUMBER_MOCS_INDEXES (64) #define GMM_XE_NUM_MOCS_ENTRIES (16) #define GMM_GEN9_MAX_NUMBER_MOCS_INDEXES (62) // On SKL there are 64 MOCS indexes, but the last two are reserved by h/w. #define GMM_XE2_NUM_MOCS_ENTRIES (16) #define GMM_NUM_PAT_ENTRIES_LEGACY (8) #define GMM_NUM_PAT_ENTRIES (32) #define GMM_NUM_MEMORY_TYPES 4 #define GMM_NUM_GFX_PAT_TYPES 6 #define GMM_TILED_RESOURCE_NO_MIP_TAIL 0xF #define GMM_TILED_RESOURCE_NO_PACKED_MIPS 0xF #define GMM_GEN10_HDCL1_MOCS_INDEX_START (48) // CNL+ MOCS index 48-61 allows HDC L1 caching, last 2 are reserved by h/w. #define GMM_MSAA_SAMPLES_MIN 1 //Define min and max MSAA samples #define GMM_MSAA_SAMPLES_MAX 16 #define GMM_HIZ_CLEAR_COLOR_SIZE (8) #define GMM_MEDIA_COMPRESSION_STATE_SIZE (64) #define GMM_CLEAR_COLOR_FLOAT_SIZE (16) #define GMM_MAX_LCU_SIZE 64 // Media Largest coding Unit gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/inc/External/Common/GmmDebug.h000066400000000000000000000161261466655022700255040ustar00rootroot00000000000000/*============================================================================== Copyright(c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ============================================================================*/ #pragma once // ------------------------------------------------------------------------ // This block determines where GMM gets definitions for debug assert and // print functions. Location differs depending who is linking GMM lib. // ------------------------------------------------------------------------ #if ( __GMM_KMD__ || GMM_OCL) #include "../../Common/AssertTracer/AssertTracer.h" #include "../../util/gfxDebug.h" #else #include "GmmCommonExt.h" #include "GmmLog/GmmLog.h" //===================== Debug Message Levels======================== #define GFXDBG_OFF (0x00000000) #define GFXDBG_CRITICAL (0x00000001) #define GFXDBG_NORMAL (0x00000002) #define GFXDBG_VERBOSE (0x00000004) #define GFXDBG_FUNCTION (0x80000000) #define GFXDBG_NONCRITICAL (0x00000010) #define GFXDBG_CRITICAL_DEBUG (0x00000020) #define GFXDBG_VERBOSE_VERBOSITY (0x00000040) #define GFXDBG_PROTOCAL (0x00000100) #define GFXDBG_FUNCTION_ENTRY (0x80000000) #define GFXDBG_FUNCTION_EXIT (0x80000000) #define GFXDBG_FUNCTION_ENTRY_VERBOSE (0x20000000) #define GFXDBG_FUNCTION_EXIT_VERBOSE (0x20000000) #define VOIDRETURN #endif #if (__GMM_KMD__ || GMM_OCL) #if defined (GMM_OCL) #include "../../3d/common/iStdLib/osinlines.h" #endif // Enable GMM_ASSERTS and GMM_DEBUG only for Debug builds similar to what UMD clients used to do earlier #if (_DEBUG) //(_DEBUG || _RELEASE_INTERNAL) #define GMM_ASSERT GMMASSERT //gfxDebug.h #define GMM_ASSERTPTR GMMASSERTPTR //gfxDebug.h #else #define GMMDebugMessage(...) #define GMM_ASSERT(expr) #define GMM_ASSERTPTR(expr, ret) #endif // GMM_DPF Logging is enabled for Debug and Release_Internal #if (_DEBUG || _RELEASE_INTERNAL) #define GMM_DPF GMMDebugMessage //gfxDebug.h #else #define GMM_DPF GMMDebugMessage #endif // (_DEBUG || _RELEASE_INTERNAL) #define __GMM_ASSERT GMM_ASSERT #define __GMM_ASSERTPTR GMM_ASSERTPTR #else // Enable GMM_ASSERTS and GMM_DEBUG only for Debug builds similar to what UMD clients used to do earlier #if (_DEBUG) //(_DEBUG || _RELEASE_INTERNAL) #if defined(_MSC_VER) #define GMM_DBG_BREAK __debugbreak() #elif defined(__GNUC__) #define GMM_DBG_BREAK __builtin_trap() #else #include #define GMM_DBG_BREAK assert(0) #endif #define GMM_LIB_ASSERT(expr) \ { \ if(!(expr) ) \ { \ GMM_DBG_BREAK; \ } \ } #define GMM_LIB_ASSERTPTR(expr, ret) \ { \ GMM_LIB_ASSERT(expr); \ if( !expr ) \ { \ return ret; \ } \ } #else #define GMM_LIB_ASSERT(expr) #define GMM_LIB_ASSERTPTR(expr, ret) \ { \ if (!expr) \ { \ return ret; \ } \ } \ #endif // (_DEBUG) //_DEBUG || _RELEASE_INTERNAL #if (_DEBUG || _RELEASE_INTERNAL) #define GMMLibDebugMessage(DebugLevel, message, ...) \ { \ if(DebugLevel == GFXDBG_CRITICAL) \ { \ GMM_LOG_ERROR(message, ##__VA_ARGS__); \ } \ else if(DebugLevel == GFXDBG_VERBOSE) \ { \ GMM_LOG_TRACE(message, ##__VA_ARGS__); \ } \ else if(DebugLevel == GFXDBG_OFF) \ { \ GMM_LOG_TRACE_IF(0, message, ##__VA_ARGS__) \ } \ else \ { \ GMM_LOG_INFO(message, ##__VA_ARGS__); \ } \ } #else #define GMMLibDebugMessage(...) #endif //_DEBUG || _RELEASE_INTERNAL #define GMM_DPF GMMLibDebugMessage #define __GMM_ASSERT GMM_LIB_ASSERT #define __GMM_ASSERTPTR GMM_LIB_ASSERTPTR #endif // ------------------------------------------------------------------------ // This block defines various debug print macros // ------------------------------------------------------------------------ #define GMM_DPF_ENTER \ GMM_DPF(GFXDBG_FUNCTION_ENTRY, "%s-->\n", __FUNCTION__); #define GMM_DPF_EXIT \ GMM_DPF(GFXDBG_FUNCTION_EXIT, "%s<--\n", __FUNCTION__); #define GMM_DPF_CRITICAL(Message) \ GMM_DPF(GFXDBG_CRITICAL, "%s:%d: %s\n", __FUNCTION__, __LINE__, (Message)); #ifndef GMM_ASSERTDPF #define GMM_ASSERTDPF(Expression, Message) \ { \ if (!(Expression)) \ { \ GMM_DPF_CRITICAL(Message); \ __GMM_ASSERT(0); \ } \ } #endif gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/inc/External/Common/GmmFormatTable.h000066400000000000000000001525101466655022700266540ustar00rootroot00000000000000/*============================================================================== Copyright(c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ============================================================================*/ // #pragma once <-- Don't use with this file! (Multi-inclusions, differnt uses.) // Format Group Selection... #if(defined(GMM_FORMAT_INCLUDE_ASTC_FORMATS_ONLY)) #define INCLUDE_ASTC_FORMATS #elif(defined(GMM_FORMAT_INCLUDE_SURFACESTATE_FORMATS_ONLY)) #define INCLUDE_SURFACESTATE_FORMATS #else #define INCLUDE_ASTC_FORMATS #define INCLUDE_MISC_FORMATS #define INCLUDE_SURFACESTATE_FORMATS #endif // Table Macros (for Readability) #define A 1 #define ALWAYS 1 #define ASTC_3D SKU(FtrAstc3D) #define ASTC_HDR_2D SKU(FtrAstcHdr2D) #define ASTC_LDR_2D SKU(FtrAstcLdr2D) #define GEN GMM_FORMAT_GEN #define NA GMM_SURFACESTATE_FORMAT_INVALID #define R 1 #define SKU GMM_FORMAT_SKU #define VLV2 GFX_IS_PRODUCT(Data.Platform,IGFX_VALLEYVIEW) #define WA GMM_FORMAT_WA #define x 0 #if(!defined(__GMM_KMD__)) #define NC GMM_COMPR_FORMAT_INVALID(pGmmLibContext) #else #define NC GMM_COMPR_FORMAT_INVALID #endif #define MC(n) n | (0x1 << 5) //GMM_FLATCCS_MIN_MC_FORMAT - 1 #define FC(ver, bpc, fmtstr, bpcstr, typestr) \ (ver == 1 || (SKU(FtrE2ECompression) && !(SKU(FtrFlatPhysCCS) || SKU(FtrUnified3DMediaCompressionFormats) || SKU(FtrXe2Compression)))) ? \ ((bpc == 16) ? GMM_E2ECOMP_FORMAT_RGBAFLOAT16 : \ (bpc == 32) ? GMM_E2ECOMP_FORMAT_R32G32B32A32_FLOAT : \ (bpc == 8) ? GMM_E2ECOMP_FORMAT_ARGB8b : \ (bpc == x) ? GMM_E2ECOMP_FORMAT_##fmtstr : \ NC) : \ (ver == 2 || (SKU(FtrFlatPhysCCS) && !(SKU(FtrUnified3DMediaCompressionFormats) || SKU(FtrXe2Compression)))) ? \ (GMM_FLATCCS_FORMAT_##fmtstr##bpcstr##typestr) : \ (ver == 3 || (SKU(FtrUnified3DMediaCompressionFormats) && !SKU(FtrXe2Compression))) ? \ (GMM_UNIFIED_COMP_FORMAT_##fmtstr##bpcstr##typestr) : \ (ver == 4 || SKU(FtrXe2Compression)) ? \ (GMM_XE2_UNIFIED_COMP_FORMAT_##fmtstr##bpcstr##typestr) : \ NC /****************************************************************************\ GMM FORMAT TABLE (See bottom of file for more info.) Supported (ALWAYS / *) -----------------------------------------------------------------o SURFACE_STATE.CompressionFormat (or NC) --------------------------------------o | RCS SURFACE_STATE.Format (or NA) --------------------------------o | | ASTC Format (A / x) ----------------------------------------o | | | Render Target Eligibility (R / x / *) -------------------o | | | | Element Depth (Pixels) -------------------------------o | | | | | Element Height (Pixels) ---------------------------o | | | | | | Element Width (Pixels) ------------------------o | | | | | | | Bits-per-Element -------------------------o | | | | | | | | | | | | | | | | | Name bpe w h d R A RCS.SS CompressFormat Available ------------------------------------------------------------------------------------------*/ #ifdef INCLUDE_SURFACESTATE_FORMATS GMM_FORMAT( A1B5G5R5_UNORM , 16, 1, 1, 1, R, x, 0x124, FC(4, x, RGB5A1, , ), GEN(8) || VLV2 ) GMM_FORMAT( A4B4G4R4_UNORM , 16, 1, 1, 1, R, x, 0x125, FC(4, x, RGB5A1, , ), GEN(8) ) GMM_FORMAT( A4P4_UNORM_PALETTE0 , 8, 1, 1, 1, R, x, 0x148, NC , ALWAYS ) GMM_FORMAT( A4P4_UNORM_PALETTE1 , 8, 1, 1, 1, R, x, 0x14F, NC , ALWAYS ) GMM_FORMAT( A8_UNORM , 8, 1, 1, 1, R, x, 0x144, FC(4, 8, R, 8, U), GEN(7) ) GMM_FORMAT( A8P8_UNORM_PALETTE0 , 16, 1, 1, 1, R, x, 0x10F, NC , ALWAYS ) GMM_FORMAT( A8P8_UNORM_PALETTE1 , 16, 1, 1, 1, R, x, 0x110, NC , ALWAYS ) GMM_FORMAT( A8X8_UNORM_G8R8_SNORM , 32, 1, 1, 1, R, x, 0x0E7, NC , ALWAYS ) GMM_FORMAT( A16_FLOAT , 16, 1, 1, 1, R, x, 0x117, NC , GEN(7) ) GMM_FORMAT( A16_UNORM , 16, 1, 1, 1, R, x, 0x113, NC , GEN(7) ) GMM_FORMAT( A24X8_UNORM , 32, 1, 1, 1, R, x, 0x0E2, NC , GEN(7) ) GMM_FORMAT( A32_FLOAT , 32, 1, 1, 1, R, x, 0x0E5, NC , GEN(7) ) GMM_FORMAT( A32_UNORM , 32, 1, 1, 1, R, x, 0x0DE, NC , GEN(7) ) GMM_FORMAT( A32X32_FLOAT , 64, 1, 1, 1, R, x, 0x090, NC , ALWAYS ) GMM_FORMAT( B4G4R4A4_UNORM , 16, 1, 1, 1, R, x, 0x104, FC(4, x, RGBA4, , ), ALWAYS ) GMM_FORMAT( B4G4R4A4_UNORM_SRGB , 16, 1, 1, 1, R, x, 0x105, FC(4, x, RGBA4, , ), ALWAYS ) GMM_FORMAT( B5G5R5A1_UNORM , 16, 1, 1, 1, R, x, 0x102, FC(4, x, RGB5A1, , ), ALWAYS ) GMM_FORMAT( B5G5R5A1_UNORM_SRGB , 16, 1, 1, 1, R, x, 0x103, FC(4, x, RGB5A1, , ), ALWAYS ) GMM_FORMAT( B5G5R5X1_UNORM , 16, 1, 1, 1, R, x, 0x11A, FC(4, x, RGB5A1, , ), ALWAYS ) GMM_FORMAT( B5G5R5X1_UNORM_SRGB , 16, 1, 1, 1, R, x, 0x11B, FC(4, x, RGB5A1, , ), ALWAYS ) GMM_FORMAT( B5G6R5_UNORM , 16, 1, 1, 1, R, x, 0x100, FC(4, x, B5G6R5, , ), ALWAYS ) GMM_FORMAT( B5G6R5_UNORM_SRGB , 16, 1, 1, 1, R, x, 0x101, FC(4, x, B5G6R5, , ), ALWAYS ) GMM_FORMAT( B8G8R8A8_UNORM , 32, 1, 1, 1, R, x, 0x0C0, FC(4, 8, RGBA, 8, U), ALWAYS ) GMM_FORMAT( B8G8R8A8_UNORM_SRGB , 32, 1, 1, 1, R, x, 0x0C1, FC(4, 8, RGBA, 8, U), ALWAYS ) GMM_FORMAT( B8G8R8X8_UNORM , 32, 1, 1, 1, R, x, 0x0E9, FC(4, 8, RGBA, 8, U), ALWAYS ) GMM_FORMAT( B8G8R8X8_UNORM_SRGB , 32, 1, 1, 1, R, x, 0x0EA, FC(4, 8, RGBA, 8, U), ALWAYS ) GMM_FORMAT( B8X8_UNORM_G8R8_SNORM , 32, 1, 1, 1, R, x, 0x0E8, NC , ALWAYS ) GMM_FORMAT( B10G10R10A2_SINT , 32, 1, 1, 1, R, x, 0x1BB, FC(4, x, RGB10A2, , ), GEN(8) ) GMM_FORMAT( B10G10R10A2_SNORM , 32, 1, 1, 1, R, x, 0x1B7, FC(4, x, RGB10A2, , ), GEN(8) ) GMM_FORMAT( B10G10R10A2_SSCALED , 32, 1, 1, 1, R, x, 0x1B9, FC(4, x, RGB10A2, , ), GEN(8) ) GMM_FORMAT( B10G10R10A2_UINT , 32, 1, 1, 1, R, x, 0x1BA, FC(4, x, RGB10A2, , ), GEN(8) ) GMM_FORMAT( B10G10R10A2_UNORM , 32, 1, 1, 1, R, x, 0x0D1, FC(4, x, RGB10A2, , ), ALWAYS ) GMM_FORMAT( B10G10R10A2_UNORM_SRGB , 32, 1, 1, 1, R, x, 0x0D2, FC(4, x, RGB10A2, , ), ALWAYS ) GMM_FORMAT( B10G10R10A2_USCALED , 32, 1, 1, 1, R, x, 0x1B8, FC(4, x, RGB10A2, , ), GEN(8) ) GMM_FORMAT( B10G10R10X2_UNORM , 32, 1, 1, 1, R, x, 0x0EE, FC(4, x, RGB10A2, , ), ALWAYS ) GMM_FORMAT( BC1_UNORM , 64, 4, 4, 1, x, x, 0x186, FC(4, x, ML8, , ), ALWAYS ) GMM_FORMAT( BC1_UNORM_SRGB , 64, 4, 4, 1, x, x, 0x18B, FC(4, x, ML8, , ), ALWAYS ) GMM_FORMAT( BC2_UNORM , 128, 4, 4, 1, x, x, 0x187, FC(4, x, ML8, , ), ALWAYS ) GMM_FORMAT( BC2_UNORM_SRGB , 128, 4, 4, 1, x, x, 0x18C, FC(4, x, ML8, , ), ALWAYS ) GMM_FORMAT( BC3_UNORM , 128, 4, 4, 1, x, x, 0x188, FC(4, x, ML8, , ), ALWAYS ) GMM_FORMAT( BC3_UNORM_SRGB , 128, 4, 4, 1, x, x, 0x18D, FC(4, x, ML8, , ), ALWAYS ) GMM_FORMAT( BC4_SNORM , 64, 4, 4, 1, x, x, 0x199, FC(4, x, ML8, , ), ALWAYS ) GMM_FORMAT( BC4_UNORM , 64, 4, 4, 1, x, x, 0x189, FC(4, x, ML8, , ), ALWAYS ) GMM_FORMAT( BC5_SNORM , 128, 4, 4, 1, x, x, 0x19A, FC(4, x, ML8, , ), ALWAYS ) GMM_FORMAT( BC5_UNORM , 128, 4, 4, 1, x, x, 0x18A, FC(4, x, ML8, , ), ALWAYS ) GMM_FORMAT( BC6H_SF16 , 128, 4, 4, 1, x, x, 0x1A1, FC(4, x, ML8, , ), GEN(7) ) GMM_FORMAT( BC6H_UF16 , 128, 4, 4, 1, x, x, 0x1A4, FC(4, x, ML8, , ), GEN(7) ) GMM_FORMAT( BC7_UNORM , 128, 4, 4, 1, x, x, 0x1A2, FC(4, x, ML8, , ), GEN(7) ) GMM_FORMAT( BC7_UNORM_SRGB , 128, 4, 4, 1, x, x, 0x1A3, FC(4, x, ML8, , ), GEN(7) ) GMM_FORMAT( DXT1_RGB , 64, 4, 4, 1, x, x, 0x191, NC , ALWAYS ) // verify for ML8 GMM_FORMAT( DXT1_RGB_SRGB , 64, 4, 4, 1, x, x, 0x180, NC , ALWAYS ) // verify for ML8 GMM_FORMAT( EAC_R11 , 64, 4, 4, 1, x, x, 0x1AB, FC(4, x, ML8, , ), GEN(8) || VLV2 ) GMM_FORMAT( EAC_RG11 , 128, 4, 4, 1, x, x, 0x1AC, FC(4, x, ML8, , ), GEN(8) || VLV2 ) GMM_FORMAT( EAC_SIGNED_R11 , 64, 4, 4, 1, x, x, 0x1AD, FC(4, x, ML8, , ), GEN(8) || VLV2 ) GMM_FORMAT( EAC_SIGNED_RG11 , 128, 4, 4, 1, x, x, 0x1AE, FC(4, x, ML8, , ), GEN(8) || VLV2 ) GMM_FORMAT( ETC1_RGB8 , 64, 4, 4, 1, x, x, 0x1A9, FC(4, x, ML8, , ), GEN(8) || VLV2 ) GMM_FORMAT( ETC2_EAC_RGBA8 , 128, 4, 4, 1, x, x, 0x1C2, FC(4, x, ML8, , ), GEN(8) || VLV2 ) GMM_FORMAT( ETC2_EAC_SRGB8_A8 , 128, 4, 4, 1, x, x, 0x1C3, FC(4, x, ML8, , ), GEN(8) || VLV2 ) GMM_FORMAT( ETC2_RGB8 , 64, 4, 4, 1, x, x, 0x1AA, FC(4, x, ML8, , ), GEN(8) || VLV2 ) GMM_FORMAT( ETC2_RGB8_PTA , 64, 4, 4, 1, x, x, 0x1C0, FC(4, x, ML8, , ), GEN(8) || VLV2 ) GMM_FORMAT( ETC2_SRGB8 , 64, 4, 4, 1, x, x, 0x1AF, FC(4, x, ML8, , ), GEN(8) || VLV2 ) GMM_FORMAT( ETC2_SRGB8_PTA , 64, 4, 4, 1, x, x, 0x1C1, FC(4, x, ML8, , ), GEN(8) || VLV2 ) GMM_FORMAT( FXT1 , 128, 8, 4, 1, x, x, 0x192, NC , ALWAYS ) GMM_FORMAT( I8_SINT , 8, 1, 1, 1, R, x, 0x155, NC , GEN(9) ) GMM_FORMAT( I8_UINT , 8, 1, 1, 1, R, x, 0x154, NC , GEN(9) ) GMM_FORMAT( I8_UNORM , 8, 1, 1, 1, R, x, 0x145, NC , ALWAYS ) GMM_FORMAT( I16_FLOAT , 16, 1, 1, 1, R, x, 0x115, NC , ALWAYS ) GMM_FORMAT( I16_UNORM , 16, 1, 1, 1, R, x, 0x111, NC , ALWAYS ) GMM_FORMAT( I24X8_UNORM , 32, 1, 1, 1, R, x, 0x0E0, NC , ALWAYS ) GMM_FORMAT( I32_FLOAT , 32, 1, 1, 1, R, x, 0x0E3, NC , ALWAYS ) GMM_FORMAT( I32X32_FLOAT , 64, 1, 1, 1, R, x, 0x092, NC , ALWAYS ) GMM_FORMAT( L8_SINT , 8, 1, 1, 1, R, x, 0x153, NC , GEN(9) ) GMM_FORMAT( L8_UINT , 8, 1, 1, 1, R, x, 0x152, NC , GEN(9) ) GMM_FORMAT( L8_UNORM , 8, 1, 1, 1, R, x, 0x146, NC , ALWAYS ) GMM_FORMAT( L8_UNORM_SRGB , 8, 1, 1, 1, R, x, 0x14C, NC , ALWAYS ) GMM_FORMAT( L8A8_SINT , 16, 1, 1, 1, R, x, 0x127, NC , GEN(9) ) GMM_FORMAT( L8A8_UINT , 16, 1, 1, 1, R, x, 0x126, NC , GEN(9) ) GMM_FORMAT( L8A8_UNORM , 16, 1, 1, 1, R, x, 0x114, NC , ALWAYS ) GMM_FORMAT( L8A8_UNORM_SRGB , 16, 1, 1, 1, R, x, 0x118, NC , ALWAYS ) GMM_FORMAT( L16_FLOAT , 16, 1, 1, 1, R, x, 0x116, NC , ALWAYS ) GMM_FORMAT( L16_UNORM , 16, 1, 1, 1, R, x, 0x112, NC , ALWAYS ) GMM_FORMAT( L16A16_FLOAT , 32, 1, 1, 1, R, x, 0x0F0, NC , ALWAYS ) GMM_FORMAT( L16A16_UNORM , 32, 1, 1, 1, R, x, 0x0DF, NC , ALWAYS ) GMM_FORMAT( L24X8_UNORM , 32, 1, 1, 1, R, x, 0x0E1, NC , ALWAYS ) GMM_FORMAT( L32_FLOAT , 32, 1, 1, 1, R, x, 0x0E4, NC , ALWAYS ) GMM_FORMAT( L32_UNORM , 32, 1, 1, 1, R, x, 0x0DD, NC , ALWAYS ) GMM_FORMAT( L32A32_FLOAT , 64, 1, 1, 1, R, x, 0x08A, NC , ALWAYS ) GMM_FORMAT( L32X32_FLOAT , 64, 1, 1, 1, R, x, 0x091, NC , ALWAYS ) GMM_FORMAT( MONO8 , 1, 1, 1, 1, R, x, 0x18E, NC , x ) // No current GMM support by this name. GMM_FORMAT( P2_UNORM_PALETTE0 , 2, 1, 1, 1, R, x, 0x184, NC , x ) // No current GMM support by this name. GMM_FORMAT( P2_UNORM_PALETTE1 , 2, 1, 1, 1, R, x, 0x185, NC , x ) // " GMM_FORMAT( P4A4_UNORM_PALETTE0 , 8, 1, 1, 1, R, x, 0x147, NC , ALWAYS ) GMM_FORMAT( P4A4_UNORM_PALETTE1 , 8, 1, 1, 1, R, x, 0x14E, NC , ALWAYS ) GMM_FORMAT( P8_UNORM_PALETTE0 , 8, 1, 1, 1, R, x, 0x14B, NC , ALWAYS ) GMM_FORMAT( P8_UNORM_PALETTE1 , 8, 1, 1, 1, R, x, 0x14D, NC , ALWAYS ) GMM_FORMAT( P8A8_UNORM_PALETTE0 , 16, 1, 1, 1, R, x, 0x122, NC , ALWAYS ) GMM_FORMAT( P8A8_UNORM_PALETTE1 , 16, 1, 1, 1, R, x, 0x123, NC , ALWAYS ) GMM_FORMAT( PACKED_422_16 , 64, 2, 1, 1, R, x, 0x1A7, NC , GEN(12) ) GMM_FORMAT( PLANAR_420_8 , 8, 1, 1, 1, R, x, 0x1A5, NC , x ) // No current GMM support by this name. GMM_FORMAT( PLANAR_420_16 , 16, 1, 1, 1, R, x, 0x1A6, NC , x ) // " GMM_FORMAT( PLANAR_422_8 , 8, 1, 1, 1, R, x, 0x00F, NC , x ) // <-- TODO(Minor): Remove this HW-internal format. GMM_FORMAT( R1_UNORM , 1, 1, 1, 1, R, x, 0x181, NC , x ) // " GMM_FORMAT( R8_SINT , 8, 1, 1, 1, R, x, 0x142, FC(4, 8, R, 8, S1), ALWAYS ) GMM_FORMAT( R8_SNORM , 8, 1, 1, 1, R, x, 0x141, FC(4, 8, R, 8, S), ALWAYS ) GMM_FORMAT( R8_SSCALED , 8, 1, 1, 1, R, x, 0x149, FC(4, 8, R, 8, S), ALWAYS ) GMM_FORMAT( R8_UINT , 8, 1, 1, 1, R, x, 0x143, FC(4, 8, R, 8, U1), ALWAYS ) GMM_FORMAT( R8_UNORM , 8, 1, 1, 1, R, x, 0x140, FC(4, 8, R, 8, U), ALWAYS ) GMM_FORMAT( R8_USCALED , 8, 1, 1, 1, R, x, 0x14A, FC(4, 8, R, 8, U), ALWAYS ) GMM_FORMAT( R8G8_SINT , 16, 1, 1, 1, R, x, 0x108, FC(4, 8, RG, 8, S), ALWAYS ) GMM_FORMAT( R8G8_SNORM , 16, 1, 1, 1, R, x, 0x107, FC(4, 8, RG, 8, S), ALWAYS ) GMM_FORMAT( R8G8_SSCALED , 16, 1, 1, 1, R, x, 0x11C, FC(4, 8, RG, 8, S), ALWAYS ) GMM_FORMAT( R8G8_UINT , 16, 1, 1, 1, R, x, 0x109, FC(4, 8, RG, 8, U), ALWAYS ) GMM_FORMAT( R8G8_UNORM , 16, 1, 1, 1, R, x, 0x106, FC(4, 8, RG, 8, U), ALWAYS ) GMM_FORMAT( R8G8_USCALED , 16, 1, 1, 1, R, x, 0x11D, FC(4, 8, RG, 8, U), ALWAYS ) GMM_FORMAT( R8G8B8_SINT , 24, 1, 1, 1, R, x, 0x1C9, NC , GEN(8) ) GMM_FORMAT( R8G8B8_SNORM , 24, 1, 1, 1, R, x, 0x194, NC , ALWAYS ) GMM_FORMAT( R8G8B8_SSCALED , 24, 1, 1, 1, R, x, 0x195, NC , ALWAYS ) GMM_FORMAT( R8G8B8_UINT , 24, 1, 1, 1, R, x, 0x1C8, NC , GEN(8) || VLV2 ) GMM_FORMAT( R8G8B8_UNORM , 24, 1, 1, 1, R, x, 0x193, NC , ALWAYS ) GMM_FORMAT( R8G8B8_UNORM_SRGB , 24, 1, 1, 1, R, x, 0x1A8, NC , GEN(7_5) ) GMM_FORMAT( R8G8B8_USCALED , 24, 1, 1, 1, R, x, 0x196, NC , ALWAYS ) GMM_FORMAT( R8G8B8A8_SINT , 32, 1, 1, 1, R, x, 0x0CA, FC(4, 8, RGBA, 8, S), ALWAYS ) GMM_FORMAT( R8G8B8A8_SNORM , 32, 1, 1, 1, R, x, 0x0C9, FC(4, 8, RGBA, 8, S), ALWAYS ) GMM_FORMAT( R8G8B8A8_SSCALED , 32, 1, 1, 1, R, x, 0x0F4, FC(4, 8, RGBA, 8, S), ALWAYS ) GMM_FORMAT( R8G8B8A8_UINT , 32, 1, 1, 1, R, x, 0x0CB, FC(4, 8, RGBA, 8, U), ALWAYS ) GMM_FORMAT( R8G8B8A8_UNORM , 32, 1, 1, 1, R, x, 0x0C7, FC(4, 8, RGBA, 8, U), ALWAYS ) GMM_FORMAT( R8G8B8A8_UNORM_SRGB , 32, 1, 1, 1, R, x, 0x0C8, FC(4, 8, RGBA, 8, U), ALWAYS ) GMM_FORMAT( R8G8B8A8_USCALED , 32, 1, 1, 1, R, x, 0x0F5, FC(4, 8, RGBA, 8, U), ALWAYS ) GMM_FORMAT( R8G8B8X8_UNORM , 32, 1, 1, 1, R, x, 0x0EB, FC(4, 8, RGBA, 8, U), ALWAYS ) GMM_FORMAT( R8G8B8X8_UNORM_SRGB , 32, 1, 1, 1, R, x, 0x0EC, FC(4, 8, RGBA, 8, U), ALWAYS ) GMM_FORMAT( R9G9B9E5_SHAREDEXP , 32, 1, 1, 1, R, x, 0x0ED, NC , ALWAYS ) GMM_FORMAT( R10G10B10_FLOAT_A2_UNORM , 32, 1, 1, 1, R, x, 0x0D5, FC(4, x, RGB10A2, , ), GEN(12) ) GMM_FORMAT( R10G10B10_SNORM_A2_UNORM , 32, 1, 1, 1, R, x, 0x0C5, FC(4, x, RGB10A2, , ), ALWAYS ) GMM_FORMAT( R10G10B10A2_SINT , 32, 1, 1, 1, R, x, 0x1B6, FC(4, x, RGB10A2, , ), GEN(8) ) GMM_FORMAT( R10G10B10A2_SNORM , 32, 1, 1, 1, R, x, 0x1B3, FC(4, x, RGB10A2, , ), GEN(8) ) GMM_FORMAT( R10G10B10A2_SSCALED , 32, 1, 1, 1, R, x, 0x1B5, FC(4, x, RGB10A2, , ), GEN(8) ) GMM_FORMAT( R10G10B10A2_UINT , 32, 1, 1, 1, R, x, 0x0C4, FC(4, x, RGB10A2, , ), ALWAYS ) GMM_FORMAT( R10G10B10A2_UNORM , 32, 1, 1, 1, R, x, 0x0C2, FC(4, x, RGB10A2, , ), ALWAYS ) GMM_FORMAT( R10G10B10A2_UNORM_SRGB , 32, 1, 1, 1, R, x, 0x0C3, FC(4, x, RGB10A2, , ), ALWAYS ) GMM_FORMAT( R10G10B10A2_USCALED , 32, 1, 1, 1, R, x, 0x1B4, FC(4, x, RGB10A2, , ), GEN(8) ) GMM_FORMAT( R10G10B10X2_USCALED , 32, 1, 1, 1, R, x, 0x0F3, FC(4, x, RGB10A2, , ), ALWAYS ) GMM_FORMAT( R11G11B10_FLOAT , 32, 1, 1, 1, R, x, 0x0D3, FC(4, x, RG11B10, , ), ALWAYS ) GMM_FORMAT( R16_FLOAT , 16, 1, 1, 1, R, x, 0x10E, FC(4, 16, R, 16, F1), ALWAYS ) GMM_FORMAT( R16_SINT , 16, 1, 1, 1, R, x, 0x10C, FC(4, 16, R, 16, S1), ALWAYS ) GMM_FORMAT( R16_SNORM , 16, 1, 1, 1, R, x, 0x10B, FC(4, 16, R, 16, S), ALWAYS ) GMM_FORMAT( R16_SSCALED , 16, 1, 1, 1, R, x, 0x11E, FC(4, 16, R, 16, S), ALWAYS ) GMM_FORMAT( R16_UINT , 16, 1, 1, 1, R, x, 0x10D, FC(4, 16, R, 16, U1), ALWAYS ) GMM_FORMAT( R16_UNORM , 16, 1, 1, 1, R, x, 0x10A, FC(4, 16, R, 16, U), ALWAYS ) GMM_FORMAT( R16_USCALED , 16, 1, 1, 1, R, x, 0x11F, FC(4, 16, R, 16, U), ALWAYS ) GMM_FORMAT( R16G16_FLOAT , 32, 1, 1, 1, R, x, 0x0D0, FC(4, 16, RG, 16, F), ALWAYS ) GMM_FORMAT( R16G16_SINT , 32, 1, 1, 1, R, x, 0x0CE, FC(4, 16, RG, 16, S), ALWAYS ) GMM_FORMAT( R16G16_SNORM , 32, 1, 1, 1, R, x, 0x0CD, FC(4, 16, RG, 16, S), ALWAYS ) GMM_FORMAT( R16G16_SSCALED , 32, 1, 1, 1, R, x, 0x0F6, FC(4, 16, RG, 16, S), ALWAYS ) GMM_FORMAT( R16G16_UINT , 32, 1, 1, 1, R, x, 0x0CF, FC(4, 16, RG, 16, U), ALWAYS ) GMM_FORMAT( R16G16_UNORM , 32, 1, 1, 1, R, x, 0x0CC, FC(4, 16, RG, 16, U), ALWAYS ) GMM_FORMAT( R16G16_USCALED , 32, 1, 1, 1, R, x, 0x0F7, FC(4, 16, RG, 16, U), ALWAYS ) GMM_FORMAT( R16G16B16_FLOAT , 48, 1, 1, 1, R, x, 0x19B, NC , ALWAYS ) GMM_FORMAT( R16G16B16_SINT , 48, 1, 1, 1, R, x, 0x1B1, NC , GEN(8) ) GMM_FORMAT( R16G16B16_SNORM , 48, 1, 1, 1, R, x, 0x19D, NC , ALWAYS ) GMM_FORMAT( R16G16B16_SSCALED , 48, 1, 1, 1, R, x, 0x19E, NC , ALWAYS ) GMM_FORMAT( R16G16B16_UINT , 48, 1, 1, 1, R, x, 0x1B0, NC , GEN(8) || VLV2 ) GMM_FORMAT( R16G16B16_UNORM , 48, 1, 1, 1, R, x, 0x19C, NC , ALWAYS ) GMM_FORMAT( R16G16B16_USCALED , 48, 1, 1, 1, R, x, 0x19F, NC , ALWAYS ) GMM_FORMAT( R16G16B16A16_FLOAT , 64, 1, 1, 1, R, x, 0x084, FC(4, 16, RGBA, 16, F), ALWAYS ) GMM_FORMAT( R16G16B16A16_SINT , 64, 1, 1, 1, R, x, 0x082, FC(4, 16, RGBA, 16, S), ALWAYS ) GMM_FORMAT( R16G16B16A16_SNORM , 64, 1, 1, 1, R, x, 0x081, FC(4, 16, RGBA, 16, S), ALWAYS ) GMM_FORMAT( R16G16B16A16_SSCALED , 64, 1, 1, 1, R, x, 0x093, FC(4, 16, RGBA, 16, S), ALWAYS ) GMM_FORMAT( R16G16B16A16_UINT , 64, 1, 1, 1, R, x, 0x083, FC(4, 16, RGBA, 16, U), ALWAYS ) GMM_FORMAT( R16G16B16A16_UNORM , 64, 1, 1, 1, R, x, 0x080, FC(4, 16, RGBA, 16, U), ALWAYS ) GMM_FORMAT( R16G16B16A16_USCALED , 64, 1, 1, 1, R, x, 0x094, FC(4, 16, RGBA, 16, U), ALWAYS ) GMM_FORMAT( R16G16B16X16_FLOAT , 64, 1, 1, 1, R, x, 0x08F, FC(4, 16, RGBA, 16, F), ALWAYS ) GMM_FORMAT( R16G16B16X16_UNORM , 64, 1, 1, 1, R, x, 0x08E, FC(4, 16, RGBA, 16, U), ALWAYS ) GMM_FORMAT( R24_UNORM_X8_TYPELESS , 32, 1, 1, 1, R, x, 0x0D9, FC(4, 32, R, 32, U1), ALWAYS ) GMM_FORMAT( R32_FLOAT , 32, 1, 1, 1, R, x, 0x0D8, FC(4, 32, R, 32, F1), ALWAYS ) GMM_FORMAT( R32_FLOAT_X8X24_TYPELESS , 64, 1, 1, 1, R, x, 0x088, FC(4, 32, R, 32, F), ALWAYS ) GMM_FORMAT( R32_SFIXED , 32, 1, 1, 1, R, x, 0x1B2, FC(4, 32, R, 32, S), GEN(8) ) GMM_FORMAT( R32_SINT , 32, 1, 1, 1, R, x, 0x0D6, FC(4, 32, R, 32, S1), ALWAYS ) GMM_FORMAT( R32_SNORM , 32, 1, 1, 1, R, x, 0x0F2, FC(4, 32, R, 32, S), ALWAYS ) GMM_FORMAT( R32_SSCALED , 32, 1, 1, 1, R, x, 0x0F8, FC(4, 32, R, 32, S), ALWAYS ) GMM_FORMAT( R32_UINT , 32, 1, 1, 1, R, x, 0x0D7, FC(4, 32, R, 32, U1), ALWAYS ) GMM_FORMAT( R32_UNORM , 32, 1, 1, 1, R, x, 0x0F1, FC(4, 32, R, 32, U), ALWAYS ) GMM_FORMAT( R32_USCALED , 32, 1, 1, 1, R, x, 0x0F9, FC(4, 32, R, 32, U), ALWAYS ) GMM_FORMAT( R32G32_FLOAT , 64, 1, 1, 1, R, x, 0x085, FC(4, 32, RG, 32, F), ALWAYS ) GMM_FORMAT( R32G32_SFIXED , 64, 1, 1, 1, R, x, 0x0A0, FC(4, 32, RG, 32, S), ALWAYS ) GMM_FORMAT( R32G32_SINT , 64, 1, 1, 1, R, x, 0x086, FC(4, 32, RG, 32, S), ALWAYS ) GMM_FORMAT( R32G32_SNORM , 64, 1, 1, 1, R, x, 0x08C, FC(4, 32, RG, 32, S), ALWAYS ) GMM_FORMAT( R32G32_SSCALED , 64, 1, 1, 1, R, x, 0x095, FC(4, 32, RG, 32, S), ALWAYS ) GMM_FORMAT( R32G32_UINT , 64, 1, 1, 1, R, x, 0x087, FC(4, 32, RG, 32, U), ALWAYS ) GMM_FORMAT( R32G32_UNORM , 64, 1, 1, 1, R, x, 0x08B, FC(4, 32, RG, 32, U), ALWAYS ) GMM_FORMAT( R32G32_USCALED , 64, 1, 1, 1, R, x, 0x096, FC(4, 32, RG, 32, U), ALWAYS ) GMM_FORMAT( R32G32B32_FLOAT , 96, 1, 1, 1, R, x, 0x040, NC , ALWAYS ) GMM_FORMAT( R32G32B32_SFIXED , 96, 1, 1, 1, R, x, 0x050, NC , ALWAYS ) GMM_FORMAT( R32G32B32_SINT , 96, 1, 1, 1, R, x, 0x041, NC , ALWAYS ) GMM_FORMAT( R32G32B32_SNORM , 96, 1, 1, 1, R, x, 0x044, NC , ALWAYS ) GMM_FORMAT( R32G32B32_SSCALED , 96, 1, 1, 1, R, x, 0x045, NC , ALWAYS ) GMM_FORMAT( R32G32B32_UINT , 96, 1, 1, 1, R, x, 0x042, NC , ALWAYS ) GMM_FORMAT( R32G32B32_UNORM , 96, 1, 1, 1, R, x, 0x043, NC , ALWAYS ) GMM_FORMAT( R32G32B32_USCALED , 96, 1, 1, 1, R, x, 0x046, NC , ALWAYS ) GMM_FORMAT( R32G32B32A32_FLOAT , 128, 1, 1, 1, R, x, 0x000, FC(4, 32, RGBA, 32, F), ALWAYS ) GMM_FORMAT( R32G32B32A32_SFIXED , 128, 1, 1, 1, R, x, 0x020, FC(4, 32, RGBA, 32, S), ALWAYS ) GMM_FORMAT( R32G32B32A32_SINT , 128, 1, 1, 1, R, x, 0x001, FC(4, 32, RGBA, 32, S), ALWAYS ) GMM_FORMAT( R32G32B32A32_SNORM , 128, 1, 1, 1, R, x, 0x004, FC(4, 32, RGBA, 32, S), ALWAYS ) GMM_FORMAT( R32G32B32A32_SSCALED , 128, 1, 1, 1, R, x, 0x007, FC(4, 32, RGBA, 32, S), ALWAYS ) GMM_FORMAT( R32G32B32A32_UINT , 128, 1, 1, 1, R, x, 0x002, FC(4, 32, RGBA, 32, U), ALWAYS ) GMM_FORMAT( R32G32B32A32_UNORM , 128, 1, 1, 1, R, x, 0x003, FC(4, 32, RGBA, 32, U), ALWAYS ) GMM_FORMAT( R32G32B32A32_USCALED , 128, 1, 1, 1, R, x, 0x008, FC(4, 32, RGBA, 32, U), ALWAYS ) GMM_FORMAT( R32G32B32X32_FLOAT , 128, 1, 1, 1, R, x, 0x006, FC(4, 32, RGBA, 32, F), ALWAYS ) GMM_FORMAT( R5G5_SNORM_B6_UNORM , 16, 1, 1, 1, R, x, 0x119, NC , ALWAYS ) GMM_FORMAT( R64_FLOAT , 64, 1, 1, 1, R, x, 0x08D, NC , ALWAYS ) GMM_FORMAT( R64_PASSTHRU , 64, 1, 1, 1, R, x, 0x0A1, NC , ALWAYS ) GMM_FORMAT( R64G64_FLOAT , 128, 1, 1, 1, R, x, 0x005, NC , ALWAYS ) GMM_FORMAT( R64G64_PASSTHRU , 128, 1, 1, 1, R, x, 0x021, NC , ALWAYS ) GMM_FORMAT( R64G64B64_FLOAT , 192, 1, 1, 1, R, x, 0x198, NC , ALWAYS ) GMM_FORMAT( R64G64B64_PASSTHRU , 192, 1, 1, 1, R, x, 0x1BD, NC , GEN(8) ) GMM_FORMAT( R64G64B64A64_FLOAT , 256, 1, 1, 1, R, x, 0x197, NC , ALWAYS ) GMM_FORMAT( R64G64B64A64_PASSTHRU , 256, 1, 1, 1, R, x, 0x1BC, NC , GEN(8) ) GMM_FORMAT( RAW , 8, 1, 1, 1, R, x, 0x1FF, NC , GEN(7) ) // "8bpp" for current GMM implementation. GMM_FORMAT( X24_TYPELESS_G8_UINT , 32, 1, 1, 1, R, x, 0x0DA, FC(4, 32, R, 32, U1), ALWAYS ) GMM_FORMAT( X32_TYPELESS_G8X24_UINT , 64, 1, 1, 1, R, x, 0x089, FC(4, 32, RG, 32, U), ALWAYS ) GMM_FORMAT( X8B8_UNORM_G8R8_SNORM , 32, 1, 1, 1, R, x, 0x0E6, NC , ALWAYS ) GMM_FORMAT( Y8_UNORM , 8, 1, 1, 1, R, x, 0x150, FC(4, x, NV12, ,_L ), ALWAYS ) GMM_FORMAT( YCRCB_NORMAL , 16, 1, 1, 1, R, x, 0x182, FC(4, x, YUY2, , ), ALWAYS ) GMM_FORMAT( YCRCB_SWAPUV , 16, 1, 1, 1, R, x, 0x18F, FC(4, x, YCRCB_SWAPUV, ,), ALWAYS ) GMM_FORMAT( YCRCB_SWAPUVY , 16, 1, 1, 1, R, x, 0x183, FC(4, x, YCRCB_SWAPUVY,,), ALWAYS ) GMM_FORMAT( YCRCB_SWAPY , 16, 1, 1, 1, R, x, 0x190, FC(4, x, YCRCB_SWAPY, , ), ALWAYS ) #endif // INCLUDE_SURFACESTATE_FORMATS #ifdef INCLUDE_ASTC_FORMATS GMM_FORMAT( ASTC_FULL_2D_4x4_FLT16 , 128, 4, 4, 1, x, A, 0x140, NC , ASTC_HDR_2D ) GMM_FORMAT( ASTC_FULL_2D_5x4_FLT16 , 128, 5, 4, 1, x, A, 0x148, NC , ASTC_HDR_2D ) GMM_FORMAT( ASTC_FULL_2D_5x5_FLT16 , 128, 5, 5, 1, x, A, 0x149, NC , ASTC_HDR_2D ) GMM_FORMAT( ASTC_FULL_2D_6x5_FLT16 , 128, 6, 5, 1, x, A, 0x151, NC , ASTC_HDR_2D ) GMM_FORMAT( ASTC_FULL_2D_6x6_FLT16 , 128, 6, 6, 1, x, A, 0x152, NC , ASTC_HDR_2D ) GMM_FORMAT( ASTC_FULL_2D_8x5_FLT16 , 128, 8, 5, 1, x, A, 0x161, NC , ASTC_HDR_2D ) GMM_FORMAT( ASTC_FULL_2D_8x6_FLT16 , 128, 8, 6, 1, x, A, 0x162, NC , ASTC_HDR_2D ) GMM_FORMAT( ASTC_FULL_2D_8x8_FLT16 , 128, 8, 8, 1, x, A, 0x164, NC , ASTC_HDR_2D ) GMM_FORMAT( ASTC_FULL_2D_10x5_FLT16 , 128, 10, 5, 1, x, A, 0x171, NC , ASTC_HDR_2D ) GMM_FORMAT( ASTC_FULL_2D_10x6_FLT16 , 128, 10, 6, 1, x, A, 0x172, NC , ASTC_HDR_2D ) GMM_FORMAT( ASTC_FULL_2D_10x8_FLT16 , 128, 10, 8, 1, x, A, 0x174, NC , ASTC_HDR_2D ) GMM_FORMAT( ASTC_FULL_2D_10x10_FLT16 , 128, 10, 10, 1, x, A, 0x176, NC , ASTC_HDR_2D ) GMM_FORMAT( ASTC_FULL_2D_12x10_FLT16 , 128, 12, 10, 1, x, A, 0x17e, NC , ASTC_HDR_2D ) GMM_FORMAT( ASTC_FULL_2D_12x12_FLT16 , 128, 12, 12, 1, x, A, 0x17f, NC , ASTC_HDR_2D ) GMM_FORMAT( ASTC_FULL_3D_3x3x3_FLT16 , 128, 3, 3, 3, x, A, 0x1c0, NC , ASTC_3D ) GMM_FORMAT( ASTC_FULL_3D_4x3x3_FLT16 , 128, 4, 3, 3, x, A, 0x1d0, NC , ASTC_3D ) GMM_FORMAT( ASTC_FULL_3D_4x4x3_FLT16 , 128, 4, 4, 3, x, A, 0x1d4, NC , ASTC_3D ) GMM_FORMAT( ASTC_FULL_3D_4x4x4_FLT16 , 128, 4, 4, 4, x, A, 0x1d5, NC , ASTC_3D ) GMM_FORMAT( ASTC_FULL_3D_5x4x4_FLT16 , 128, 5, 4, 4, x, A, 0x1e5, NC , ASTC_3D ) GMM_FORMAT( ASTC_FULL_3D_5x5x4_FLT16 , 128, 5, 5, 4, x, A, 0x1e9, NC , ASTC_3D ) GMM_FORMAT( ASTC_FULL_3D_5x5x5_FLT16 , 128, 5, 5, 5, x, A, 0x1ea, NC , ASTC_3D ) GMM_FORMAT( ASTC_FULL_3D_6x5x5_FLT16 , 128, 6, 5, 5, x, A, 0x1fa, NC , ASTC_3D ) GMM_FORMAT( ASTC_FULL_3D_6x6x5_FLT16 , 128, 6, 6, 5, x, A, 0x1fe, NC , ASTC_3D ) GMM_FORMAT( ASTC_FULL_3D_6x6x6_FLT16 , 128, 6, 6, 6, x, A, 0x1ff, NC , ASTC_3D ) GMM_FORMAT( ASTC_LDR_2D_4x4_FLT16 , 128, 4, 4, 1, x, A, 0x040, NC , ASTC_LDR_2D ) GMM_FORMAT( ASTC_LDR_2D_4x4_U8sRGB , 128, 4, 4, 1, x, A, 0x000, NC , ASTC_LDR_2D ) GMM_FORMAT( ASTC_LDR_2D_5x4_FLT16 , 128, 5, 4, 1, x, A, 0x048, NC , ASTC_LDR_2D ) GMM_FORMAT( ASTC_LDR_2D_5x4_U8sRGB , 128, 5, 4, 1, x, A, 0x008, NC , ASTC_LDR_2D ) GMM_FORMAT( ASTC_LDR_2D_5x5_FLT16 , 128, 5, 5, 1, x, A, 0x049, NC , ASTC_LDR_2D ) GMM_FORMAT( ASTC_LDR_2D_5x5_U8sRGB , 128, 5, 5, 1, x, A, 0x009, NC , ASTC_LDR_2D ) GMM_FORMAT( ASTC_LDR_2D_6x5_FLT16 , 128, 6, 5, 1, x, A, 0x051, NC , ASTC_LDR_2D ) GMM_FORMAT( ASTC_LDR_2D_6x5_U8sRGB , 128, 6, 5, 1, x, A, 0x011, NC , ASTC_LDR_2D ) GMM_FORMAT( ASTC_LDR_2D_6x6_FLT16 , 128, 6, 6, 1, x, A, 0x052, NC , ASTC_LDR_2D ) GMM_FORMAT( ASTC_LDR_2D_6x6_U8sRGB , 128, 6, 6, 1, x, A, 0x012, NC , ASTC_LDR_2D ) GMM_FORMAT( ASTC_LDR_2D_8x5_FLT16 , 128, 8, 5, 1, x, A, 0x061, NC , ASTC_LDR_2D ) GMM_FORMAT( ASTC_LDR_2D_8x5_U8sRGB , 128, 8, 5, 1, x, A, 0x021, NC , ASTC_LDR_2D ) GMM_FORMAT( ASTC_LDR_2D_8x6_FLT16 , 128, 8, 6, 1, x, A, 0x062, NC , ASTC_LDR_2D ) GMM_FORMAT( ASTC_LDR_2D_8x6_U8sRGB , 128, 8, 6, 1, x, A, 0x022, NC , ASTC_LDR_2D ) GMM_FORMAT( ASTC_LDR_2D_8x8_FLT16 , 128, 8, 8, 1, x, A, 0x064, NC , ASTC_LDR_2D ) GMM_FORMAT( ASTC_LDR_2D_8x8_U8sRGB , 128, 8, 8, 1, x, A, 0x024, NC , ASTC_LDR_2D ) GMM_FORMAT( ASTC_LDR_2D_10x5_FLT16 , 128, 10, 5, 1, x, A, 0x071, NC , ASTC_LDR_2D ) GMM_FORMAT( ASTC_LDR_2D_10x5_U8sRGB , 128, 10, 5, 1, x, A, 0x031, NC , ASTC_LDR_2D ) GMM_FORMAT( ASTC_LDR_2D_10x6_FLT16 , 128, 10, 6, 1, x, A, 0x072, NC , ASTC_LDR_2D ) GMM_FORMAT( ASTC_LDR_2D_10x6_U8sRGB , 128, 10, 6, 1, x, A, 0x032, NC , ASTC_LDR_2D ) GMM_FORMAT( ASTC_LDR_2D_10x8_FLT16 , 128, 10, 8, 1, x, A, 0x074, NC , ASTC_LDR_2D ) GMM_FORMAT( ASTC_LDR_2D_10x8_U8sRGB , 128, 10, 8, 1, x, A, 0x034, NC , ASTC_LDR_2D ) GMM_FORMAT( ASTC_LDR_2D_10x10_FLT16 , 128, 10, 10, 1, x, A, 0x076, NC , ASTC_LDR_2D ) GMM_FORMAT( ASTC_LDR_2D_10x10_U8sRGB , 128, 10, 10, 1, x, A, 0x036, NC , ASTC_LDR_2D ) GMM_FORMAT( ASTC_LDR_2D_12x10_FLT16 , 128, 12, 10, 1, x, A, 0x07e, NC , ASTC_LDR_2D ) GMM_FORMAT( ASTC_LDR_2D_12x10_U8sRGB , 128, 12, 10, 1, x, A, 0x03e, NC , ASTC_LDR_2D ) GMM_FORMAT( ASTC_LDR_2D_12x12_FLT16 , 128, 12, 12, 1, x, A, 0x07f, NC , ASTC_LDR_2D ) GMM_FORMAT( ASTC_LDR_2D_12x12_U8sRGB , 128, 12, 12, 1, x, A, 0x03f, NC , ASTC_LDR_2D ) GMM_FORMAT( ASTC_LDR_3D_3x3x3_U8sRGB , 128, 3, 3, 3, x, A, 0x080, NC , ASTC_3D ) GMM_FORMAT( ASTC_LDR_3D_3x3x3_FLT16 , 128, 3, 3, 3, x, A, 0x0c0, NC , ASTC_3D ) GMM_FORMAT( ASTC_LDR_3D_4x3x3_U8sRGB , 128, 4, 3, 3, x, A, 0x090, NC , ASTC_3D ) GMM_FORMAT( ASTC_LDR_3D_4x3x3_FLT16 , 128, 4, 3, 3, x, A, 0x0d0, NC , ASTC_3D ) GMM_FORMAT( ASTC_LDR_3D_4x4x3_U8sRGB , 128, 4, 4, 3, x, A, 0x094, NC , ASTC_3D ) GMM_FORMAT( ASTC_LDR_3D_4x4x3_FLT16 , 128, 4, 4, 3, x, A, 0x0d4, NC , ASTC_3D ) GMM_FORMAT( ASTC_LDR_3D_4x4x4_U8sRGB , 128, 4, 4, 4, x, A, 0x095, NC , ASTC_3D ) GMM_FORMAT( ASTC_LDR_3D_4x4x4_FLT16 , 128, 4, 4, 4, x, A, 0x0d5, NC , ASTC_3D ) GMM_FORMAT( ASTC_LDR_3D_5x4x4_U8sRGB , 128, 5, 4, 4, x, A, 0x0a5, NC , ASTC_3D ) GMM_FORMAT( ASTC_LDR_3D_5x4x4_FLT16 , 128, 5, 4, 4, x, A, 0x0e5, NC , ASTC_3D ) GMM_FORMAT( ASTC_LDR_3D_5x5x4_U8sRGB , 128, 5, 5, 4, x, A, 0x0a9, NC , ASTC_3D ) GMM_FORMAT( ASTC_LDR_3D_5x5x4_FLT16 , 128, 5, 5, 4, x, A, 0x0e9, NC , ASTC_3D ) GMM_FORMAT( ASTC_LDR_3D_5x5x5_U8sRGB , 128, 5, 5, 5, x, A, 0x0aa, NC , ASTC_3D ) GMM_FORMAT( ASTC_LDR_3D_5x5x5_FLT16 , 128, 5, 5, 5, x, A, 0x0ea, NC , ASTC_3D ) GMM_FORMAT( ASTC_LDR_3D_6x5x5_U8sRGB , 128, 6, 5, 5, x, A, 0x0ba, NC , ASTC_3D ) GMM_FORMAT( ASTC_LDR_3D_6x5x5_FLT16 , 128, 6, 5, 5, x, A, 0x0fa, NC , ASTC_3D ) GMM_FORMAT( ASTC_LDR_3D_6x6x5_U8sRGB , 128, 6, 6, 5, x, A, 0x0be, NC , ASTC_3D ) GMM_FORMAT( ASTC_LDR_3D_6x6x5_FLT16 , 128, 6, 6, 5, x, A, 0x0fe, NC , ASTC_3D ) GMM_FORMAT( ASTC_LDR_3D_6x6x6_U8sRGB , 128, 6, 6, 6, x, A, 0x0bf, NC , ASTC_3D ) GMM_FORMAT( ASTC_LDR_3D_6x6x6_FLT16 , 128, 6, 6, 6, x, A, 0x0ff, NC , ASTC_3D ) #endif // INCLUDE_ASTC_FORMATS #ifdef INCLUDE_MISC_FORMATS GMM_FORMAT( AUYV , 32, 1, 1, 1, R, x, NA , NC , ALWAYS ) GMM_FORMAT( AYUV , 32, 1, 1, 1, R, x, NA , FC(4, x, AYUV, , ), ALWAYS ) GMM_FORMAT( BAYER_BGGR8 , 8, 1, 1, 1, R, x, NA , NC , ALWAYS ) // (0, 0) = B GMM_FORMAT( BAYER_BGGR16 , 16, 1, 1, 1, R, x, NA , NC , ALWAYS ) // (0, 0) = B GMM_FORMAT( BAYER_GBRG8 , 8, 1, 1, 1, R, x, NA , NC , ALWAYS ) // (0, 0) = G, (1, 0) = B GMM_FORMAT( BAYER_GBRG16 , 16, 1, 1, 1, R, x, NA , NC , ALWAYS ) // (0, 0) = G, (1, 0) = B GMM_FORMAT( BAYER_GRBG8 , 8, 1, 1, 1, R, x, NA , NC , ALWAYS ) // (0, 0) = G, (1, 0) = R GMM_FORMAT( BAYER_GRBG16 , 16, 1, 1, 1, R, x, NA , NC , ALWAYS ) // (0, 0) = G, (1, 0) = R GMM_FORMAT( BAYER_RGGB8 , 8, 1, 1, 1, R, x, NA , NC , ALWAYS ) // (0, 0) = R GMM_FORMAT( BAYER_RGGB16 , 16, 1, 1, 1, R, x, NA , NC , ALWAYS ) // (0, 0) = R GMM_FORMAT( BC1 , 64, 4, 4, 1, x, x, NA , FC(4, x, ML8, , ), ALWAYS ) // Legacy GMM name for related HW format. GMM_FORMAT( BC2 , 128, 4, 4, 1, x, x, NA , FC(4, x, ML8, , ), ALWAYS ) // " GMM_FORMAT( BC3 , 128, 4, 4, 1, x, x, NA , FC(4, x, ML8, , ), ALWAYS ) // " GMM_FORMAT( BC4 , 64, 4, 4, 1, x, x, NA , FC(4, x, ML8, , ), ALWAYS ) // " GMM_FORMAT( BC5 , 128, 4, 4, 1, x, x, NA , FC(4, x, ML8, , ), ALWAYS ) // " GMM_FORMAT( BC6 , 128, 4, 4, 1, x, x, NA , FC(4, x, ML8, , ), ALWAYS ) // " GMM_FORMAT( BC6H , 128, 4, 4, 1, x, x, NA , FC(4, x, ML8, , ), ALWAYS ) // " GMM_FORMAT( BC7 , 128, 4, 4, 1, x, x, NA , FC(4, x, ML8, , ), GEN(7) ) // " GMM_FORMAT( BGRP , 8, 1, 1, 1, R, x, NA , NC , ALWAYS ) // FOURCC:BGRP GMM_FORMAT( D16_UNORM , 16, 1, 1, 1, x, x, NA , FC(4, 16, R, 16, U), ALWAYS ) //Depth uses color format L1e.En GMM_FORMAT( D24_UNORM_X8_UINT , 32, 1, 1, 1, x, x, NA , FC(4, 32, D, 32, U), ALWAYS ) GMM_FORMAT( D32_FLOAT , 32, 1, 1, 1, x, x, NA , FC(4, 32, R, 32, F1), ALWAYS ) GMM_FORMAT( DXT1 , 64, 4, 4, 1, x, x, NA , NC , ALWAYS ) // Legacy GMM name for related HW format. GMM_FORMAT( DXT2_5 , 128, 4, 4, 1, x, x, NA , NC , ALWAYS ) // " GMM_FORMAT( ETC1 , 64, 4, 4, 1, x, x, NA , FC(4, x, ML8, , ), GEN(8) || VLV2 ) // " GMM_FORMAT( ETC2 , 64, 4, 4, 1, x, x, NA , FC(4, x, ML8, , ), GEN(8) || VLV2 ) // " GMM_FORMAT( ETC2_EAC , 128, 4, 4, 1, x, x, NA , FC(4, x, ML8, , ), GEN(8) || VLV2 ) // " GMM_FORMAT( GENERIC_8BIT , 8, 1, 1, 1, x, x, NA , FC(4, x, ML8, , ), ALWAYS ) GMM_FORMAT( GENERIC_16BIT , 16, 1, 1, 1, x, x, NA , FC(4, x, ML8, , ), ALWAYS ) GMM_FORMAT( GENERIC_24BIT , 24, 1, 1, 1, x, x, NA , NC , ALWAYS ) // verify ML8 for > 16 bit GMM_FORMAT( GENERIC_32BIT , 32, 1, 1, 1, x, x, NA , NC , ALWAYS ) GMM_FORMAT( GENERIC_48BIT , 48, 1, 1, 1, x, x, NA , NC , ALWAYS ) GMM_FORMAT( GENERIC_64BIT , 64, 1, 1, 1, x, x, NA , NC , ALWAYS ) GMM_FORMAT( GENERIC_96BIT , 96, 1, 1, 1, x, x, NA , NC , ALWAYS ) GMM_FORMAT( GENERIC_128BIT , 128, 1, 1, 1, x, x, NA , NC , ALWAYS ) GMM_FORMAT( GENERIC_192BIT , 192, 1, 1, 1, x, x, NA , NC , GEN(8) ) GMM_FORMAT( GENERIC_256BIT , 256, 1, 1, 1, x, x, NA , NC , GEN(8) ) GMM_FORMAT( I420 , 8, 1, 1, 1, R, x, NA , NC , ALWAYS ) // Same as IYUV. GMM_FORMAT( IYUV , 8, 1, 1, 1, R, x, NA , NC , ALWAYS ) GMM_FORMAT( IMC1 , 8, 1, 1, 1, R, x, NA , FC(4, x, NV12, ,_L ), ALWAYS ) GMM_FORMAT( IMC2 , 8, 1, 1, 1, R, x, NA , FC(4, x, NV12, ,_L ), ALWAYS ) GMM_FORMAT( IMC3 , 8, 1, 1, 1, R, x, NA , FC(4, x, NV12, ,_L ), ALWAYS ) GMM_FORMAT( IMC4 , 8, 1, 1, 1, R, x, NA , FC(4, x, NV12, ,_L ), ALWAYS ) GMM_FORMAT( L4A4 , 8, 1, 1, 1, R, x, NA , FC(4, x, NV12, ,_L ), ALWAYS ) // No HW support. GMM_FORMAT( MFX_JPEG_YUV411 , 8, 1, 1, 1, R, x, NA , FC(4, x, NV12, ,_L ), GEN(7) ) GMM_FORMAT( MFX_JPEG_YUV411R , 8, 1, 1, 1, R, x, NA , FC(4, x, NV12, ,_L ), GEN(7) ) GMM_FORMAT( MFX_JPEG_YUV420 , 8, 1, 1, 1, R, x, NA , FC(4, x, NV12, ,_L ), GEN(7) ) // Same as IMC3. GMM_FORMAT( MFX_JPEG_YUV422H , 8, 1, 1, 1, R, x, NA , FC(4, x, NV12, ,_L ), GEN(7) ) GMM_FORMAT( MFX_JPEG_YUV422V , 8, 1, 1, 1, R, x, NA , FC(4, x, NV12, ,_L ), GEN(7) ) GMM_FORMAT( MFX_JPEG_YUV444 , 8, 1, 1, 1, R, x, NA , FC(4, x, NV12, ,_L ), GEN(7) ) GMM_FORMAT( NV11 , 8, 1, 1, 1, R, x, NA , NC , ALWAYS ) GMM_FORMAT( NV12 , 8, 1, 1, 1, R, x, NA , FC(4, x, NV12, ,_L ), ALWAYS ) GMM_FORMAT( NV21 , 8, 1, 1, 1, R, x, NA , FC(4, x, NV12, ,_L ), ALWAYS ) GMM_FORMAT( P8 , 8, 1, 1, 1, R, x, NA, NC , ALWAYS ) GMM_FORMAT( P010 , 16, 1, 1, 1, R, x, NA , FC(4, x, P010, ,_L ), ALWAYS ) GMM_FORMAT( P012 , 16, 1, 1, 1, R, x, NA , NC , ALWAYS ) GMM_FORMAT( P016 , 16, 1, 1, 1, R, x, NA , FC(4, x, P016, ,_L ), ALWAYS ) GMM_FORMAT( P208 , 8, 1, 1, 1, R, x, NA , NC , ALWAYS ) GMM_FORMAT( R10G10B10_XR_BIAS_A2_UNORM , 32, 1, 1, 1, x, x, NA , FC(4, x, RGB10A2, , ), ALWAYS ) // DXGI_FORMAT_R10G10B10_XR_BIAS_A2_UNORM GMM_FORMAT( R24G8_TYPELESS , 32, 1, 1, 1, x, x, NA , FC(4, 32, R, 32, U), ALWAYS ) // DXGI_FORMAT_R24G8_TYPELESS (To differentiate between GENERIC_32BIT.) GMM_FORMAT( R32G8X24_TYPELESS , 64, 1, 1, 1, x, x, NA , FC(4, 32, R, 32, U), ALWAYS ) // DXGI_FORMAT_R32G8X24_TYPELESS (To differentiate between GENERIC_64BIT.) GMM_FORMAT( RENDER_8BIT , 8, 1, 1, 1, R, x, NA , NC , ALWAYS ) GMM_FORMAT( RGBP , 8, 1, 1, 1, R, x, NA , FC(4, x, NV12, ,_L ), ALWAYS ) // FOURCC:RGBP GMM_FORMAT( Y1_UNORM , 1, 1, 1, 1, x, x, NA , NC , GEN(8) ) GMM_FORMAT( Y8_UNORM_VA , 8, 1, 1, 1, x, x, NA , FC(4, x, NV12, ,_L ), GEN(8) ) GMM_FORMAT( Y16_SNORM , 16, 1, 1, 1, x, x, NA , FC(4, x, P010, ,_L ), GEN(8) ) GMM_FORMAT( Y16_UNORM , 16, 1, 1, 1, x, x, NA , FC(4, x, P010, ,_L ), GEN(8) ) #if (IGFX_GEN >= IGFX_GEN10) GMM_FORMAT( Y32_UNORM , 32, 1, 1, 1, x, x, NA , NC , GEN(10) ) // Y32 removed from Gen9 but still referenced, only available Gen10+ #endif GMM_FORMAT( Y210 , 64, 2, 1, 1, R, x, NA , FC(4, x, Y210, , ), GEN(11) ) // Packed 422 10/12/16 bit GMM_FORMAT( Y212 , 64, 2, 1, 1, R, x, NA , FC(4, x, Y216, , ), GEN(11) ) GMM_FORMAT( Y410 , 32, 1, 1, 1, R, x, NA , FC(4, x, Y410, , ), GEN(11) ) GMM_FORMAT( Y412 , 64, 1, 1, 1, R, x, NA , FC(4, x, Y416, , ), GEN(11) ) GMM_FORMAT( Y216 , 64, 2, 1, 1, R, x, NA, FC(4, x, Y216, , ), ALWAYS ) GMM_FORMAT( Y416 , 64, 1, 1, 1, R, x, NA , FC(4, x, Y416, , ), ALWAYS ) // Packed 444 10/12/16 bit, GMM_FORMAT( YV12 , 8, 1, 1, 1, R, x, NA , NC , ALWAYS ) GMM_FORMAT( YVU9 , 8, 1, 1, 1, R, x, NA , NC , ALWAYS ) // Implement packed 4:2:2 YUV format (UYVY, VYUY, YUY2, YVYU) as compressed block format by suffixing _2x1.(i.e. 32bpe 2x1 pixel blocks instead of 16bpp 1x1 block) // All OS components(UMDs/KMD) can switch to *_2x1 style independent of legacy implementation. // Refer GmmCommonExt.h for legacy implemenation of UYVY, VYUY, YUY2, YVYU) // TODO : Unify them when all OS-components switch to compressed block format GMM_FORMAT( UYVY_2x1 , 32, 2, 1, 1, R, x, NA , FC(4, x, SWAPY, , ), ALWAYS ) GMM_FORMAT( VYUY_2x1 , 32, 2, 1, 1, R, x, NA , FC(4, x, SWAPUVY, , ), ALWAYS ) GMM_FORMAT( YUY2_2x1 , 32, 2, 1, 1, R, x, NA , FC(4, x, YUY2, , ), ALWAYS ) GMM_FORMAT( YVYU_2x1 , 32, 2, 1, 1, R, x, NA , FC(4, x, SWAPUV, , ), ALWAYS ) GMM_FORMAT( MEDIA_Y1_UNORM , 1, 1, 1, 1, x, x, NA , NC , GEN(8) ) GMM_FORMAT( MEDIA_Y8_UNORM , 8, 1, 1, 1, x, x, NA , FC(4, x, NV12, ,_L ), GEN(8) ) GMM_FORMAT( MEDIA_Y16_SNORM , 16, 1, 1, 1, x, x, NA , FC(4, x, P010, ,_L ), GEN(8) ) GMM_FORMAT( MEDIA_Y16_UNORM , 16, 1, 1, 1, x, x, NA , FC(4, x, P010, ,_L ), GEN(8) ) GMM_FORMAT( MEDIA_Y32_UNORM , 1, 1, 1, 1, x, x, NA , NC , GEN(8) ) // Y32 is BDW name for SKL Y1, and is 1bpp with 32b granularity GMM_FORMAT( B16G16R16A16_UNORM , 64, 1, 1, 1, R, x, NA , FC(4, 16, RGBA, 16, U), ALWAYS ) // Swapped ARGB16 for media-SFC output GMM_FORMAT( P216 , 16, 1, 1, 1, R, x, NA , NC , ALWAYS ) #if _WIN32 GMM_FORMAT( WGBOX_YUV444 , 32, 1, 1, 1, x, x, NA , NC , GEN(9) ) // For testing purposes only. GMM_FORMAT( WGBOX_PLANAR_YUV444 , 32, 1, 1, 1, x, x, NA , NC , GEN(9) ) // For testing purposes only. #endif #endif // INCLUDE_MISC_FORMATS /*****************************************************************************\ Usage: File #include'ed into various areas of source code, to produce different things--various enums, struct/array-initializing code, etc. Format Names: The GMM_RESOURCE_FORMAT and GMM_SURFACESTATE_FORMAT enums are generated from this table. Supported Conditionals(*) and Meaning: GEN(X)........"Gen X or later" where X is text for IGFX_GEN[X]_CORE. SKU(FtrXxx)..."SKU FtrXxx is set". WA(WaXxx)....."WA WaXxx is set". Usually used with !/NOT prefix in table. Conditionals: Inclusions making use of columns supporting conditionals (e.g. "RT", "Available") must wrap the inclusion with macro definitions to service the supported conditionals in the local source--e.g.... #define GMM_FORMAT_GEN(X) (GFX_GET_CURRENT_RENDERCORE(pHwDevExt->platform) >= IGFX_GEN##X##_CORE) #define GMM_FORMAT_SKU(FtrXxx) (GFX_IS_SKU(pHwDevExt, FtrXxx)) #define GMM_FORMAT_WA(WaXxx) (GFX_IS_WA(pHwDevExt, WaXxx)) #define GMM_FORMAT(Name, bpe, Width, Height, Depth, IsRT, IsASTC, RcsSurfaceFormat, AuxL1eFormat, Availability) ... #include "GmmFormatTable.h" \*****************************************************************************/ #undef A #undef ALWAYS #undef ASTC_3D #undef ASTC_HDR_2D #undef ASTC_LDR_2D #undef GEN #undef INCLUDE_ASTC_FORMATS #undef INCLUDE_MISC_FORMATS #undef INCLUDE_SURFACESTATE_FORMATS #undef NA #undef NC #undef R #undef SKU #undef VLV2 #undef WA #undef x // So include-side code doesn't have to do this... #undef GMM_FORMAT #undef GMM_FORMAT_INCLUDE_ASTC_FORMATS_ONLY #undef GMM_FORMAT_INCLUDE_SURFACESTATE_FORMATS_ONLY #undef GMM_FORMAT_GEN #undef GMM_FORMAT_SKU #undef GMM_FORMAT_WA gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/inc/External/Common/GmmHw.h000066400000000000000000000172431466655022700250350ustar00rootroot00000000000000/*============================================================================== Copyright(c) 2019 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ============================================================================*/ #pragma once #include "gfxmacro.h" ////////////////////// Auxiliary Translation Table definitions////////////////////////////////////////// //=========================================================================== // typedef: // GMM_AUXTTL3e // // Description: // Struct for Auxiliary Translation-Table L3 entry //-------------------------------------------------------------------------- typedef union GMM_AUXTTL3e_REC { struct { uint64_t Valid : 1; uint64_t Reserved0 : 14; uint64_t L2GfxAddr : 33; uint64_t Reserved1 : 16; }; uint64_t Value; } GMM_AUXTTL3e; C_ASSERT(sizeof(GMM_AUXTTL3e) == 8); // Get the L2GfxAddr bit field as a full L2 graphics address #define GMM_FULL_GFXADDR_FROM_AUX_L3e_L2GFXADDR(L2GfxAddr) ((L2GfxAddr) << 16) // Set the L2GfxAddr bit field given a full L2 graphics address #define GMM_TO_AUX_L3e_L2GFXADDR(L2GfxAddress) ((L2GfxAddress) >> 16) //=========================================================================== // typedef: // GMM_AUXTTL2e // // Description: // Struct for Auxiliary Translation-Table L2 entry //-------------------------------------------------------------------------- typedef union GMM_AUXTTL2e_REC { struct { uint64_t Valid : 1; uint64_t Reserved0 : 10; uint64_t Reserved2 : 2; // used for MTL and above uint64_t L1GfxAddr : 35; uint64_t Reserved1 : 16; }; uint64_t Value; } GMM_AUXTTL2e; C_ASSERT(sizeof(GMM_AUXTTL2e) == 8); // Get the L1GfxAddr bit field as a full L1 graphics address #define GMM_FULL_GFXADDR_FROM_AUX_L2e_L1GFXADDR(L1GfxAddr) ((L1GfxAddr) << 16) #define GMM_L1TABLE_ADDR_FROM_AUX_L2e_L1GFXADDR(L2e, Is1MBaligned) (Is1MBaligned ? (L2e.L1GfxAddr << 13 | L2e.Reserved2 << 11) : (L2e.L1GfxAddr << 13)) // Set the L1GfxAddr bit field given a full L1 graphics address #define GMM_TO_AUX_L2e_L1GFXADDR(L1GfxAddress) ((L1GfxAddress) >> 16) #define GMM_TO_AUX_L2e_L1GFXADDR_2(GfxAddr, L2e, Is1MBaligned) { \ L2e.L1GfxAddr = (GfxAddr >> 13); \ L2e.Reserved2 = Is1MBaligned ? (GfxAddr >> 11) : 0;\ } #define GMM_GET_AUX_CCS_SIZE(Is1MBaligned) (Is1MBaligned? GMM_KBYTE(4): GMM_BYTES(256)) typedef union GMM_AUXTTL1e_REC { struct { uint64_t Valid : 1; uint64_t Mode : 2; //Compression ratio (128B compr ie 2:1 for RC, 256B compr ie 4:n compr for MC) uint64_t Lossy : 1; //Lossy Compression uint64_t Reserved0 : 2; uint64_t Reserved2 : 2; //LSbs of 64B-aligned CCS chunk/cacheline address uint64_t Reserved4 : 4; //LSbs of 256B-aligned CCS chunk/cacheline address uint64_t GfxAddress : 36; //4K-aligned CCS chunk address uint64_t Reserved1 : 4; uint64_t TileMode : 2; //Ys = 0, Y=1, Reserved=(2-3) uint64_t Depth : 3; //Packed/Planar bit-depth for MC; Bpp for RC uint64_t LumaChroma : 1; //Planar Y=0 or Cr=1 uint64_t Format : 6; //Format encoding shared with Vivante/Internal CC/DEC units to recognize surafce formats }; uint64_t Value; } GMM_AUXTTL1e; C_ASSERT(sizeof(GMM_AUXTTL1e) == 8); #define GMM_NO_TABLE ((GMM_GFX_ADDRESS)(-1L)) //common #define GMM_INVALID_AUX_ENTRY ~__BIT(0) #define GMM_AUX_L1e_SIZE (sizeof(GMM_AUXTTL1e)) #define GMM_AUX_L2e_SIZE (sizeof(GMM_AUXTTL2e)) #define GMM_AUX_L3e_SIZE (sizeof(GMM_AUXTTL3e)) #define GMM_AUX_L1_LOW_BIT (14) #define GMM_AUX_L1_HIGH_BIT (23) #define GMM_AUX_L2_LOW_BIT (24) #define GMM_AUX_L2_HIGH_BIT (35) #define GMM_AUX_L3_LOW_BIT (36) #define GMM_AUX_L3_HIGH_BIT (47) //For perf, AuxTable granularity changed to 64K #define WA16K(pGmmLibContext) (pGmmLibContext->GetWaTable().WaAuxTable16KGranular) #define WA64K(pGmmLibContext) (pGmmLibContext->GetWaTable().WaAuxTable64KGranular) // #L1 entries, i.e. 1024; 16K-granular ie 4 consequtive pages share Aux-cacheline; // HW only tracks the distinct entries; // Handle WA where HW chicken bit forces 64K-granularity #define GMM_AUX_L1_SIZE(pGmmLibContext) ((1 << (GMM_AUX_L1_HIGH_BIT - GMM_AUX_L1_LOW_BIT + 1)) / (WA16K(pGmmLibContext) ? 1 : 4)) // MTL : L1 size is 256 entries, but only first 16 entries are used in HW (0-15) #define GMM_AUX_L1_USABLESIZE(pGmmLibContext) ((1 << (GMM_AUX_L1_HIGH_BIT - GMM_AUX_L1_LOW_BIT + 1)) / (WA16K(pGmmLibContext) ? 1 : WA64K(pGmmLibContext) ? 4 : 64)) // MTL : L1 size is 256 entries, but only first 16 entries are used in HW (0-15) #define GMM_AUX_L1_SIZE_DWORD(pGmmLibContext) (GFX_CEIL_DIV(GMM_AUX_L1_SIZE(pGmmLibContext), 32)) // MTL : 256/32 = 8 // #L2 entries, i.e. 4096 #define GMM_AUX_L2_SIZE (1 << (GMM_AUX_L2_HIGH_BIT - GMM_AUX_L2_LOW_BIT + 1)) #define GMM_AUX_L2_SIZE_DWORD (GFX_CEIL_DIV(GMM_AUX_L2_SIZE, 32)) // #L3 entries, i.e. 4096 #define GMM_AUX_L3_SIZE (1 << (GMM_AUX_L3_HIGH_BIT - GMM_AUX_L3_LOW_BIT + 1)) #define GMM_AUX_L1_ENTRY_IDX(GfxAddress, pGmmLibContext) \ ((((GfxAddress)&GFX_MASK_LARGE(GMM_AUX_L1_LOW_BIT, GMM_AUX_L1_HIGH_BIT)) >> \ (uint64_t)GMM_AUX_L1_LOW_BIT) / \ (WA16K(pGmmLibContext) ? 1 : WA64K(pGmmLibContext) ? 4 : 64)) // MTL and above: L1 size is 256 entries, but only first 16 entries are used in HW #define GMM_AUX_L1_ENTRY_IDX_EXPORTED(GfxAddress,WA64KEx) \ ((((GfxAddress) & GFX_MASK_LARGE(GMM_AUX_L1_LOW_BIT, GMM_AUX_L1_HIGH_BIT)) >> \ (uint64_t)GMM_AUX_L1_LOW_BIT) / ((WA64KEx) ? 4 : 1)) #define GMM_AUX_L1_ENTRY_IDX_EXPORTED_2(GfxAddress, WA64KEx, WA16KEx) \ ((((GfxAddress)&GFX_MASK_LARGE(GMM_AUX_L1_LOW_BIT, GMM_AUX_L1_HIGH_BIT)) >> (uint64_t)GMM_AUX_L1_LOW_BIT) / (WA16KEx ? 1 : WA64KEx ? 4 : 64) ) #define GMM_AUX_L2_ENTRY_IDX(GfxAddress) \ (((GfxAddress) & GFX_MASK_LARGE(GMM_AUX_L2_LOW_BIT, GMM_AUX_L2_HIGH_BIT)) >> \ (uint64_t)GMM_AUX_L2_LOW_BIT) #define GMM_AUX_L3_ENTRY_IDX(GfxAddress) \ (((GfxAddress) & GFX_MASK_LARGE(GMM_AUX_L3_LOW_BIT, GMM_AUX_L3_HIGH_BIT)) >> \ (uint64_t)GMM_AUX_L3_LOW_BIT) ////////////////////// Auxiliary Translation Table definitions end////////////////////////////////////////// gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/inc/External/Common/GmmInfo.h000066400000000000000000000760471466655022700253610ustar00rootroot00000000000000/*============================================================================== Copyright(c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ============================================================================*/ #pragma once // GmmConst.h needed for GMM_MAX_NUMBER_MOCS_INDEXES #include "GmmConst.h" #include "../../../Platform/GmmPlatforms.h" #ifdef _WIN32 #define GMM_MUTEX_HANDLE HANDLE #else #include #define GMM_MUTEX_HANDLE pthread_mutex_t #endif // Set packing alignment #pragma pack(push, 8) //=========================================================================== // Forward Declaration: Defined in GmmResourceInfoExt.h //--------------------------------------------------------------------------- struct GMM_CONTEXT_REC; typedef struct GMM_CONTEXT_REC GMM_CONTEXT; //=========================================================================== // typedef: // GMM_UMD_CONTEXT // // Description: // Struct defines user mode GMM context. //---------------------------------------------------------------------------- typedef struct GMM_UMD_CONTEXT_REC { uint32_t TBD1; uint32_t TBD2; uint32_t TBD3; } GMM_UMD_CONTEXT; #if (!defined(__GMM_KMD__) && !defined(GMM_UNIFIED_LIB)) #include "GmmClientContext.h" #endif //=========================================================================== // typedef: // GMM_GLOBAL_CONTEXT // // Description: // Struct contains contexts for user mode and kernel mode. It also contains // platform information. This struct is initialized in user mode with // GmmInitGlobalContext(). // //---------------------------------------------------------------------------- #ifdef __cplusplus #include "GmmMemAllocator.hpp" namespace GmmLib { class NON_PAGED_SECTION Context : public GmmMemAllocator { private: #if(!defined(__GMM_KMD__) && !GMM_LIB_DLL_MA) static int32_t RefCount; #endif #if GMM_LIB_DLL_MA int32_t RefCount; #endif //GMM_LIB_DLL_MA GMM_CLIENT ClientType; GMM_PLATFORM_INFO_CLASS* pPlatformInfo; GMM_TEXTURE_CALC* pTextureCalc; SKU_FEATURE_TABLE SkuTable; WA_TABLE WaTable; GT_SYSTEM_INFO GtSysInfo; #if(defined(__GMM_KMD__)) GMM_GTT_CONTEXT GttContext; #endif GMM_CONTEXT *pGmmKmdContext; GMM_UMD_CONTEXT *pGmmUmdContext; void *pKmdHwDev; void *pUmdAdapter; GMM_CACHE_POLICY_ELEMENT CachePolicy[GMM_RESOURCE_USAGE_MAX]; GMM_CACHE_POLICY_TBL_ELEMENT CachePolicyTbl[GMM_MAX_NUMBER_MOCS_INDEXES]; GMM_CACHE_POLICY *pGmmCachePolicy; #if(defined(__GMM_KMD__)) uint64_t IA32ePATTable; GMM_PRIVATE_PAT PrivatePATTable[GMM_NUM_PAT_ENTRIES]; int32_t PrivatePATTableMemoryType[GMM_NUM_GFX_PAT_TYPES]; #endif // Padding Percentage limit on 64KB paged resource uint32_t AllowedPaddingFor64KbPagesPercentage; uint64_t InternalGpuVaMax; uint32_t AllowedPaddingFor64KBTileSurf; #ifdef GMM_LIB_DLL // Mutex Object used for synchronization of ProcessSingleton Context static GMM_MUTEX_HANDLE SingletonContextSyncMutex; #endif GMM_PRIVATE_PAT PrivatePATTable[GMM_NUM_PAT_ENTRIES]; GMM_MUTEX_HANDLE SyncMutex; // SyncMutex to protect access of Gmm UMD Lib process Singleton Context public : //Constructors and destructors Context(); ~Context(); GMM_STATUS GMM_STDCALL LockSingletonContextSyncMutex(); GMM_STATUS GMM_STDCALL UnlockSingletonContextSyncMutex(); #if GMM_LIB_DLL_MA int32_t IncrementRefCount(); int32_t DecrementRefCount(); #endif //GMM_LIB_DLL_MA #if(!defined(__GMM_KMD__) && (!GMM_LIB_DLL_MA)) static int32_t IncrementRefCount() // Returns the current RefCount and then increment it { #if defined(_WIN32) return(InterlockedIncrement((LONG *)&RefCount) - 1); //InterLockedIncrement() returns incremented value #elif defined(__linux__) return(__sync_fetch_and_add(&RefCount, 1)); #endif } static int32_t DecrementRefCount() { int CurrentValue = 0; int TargetValue = 0; do { CurrentValue = RefCount; if (CurrentValue > 0) { TargetValue = CurrentValue - 1; } else { break; } #if defined(_WIN32) } while (!(InterlockedCompareExchange((LONG *)&RefCount, TargetValue, CurrentValue) == CurrentValue)); #elif defined(__linux__) } while (!__sync_bool_compare_and_swap(&RefCount, CurrentValue, TargetValue)); #endif return TargetValue; } #endif GMM_STATUS GMM_STDCALL InitContext( const PLATFORM& Platform, const SKU_FEATURE_TABLE* pSkuTable, const WA_TABLE* pWaTable, const GT_SYSTEM_INFO* pGtSysInfo, GMM_CLIENT ClientType); void GMM_STDCALL DestroyContext(); #if (!defined(__GMM_KMD__) && !defined(GMM_UNIFIED_LIB)) GMM_CLIENT_CONTEXT *pGmmGlobalClientContext; #endif //Inline functions ///////////////////////////////////////////////////////////////////////// /// Returns the client type e.g. DX, OCL, OGL etc. /// @return client type ///////////////////////////////////////////////////////////////////////// GMM_INLINE GMM_CLIENT GMM_STDCALL GetClientType() { return (ClientType); } ///////////////////////////////////////////////////////////////////////// /// Returns the PlatformInfo /// @return PlatformInfo ///////////////////////////////////////////////////////////////////////// GMM_INLINE GMM_PLATFORM_INFO& GMM_STDCALL GetPlatformInfo() { return (const_cast(pPlatformInfo->GetData())); } ///////////////////////////////////////////////////////////////////////// /// Returns the cache policy element array ptr /// @return const cache policy elment ptr ///////////////////////////////////////////////////////////////////////// GMM_INLINE GMM_CACHE_POLICY_ELEMENT* GMM_STDCALL GetCachePolicyUsage() { return (&CachePolicy[0]); } ///////////////////////////////////////////////////////////////////////// /// Returns the cache policy tlb element array ptr /// @return const cache policy elment ptr ///////////////////////////////////////////////////////////////////////// GMM_INLINE GMM_CACHE_POLICY_TBL_ELEMENT* GMM_STDCALL GetCachePolicyTlbElement() { return (&CachePolicyTbl[0]); } ///////////////////////////////////////////////////////////////////////// /// Returns the texture calculation object ptr /// @return TextureCalc ptr ///////////////////////////////////////////////////////////////////////// GMM_INLINE GMM_TEXTURE_CALC* GMM_STDCALL GetTextureCalc() { return (pTextureCalc); } ///////////////////////////////////////////////////////////////////////// /// Returns the platform info class object ptr /// @return PlatformInfo class object ptr ///////////////////////////////////////////////////////////////////////// GMM_INLINE GMM_PLATFORM_INFO_CLASS* GMM_STDCALL GetPlatformInfoObj() { return (pPlatformInfo); } ///////////////////////////////////////////////////////////////////////// /// Returns the cache policy object ptr /// @return TextureCalc ptr ///////////////////////////////////////////////////////////////////////// GMM_INLINE GMM_CACHE_POLICY* GMM_STDCALL GetCachePolicyObj() { return (pGmmCachePolicy); } ///////////////////////////////////////////////////////////////////////// /// Returns the sku table ptr /// @return const SkuTable ptr ///////////////////////////////////////////////////////////////////////// GMM_INLINE const SKU_FEATURE_TABLE& GMM_STDCALL GetSkuTable() { return (SkuTable); } ///////////////////////////////////////////////////////////////////////// /// Returns the Wa table ptr /// @return WaTable ptr ///////////////////////////////////////////////////////////////////////// GMM_INLINE const WA_TABLE& GMM_STDCALL GetWaTable() { return (WaTable); } ///////////////////////////////////////////////////////////////////////// /// Returns the GT system info ptr /// @return const GtSysInfo ptr ///////////////////////////////////////////////////////////////////////// GMM_INLINE const GT_SYSTEM_INFO* GMM_STDCALL GetGtSysInfoPtr() { return (&GtSysInfo); } ///////////////////////////////////////////////////////////////////////// /// Returns the GT system info ptr /// @return GtSysInfo ptr ///////////////////////////////////////////////////////////////////////// GMM_INLINE GT_SYSTEM_INFO* GMM_STDCALL GetGtSysInfo() { return (&GtSysInfo); } ///////////////////////////////////////////////////////////////////////// /// Returns Cache policy element for a given usage type /// @return cache policy element //////////////////////////////////////////////////////////////////////// GMM_INLINE GMM_CACHE_POLICY_ELEMENT GetCachePolicyElement(GMM_RESOURCE_USAGE_TYPE Usage) { return (CachePolicy[Usage]); } ///////////////////////////////////////////////////////////////////////// /// Get padding percentage limit for 64kb pages ///////////////////////////////////////////////////////////////////////// uint32_t GetAllowedPaddingFor64KbPagesPercentage() { return (AllowedPaddingFor64KbPagesPercentage); } uint64_t& GetInternalGpuVaRangeLimit() { return InternalGpuVaMax; } ///////////////////////////////////////////////////////////////////////// /// Get padding limit for 64k pages ///////////////////////////////////////////////////////////////////////// uint32_t GetAllowedPaddingFor64KBTileSurf() { return (AllowedPaddingFor64KBTileSurf); } ///////////////////////////////////////////////////////////////////////// /// Set padding limit for 64k pages ///////////////////////////////////////////////////////////////////////// GMM_INLINE void SetAllowedPaddingFor64KBTileSurf(uint32_t Value) { AllowedPaddingFor64KBTileSurf = Value; } #ifdef GMM_LIB_DLL ADAPTER_BDF sBdf; // Adpater's Bus, Device and Function info for which Gmm UMD Lib process Singleton Context is created #ifdef _WIN32 // ProcessHeapVA Singleton HeapObj GMM_HEAP *pHeapObj; uint32_t ProcessHeapCounter; // ProcessVA Partition Address space GMM_GFX_PARTITIONING ProcessVA; uint32_t ProcessVACounter; ///////////////////////////////////////////////////////////////////////// /// Get ProcessHeapVA Singleton HeapObj ///////////////////////////////////////////////////////////////////////// GMM_HEAP* GetSharedHeapObject(); ///////////////////////////////////////////////////////////////////////// /// Set ProcessHeapVA Singleton HeapObj ///////////////////////////////////////////////////////////////////////// uint32_t SetSharedHeapObject(GMM_HEAP **pProcessHeapObj); ///////////////////////////////////////////////////////////////////////// /// Get or Sets ProcessGfxPartition VA ///////////////////////////////////////////////////////////////////////// void GetProcessGfxPartition(GMM_GFX_PARTITIONING* pProcessVA); ///////////////////////////////////////////////////////////////////////// /// Get or Sets ProcessGfxPartition VA ///////////////////////////////////////////////////////////////////////// void SetProcessGfxPartition(GMM_GFX_PARTITIONING* pProcessVA); ///////////////////////////////////////////////////////////////////////// /// Destroy Sync Mutex created for Singleton Context access ///////////////////////////////////////////////////////////////////////// static void DestroySingletonContextSyncMutex() { if (SingletonContextSyncMutex) { ::CloseHandle(SingletonContextSyncMutex); SingletonContextSyncMutex = NULL; } } #if !GMM_LIB_DLL_MA ///////////////////////////////////////////////////////////////////////// /// Acquire Sync Mutex for Singleton Context access ///////////////////////////////////////////////////////////////////////// static GMM_STATUS LockSingletonContextSyncMutex() { if (SingletonContextSyncMutex) { while (WAIT_OBJECT_0 != ::WaitForSingleObject(SingletonContextSyncMutex, INFINITE)); return GMM_SUCCESS; } else { return GMM_ERROR; } } ///////////////////////////////////////////////////////////////////////// /// Release Sync Mutex for Singleton Context access ///////////////////////////////////////////////////////////////////////// static GMM_STATUS UnlockSingletonContextSyncMutex() { if (SingletonContextSyncMutex) { ::ReleaseMutex(SingletonContextSyncMutex); return GMM_SUCCESS; } else { return GMM_ERROR; } } #endif //!GMM_LIB_DLL_MA #else // Non Win OS ///////////////////////////////////////////////////////////////////////// /// Destroy Sync Mutex created for Singleton Context access ///////////////////////////////////////////////////////////////////////// static void DestroySingletonContextSyncMutex() { pthread_mutex_destroy(&SingletonContextSyncMutex); } #if !GMM_LIB_DLL_MA ///////////////////////////////////////////////////////////////////////// /// Acquire Sync Mutex for Singleton Context access ///////////////////////////////////////////////////////////////////////// static GMM_STATUS LockSingletonContextSyncMutex() { pthread_mutex_lock(&SingletonContextSyncMutex); return GMM_SUCCESS; } ///////////////////////////////////////////////////////////////////////// /// Release Sync Mutex for Singleton Context access ///////////////////////////////////////////////////////////////////////// static GMM_STATUS UnlockSingletonContextSyncMutex() { pthread_mutex_unlock(&SingletonContextSyncMutex); return GMM_SUCCESS; } #endif //!GMM_LIB_DLL_MA #endif // _WIN32 #endif // GMM_LIB_DLL // KMD specific inline functions #ifdef __GMM_KMD__ ///////////////////////////////////////////////////////////////////////// /// Returns private PAT table memory type for a given PAT type /// @return PAT Memory type ///////////////////////////////////////////////////////////////////////// GMM_INLINE int32_t GMM_STDCALL GetPrivatePATTableMemoryType(GMM_GFX_PAT_TYPE PatType) { return (PrivatePATTableMemoryType[PatType]); } ///////////////////////////////////////////////////////////////////////// /// Returns private PAT table memory type array ptr /// @return PAT Memory type array ptr ///////////////////////////////////////////////////////////////////////// GMM_INLINE int32_t* GMM_STDCALL GetPrivatePATTableMemoryType() { return (PrivatePATTableMemoryType); } ///////////////////////////////////////////////////////////////////////// /// Returns private PAT table array ptr /// @return PAT array ptr ///////////////////////////////////////////////////////////////////////// GMM_INLINE GMM_PRIVATE_PAT* GMM_STDCALL GetPrivatePATTable() { return (PrivatePATTable); } ///////////////////////////////////////////////////////////////////////// /// Returns private PAT table entry for a given PAT index /// @return PAT entry ///////////////////////////////////////////////////////////////////////// GMM_INLINE GMM_PRIVATE_PAT GMM_STDCALL GetPrivatePATEntry(uint32_t PatIndex) { return (PrivatePATTable[PatIndex]); } ///////////////////////////////////////////////////////////////////////// /// Returns gmm kmd context ptr /// @return GmmKmdContext ptr ///////////////////////////////////////////////////////////////////////// GMM_INLINE GMM_CONTEXT* GetGmmKmdContext() { return (pGmmKmdContext); } ///////////////////////////////////////////////////////////////////////// /// Sets gmm kmd context ptr /// @return GmmKmdContext ptr ///////////////////////////////////////////////////////////////////////// GMM_INLINE void SetGmmKmdContext(GMM_CONTEXT *pGmmKmdContext) { this->pGmmKmdContext = pGmmKmdContext; } ///////////////////////////////////////////////////////////////////////// /// Returns gtt context ptr /// @return GttContext ptr ///////////////////////////////////////////////////////////////////////// GMM_INLINE GMM_GTT_CONTEXT* GetGttContext() { return (&GttContext); } ///////////////////////////////////////////////////////////////////////// /// Returns Cache policy tbl element for a given usage type /// @return cache policy tbl element //////////////////////////////////////////////////////////////////////// GMM_INLINE GMM_CACHE_POLICY_TBL_ELEMENT GetCachePolicyTblElement(GMM_RESOURCE_USAGE_TYPE Usage) { return (CachePolicyTbl[Usage]); } ///////////////////////////////////////////////////////////////////////// /// Resets the sku Table after GmmInitContext() could have changed them /// since original latching //////////////////////////////////////////////////////////////////////// GMM_INLINE void SetSkuTable(SKU_FEATURE_TABLE SkuTable) { this->SkuTable = SkuTable; } ///////////////////////////////////////////////////////////////////////// /// Resets the Wa Table after GmmInitContext() could have changed them /// since original latching //////////////////////////////////////////////////////////////////////// GMM_INLINE void SetWaTable(WA_TABLE WaTable) { this->WaTable = WaTable; } #if(_DEBUG || _RELEASE_INTERNAL) ///////////////////////////////////////////////////////////////////////// /// Returns the override platform info class object ptr /// @return PlatformInfo class object ptr ///////////////////////////////////////////////////////////////////////// GMM_INLINE GMM_PLATFORM_INFO_CLASS* GMM_STDCALL GetOverridePlatformInfoObj() { return (Override.pPlatformInfo); } ///////////////////////////////////////////////////////////////////////// /// Returns the override Platform info ptr to kmd /// @return override PlatformInfo ref //////////////////////////////////////////////////////////////////////// GMM_INLINE GMM_PLATFORM_INFO& GMM_STDCALL GetOverridePlatformInfo() { return (const_cast(Override.pPlatformInfo->GetData())); } ///////////////////////////////////////////////////////////////////////// /// Set the override platform info calc ptr //////////////////////////////////////////////////////////////////////// GMM_INLINE void SetOverridePlatformInfoObj(GMM_PLATFORM_INFO_CLASS *pPlatformInfoObj) { Override.pPlatformInfo = pPlatformInfoObj; } ///////////////////////////////////////////////////////////////////////// /// Returns the override Texture calc ptr to kmd /// @return override Texture calc ptr //////////////////////////////////////////////////////////////////////// GMM_INLINE GMM_TEXTURE_CALC* GetOverrideTextureCalc() { return (Override.pTextureCalc); } ///////////////////////////////////////////////////////////////////////// /// Set the override Texture calc ptr //////////////////////////////////////////////////////////////////////// GMM_INLINE void SetOverrideTextureCalc(GMM_TEXTURE_CALC *pTextureCalc) { Override.pTextureCalc = pTextureCalc; } #endif // (_DEBUG || _RELEASE_INTERNAL) #endif // __GMM_KMD__ GMM_CACHE_POLICY* GMM_STDCALL CreateCachePolicyCommon(); GMM_TEXTURE_CALC* GMM_STDCALL CreateTextureCalc(PLATFORM Platform, bool Override); GMM_PLATFORM_INFO_CLASS *GMM_STDCALL CreatePlatformInfo(PLATFORM Platform, bool Override); private: void GMM_STDCALL OverrideSkuWa(); public: ///////////////////////////////////////////////////////////////////////// /// Returns private PAT table array ptr /// @return PAT array ptr ///////////////////////////////////////////////////////////////////////// GMM_INLINE GMM_PRIVATE_PAT *GMM_STDCALL GetPrivatePATTable() { return (&PrivatePATTable[0]); } }; // Max number of Multi-Adapters allowed in the system #define MAX_NUM_ADAPTERS 9 //=========================================================================== // typedef: // _GMM_ADAPTER_INFO_ // // Description: // Struct holds Adapter level information. //---------------------------------------------------------------------------- typedef struct _GMM_ADAPTER_INFO_ { Context *pGmmLibContext; // Gmm UMD Lib Context which is process Singleton _GMM_ADAPTER_INFO_ *pNext; // Linked List Next pointer to point to the Next Adapter node in the List }GMM_ADAPTER_INFO; //////////////////////////////////////////////////////////////////////////////////// /// Multi Adpater Context to hold data related to Multiple Adapters in the system /// Contains functions and members that are needed to support Multi-Adapter. /////////////////////////////////////////////////////////////////////////////////// class NON_PAGED_SECTION GmmMultiAdapterContext : public GmmMemAllocator { private: GMM_ADAPTER_INFO AdapterInfo[MAX_NUM_ADAPTERS];// For Static Initialization of adapter. GMM_MUTEX_HANDLE MAContextSyncMutex; // SyncMutex to protect access of GmmMultiAdpaterContext uint32_t NumAdapters; void* pCpuReserveBase; uint64_t CpuReserveSize; GMM_ADAPTER_INFO *pHeadNode;// For dynamic Initialization of adapter. // The Multi-Adapter Initialization is done dynamiclly using a Linked list Vector // pHeadNode points to the root node of the linked list and registers the first // adapter received from UMD. // thread safe functions; these cannot be called within a LockMAContextSyncMutex block GMM_ADAPTER_INFO * GetAdapterNode(ADAPTER_BDF sBdf); // Replacement for GetAdapterIndex, now get adapter node from the linked list // Mutexes which protect the below thread unsafe functions GMM_STATUS GMM_STDCALL LockMAContextSyncMutex(); GMM_STATUS GMM_STDCALL UnLockMAContextSyncMutex(); // thread unsafe functions; these must be protected with LockMAContextSyncMutex GMM_ADAPTER_INFO * GetAdapterNodeUnlocked(ADAPTER_BDF sBdf); GMM_ADAPTER_INFO * AddAdapterNode(); void RemoveAdapterNode(GMM_ADAPTER_INFO *pNode); public: //Constructors and destructors GmmMultiAdapterContext(); ~GmmMultiAdapterContext(); /* Function prototypes */ /* Functions that update MultiAdapterContext members*/ uint32_t GMM_STDCALL GetAdapterIndex(ADAPTER_BDF sBdf); uint32_t GMM_STDCALL GetNumAdapters(); /* Functions that update AdapterInfo*/ // thread safe functions; these cannot be called within a LockMAContextSyncMutex block #if LHDM GMM_STATUS GMM_STDCALL AddContext(const PLATFORM Platform, const SKU_FEATURE_TABLE *pSkuTable, const WA_TABLE * pWaTable, const GT_SYSTEM_INFO * pGtSysInfo, ADAPTER_BDF sBdf, const char * DeviceRegistryPath); #else GMM_STATUS GMM_STDCALL AddContext(const PLATFORM Platform, const void * pSkuTable, const void * pWaTable, const void * pGtSysInfo, ADAPTER_BDF sBdf, const GMM_CLIENT ClientType); #endif GMM_STATUS GMM_STDCALL RemoveContext(ADAPTER_BDF sBdf); Context* GMM_STDCALL GetAdapterLibContext(ADAPTER_BDF sBdf); }; // GmmMultiAdapterContext } //namespace typedef GmmLib::Context GMM_GLOBAL_CONTEXT, GMM_LIB_CONTEXT; typedef GmmLib::GmmMultiAdapterContext GMM_MA_LIB_CONTEXT; #else struct GmmLibContext; typedef struct GmmLibContext GMM_GLOBAL_CONTEXT, GMM_LIB_CONTEXT; #endif #ifdef __GMM_KMD__ void GMM_STDCALL GmmLinkKmdContextToGlobalInfo(GMM_GLOBAL_CONTEXT *pGmmLibContext, GMM_CONTEXT *pGmmKmdContext); #endif /*__GMM_KMD__*/ //Declare all GMM global context C interfaces. #ifdef __cplusplus extern "C" { #endif /*__cplusplus*/ const GMM_PLATFORM_INFO* GMM_STDCALL GmmGetPlatformInfo(GMM_GLOBAL_CONTEXT *pGmmLibContext); const GMM_CACHE_POLICY_ELEMENT* GmmGetCachePolicyUsage(GMM_GLOBAL_CONTEXT *pGmmLibContext); GMM_TEXTURE_CALC* GmmGetTextureCalc(GMM_GLOBAL_CONTEXT *pGmmLibContext); const SKU_FEATURE_TABLE* GmmGetSkuTable(GMM_GLOBAL_CONTEXT *pGmmLibContext); const WA_TABLE* GmmGetWaTable(GMM_GLOBAL_CONTEXT *pGmmLibContext); const GT_SYSTEM_INFO* GmmGetGtSysInfo(GMM_GLOBAL_CONTEXT *pGmmLibContext); #ifdef __GMM_KMD__ int32_t GmmGetPrivatePATTableMemoryType(GMM_GLOBAL_CONTEXT *pGmmLibContext, GMM_GFX_PAT_TYPE PatType); GMM_CONTEXT* GmmGetGmmKmdContext(GMM_GLOBAL_CONTEXT *pGmmLibContext); GMM_GTT_CONTEXT* GmmGetGttContext(GMM_GLOBAL_CONTEXT *pGmmLibContext); GMM_CACHE_POLICY_TBL_ELEMENT GmmGetCachePolicyTblElement(GMM_GLOBAL_CONTEXT *pGmmLibContext, GMM_RESOURCE_USAGE_TYPE Usage); GMM_CACHE_POLICY_ELEMENT GmmGetCachePolicyElement(GMM_GLOBAL_CONTEXT *pGmmLibContext, GMM_RESOURCE_USAGE_TYPE Usage); void GmmSetSkuTable(GMM_GLOBAL_CONTEXT *pGmmLibContext, SKU_FEATURE_TABLE SkuTable); void GmmSetWaTable(GMM_GLOBAL_CONTEXT *pGmmLibContext, WA_TABLE WaTable); GMM_PLATFORM_INFO* GmmKmdGetPlatformInfo(GMM_GLOBAL_CONTEXT *pGmmLibContext); #if(_DEBUG || _RELEASE_INTERNAL) const GMM_PLATFORM_INFO* GmmGetOverridePlatformInfo(GMM_GLOBAL_CONTEXT *pGmmLibContext); GMM_TEXTURE_CALC* GmmGetOverrideTextureCalc(GMM_GLOBAL_CONTEXT *pGmmLibContext); #endif #endif GMM_PRIVATE_PAT GmmGetPrivatePATEntry(GMM_LIB_CONTEXT *pGmmLibContext, uint32_t PatIndex); #ifdef __cplusplus } #endif /*__cplusplus*/ #define GMM_OVERRIDE_PLATFORM_INFO(pTexInfo,pGmmLibContext) (GmmGetPlatformInfo(pGmmLibContext)) #define GMM_OVERRIDE_TEXTURE_CALC(pTexInfo,pGmmLibContext) (GmmGetTextureCalc(pGmmLibContext)) #ifdef __GMM_KMD__ #define GMM_OVERRIDE_EXPORTED_PLATFORM_INFO(pTexInfo) GMM_OVERRIDE_PLATFORM_INFO(pTexInfo) #define GMM_IS_PLANAR(Format) GmmIsPlanar(Format) #else #define GMM_OVERRIDE_EXPORTED_PLATFORM_INFO(pTexInfo,pGmmLibContext) (&((GmmClientContext*)pClientContext)->GetPlatformInfo()) #define GMM_IS_PLANAR(Format) (pClientContext->IsPlanar(Format)) #endif #define GMM_IS_1MB_AUX_TILEALIGNEDPLANES(Platform, Surf) \ ((GFX_GET_CURRENT_PRODUCT(Platform) >= IGFX_METEORLAKE) && Surf.OffsetInfo.PlaneXe_LPG.Is1MBAuxTAlignedPlanes) // Reset packing alignment to project default #pragma pack(pop) gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/inc/External/Common/GmmInfoExt.h000066400000000000000000000035171466655022700260320ustar00rootroot00000000000000/*============================================================================== Copyright(c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ============================================================================*/ #pragma once #include "GmmInfo.h" #ifdef __cplusplus extern "C" { #endif /*__cplusplus*/ // Set packing alignment #pragma pack(push, 8) //*************************************************************************** // // GMM_GLOBAL_CONTEXT API // //*************************************************************************** void GMM_STDCALL GmmGetCacheSizes(GMM_LIB_CONTEXT *pGmmLibContext, GMM_CACHE_SIZES *CacheSizes); const GMM_PLATFORM_INFO* GMM_STDCALL GmmGetPlatformInfo(GMM_GLOBAL_CONTEXT* pGmmLibContext); // Reset packing alignment to project default #pragma pack(pop) #ifdef __cplusplus } #endif /*__cplusplus*/ gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/inc/External/Common/GmmInternal.h000066400000000000000000000063541466655022700262340ustar00rootroot00000000000000/*============================================================================== Copyright(c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ============================================================================*/ #pragma once #define __STR2__(x) #x #define __STR1__(x) __STR2__(x) #define __LOC__ __FILE__ "(" __STR1__(__LINE__) ") : Warning Msg: " #define __LOC2__ __FILE__ "(" __STR1__(__LINE__) ") : " //#pragma message(__LOC2__ "Header Message") #ifndef _WIN32 #include #endif #if !defined(GMM_DIAG_APP_DIRECTIVE) #include "../../../../inc/umKmInc/sharedata.h" #include "../../../../inc/common/igfxfmid.h" // Contains platform families #include "../../../../inc/common/gfxplatform.h" // __GFX_MACRO_C__ must be defined before #include "../../../../inc/common/gfxmacro.h" // including gfxplatform.h. See Preprocessor settings // has MACRO ops like POW2, MASK, etc. #include "External/Common/GmmDebug.h" // GMM definitions for assert and printf #else #define DRIVER_VERSION_INFO uint32_t #endif //For compile time GFXGEN detection. GMM_GFX_GEN is optional cmd line definition #if (!defined(GMM_GFX_GEN) || (GMM_GFX_GEN == 80)) #define GMM_ENABLE_GEN8 1 #else #define GMM_ENABLE_GEN8 0 #endif #if (!defined(GMM_GFX_GEN) || (GMM_GFX_GEN == 90)) #define GMM_ENABLE_GEN9 1 #else #define GMM_ENABLE_GEN9 0 #endif #if (!defined(GMM_GFX_GEN) || (GMM_GFX_GEN == 100)) #define GMM_ENABLE_GEN10 1 #else #define GMM_ENABLE_GEN10 0 #endif #if (!defined(GMM_GFX_GEN) || (GMM_GFX_GEN == 110)) #define GMM_ENABLE_GEN11 1 #else #define GMM_ENABLE_GEN11 0 #endif #if (!defined(GMM_GFX_GEN) || (GMM_GFX_GEN == 120)) #define GMM_ENABLE_GEN12 1 #else #define GMM_ENABLE_GEN12 0 #endif #if (IGFX_GEN >= IGFX_GEN11) #if !(GMM_ENABLE_GEN8 || GMM_ENABLE_GEN9 || GMM_ENABLE_GEN10 || \ GMM_ENABLE_GEN11 || GMM_ENABLE_GEN12) #error "Unrecognized GMM_GFX_GEN !" #endif #elif (IGFX_GEN >= IGFX_GEN10) #if !(GMM_ENABLE_GEN8 || GMM_ENABLE_GEN9 || GMM_ENABLE_GEN10) #error "Unrecognized GMM_GFX_GEN !" #endif #else #if !(GMM_ENABLE_GEN8 || GMM_ENABLE_GEN9) #error "Unrecognized GMM_GFX_GEN !" #endif #endif gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/inc/External/Common/GmmLibDll.h000077500000000000000000000065361466655022700256270ustar00rootroot00000000000000/*============================================================================== Copyright(c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ============================================================================*/ #pragma once #include "GmmCommonExt.h" #include "GmmInfo.h" typedef struct _GMM_INIT_IN_ARGS_ { PLATFORM Platform; void *pSkuTable; void *pWaTable; void *pGtSysInfo; uint32_t FileDescriptor; GMM_CLIENT ClientType; } GMM_INIT_IN_ARGS; typedef struct _GMM_INIT_OUT_ARGS_ { GMM_CLIENT_CONTEXT *pGmmClientContext; } GMM_INIT_OUT_ARGS; // Interfaces exported from GMM Lib DLL typedef struct _GmmExportEntries { #ifdef _WIN32 GMM_STATUS (GMM_STDCALL *pfnCreateSingletonContext)(const PLATFORM Platform, const SKU_FEATURE_TABLE* pSkuTable, const WA_TABLE* pWaTable, const GT_SYSTEM_INFO* pGtSysInfo); #else GMM_STATUS(GMM_STDCALL *pfnCreateSingletonContext)(const PLATFORM Platform, const void* pSkuTable, const void* pWaTable, const void* pGtSysInfo); #endif void (GMM_STDCALL *pfnDestroySingletonContext)(void); GMM_CLIENT_CONTEXT* (GMM_STDCALL *pfnCreateClientContext)(GMM_CLIENT ClientType); void (GMM_STDCALL *pfnDeleteClientContext)(GMM_CLIENT_CONTEXT *pGmmClientContext); }GmmExportEntries; #ifdef __cplusplus extern "C" { #endif ///////////////////////////////////////////////////////////////////////////////////// /// Only function exported from GMM lib DLL. ///////////////////////////////////////////////////////////////////////////////////// GMM_LIB_API GMM_STATUS GMM_STDCALL InitializeGmm(GMM_INIT_IN_ARGS *pInArgs, GMM_INIT_OUT_ARGS *pOutArgs); GMM_LIB_API void GMM_STDCALL GmmAdapterDestroy(GMM_INIT_OUT_ARGS *pInArgs); #ifdef __cplusplus } #endif typedef GMM_STATUS (GMM_STDCALL *pfnGmmEntry)(GmmExportEntries *); typedef GMM_STATUS (GMM_STDCALL *pfnGmmInit)(GMM_INIT_IN_ARGS *, GMM_INIT_OUT_ARGS *); typedef void (GMM_STDCALL *pfnGmmDestroy)(GMM_INIT_OUT_ARGS *); gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/inc/External/Common/GmmLibDllName.h000077500000000000000000000037131466655022700264220ustar00rootroot00000000000000/*============================================================================== Copyright(c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ============================================================================*/ #pragma once #if defined(_WIN64 ) || defined(__x86_64__) || defined(__LP64__) #define GMM_ADAPTER_INIT_NAME "InitializeGmm" #define GMM_ADAPTER_DESTROY_NAME "GmmAdapterDestroy" #if defined(_WIN64) #define GMM_UMD_DLL "igdgmm64.dll" #elif defined(ANDROID) #define GMM_UMD_DLL "libigdgmm.so" #else #define GMM_UMD_DLL "libigdgmm.so.12" #endif #else #define GMM_ADAPTER_INIT_NAME "_InitializeGmm@8" #define GMM_ADAPTER_DESTROY_NAME "_GmmAdapterDestroy@4" #if defined(_WIN32) #define GMM_UMD_DLL "igdgmm32.dll" #elif defined(ANDROID) #define GMM_UMD_DLL "libigdgmm.so" #else #define GMM_UMD_DLL "libigdgmm.so.12" #endif #endif gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/inc/External/Common/GmmMemAllocator.hpp000066400000000000000000000042141466655022700273700ustar00rootroot00000000000000/*============================================================================== Copyright(c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ============================================================================*/ #pragma once #include "GmmUtil.h" #include #define NON_PAGED_SECTION #define GMM_MALLOC(size) malloc(size) #define GMM_FREE(p) free(p) ///////////////////////////////////////////////////////////// /// Overrides new() and delete() to work with both user mode /// and kernel mode. ///////////////////////////////////////////////////////////// class NON_PAGED_SECTION GmmMemAllocator { public: void* operator new(size_t size) { return GMM_MALLOC(size); } void* operator new(size_t size, void* ptr) { GMM_UNREFERENCED_PARAMETER(size); return ptr; } void operator delete(void *ptr) { GMM_FREE(ptr); } void operator delete(void *ptr, void *place) { GMM_UNREFERENCED_PARAMETER(ptr); GMM_UNREFERENCED_PARAMETER(place); // placement delete -- nothing to do. } }; gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/inc/External/Common/GmmPageTableMgr.h000066400000000000000000000162341466655022700267500ustar00rootroot00000000000000/*============================================================================== Copyright(c) 2019 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. Description: This file contains the class definitions for GmmPageTableMgr for user-mode PageTable management, that is common for both Linux and Windows. ============================================================================*/ #pragma once #include "GmmHw.h" #ifdef __linux__ #include #endif typedef enum _GMM_ENGINE_TYPE { ENGINE_TYPE_RCS = 0, //RCS ENGINE_TYPE_COMPUTE = 1, //Compute-CS ENGINE_TYPE_BCS, //BLT ENGINE_TYPE_VD0, ENGINE_TYPE_VD1, ENGINE_TYPE_VE0 //Add all engines supporting AUX-TT } GMM_ENGINE_TYPE; typedef enum TT_Flags { AUXTT = 1, //Indicate TT request for AUX i.e. e2e compression } TT_TYPE; #if !(defined(__GMM_KMD__)) // Shared Structure for both Windows and Linux typedef struct __GMM_DDI_UPDATEAUXTABLE { GMM_UMD_SYNCCONTEXT * UmdContext; // [in] pointer to thread-specific data, specifying BBQHandle/Fence etc GMM_RESOURCE_INFO * BaseResInfo; // [in] GmmResourceInfo ptr for compressed resource GMM_RESOURCE_INFO * AuxResInfo; // [in] GmmResourceInfo ptr for separate Auxiliary resource GMM_GFX_ADDRESS BaseGpuVA; // [in] GPUVA where compressed resource has been mapped GMM_GFX_ADDRESS AuxSurfVA; // [in] GPUVA where separate Auxiliary resource has been mapped uint8_t Map; // [in] specifies if resource is being mapped or unmapped uint8_t DoNotWait; // [in] specifies if PageTable update be done on CPU (true) or GPU (false) }GMM_DDI_UPDATEAUXTABLE; #ifdef __cplusplus #include "GmmMemAllocator.hpp" namespace GmmLib { class SyncInfoLin { //dummy class public: HANDLE BBQueueHandle; uint64_t BBFence; SyncInfoLin() : BBQueueHandle(NULL), BBFence(0) {} SyncInfoLin(HANDLE Handle, uint64_t Fence) : BBQueueHandle(Handle), BBFence(Fence) {} }; typedef class SyncInfoLin SyncInfo; //Forward class declarations class AuxTable; class GmmPageTablePool; typedef class GmmPageTablePool GMM_PAGETABLEPool; typedef enum POOL_TYPE_REC { POOL_TYPE_TRTTL1 = 0, POOL_TYPE_TRTTL2 = 1, POOL_TYPE_AUXTTL1 = 2, POOL_TYPE_AUXTTL2 = 3, } POOL_TYPE; ////////////////////////////////////////////////////////////////////////////////////////////// /// Contains functions and members for GMM_PAGETABLE_MGR, clients must place its pointer in /// their device object. Clients call GmmLib to initialize the instance and use it for mapping /// /unmapping on GmmLib managed page tables (TR-TT for SparseResources, AUX-TT for compression) ////////////////////////////////////////////////////////////////////////////////////////////// class GMM_LIB_API NON_PAGED_SECTION GmmPageTableMgr : public GmmMemAllocator { private: GMM_ENGINE_TYPE EngType; //PageTable managed @ device-level (specifies engine associated with the device) AuxTable* AuxTTObj; //Auxiliary Translation Table obj GMM_PAGETABLEPool *pPool; //Common page table pool uint32_t NumNodePoolElements; GmmClientContext *pClientContext; ///< ClientContext of the client creating this Object //OS-specific defn #if defined __linux__ pthread_mutex_t PoolLock; #endif public: GMM_DEVICE_CALLBACKS DeviceCb; //OS-specific defn: Will be used by Clients to send as input arguments for TR-TT APIs GMM_DEVICE_CALLBACKS_INT DeviceCbInt; //OS-specific defn: Will be used internally GMM lib GMM_TRANSLATIONTABLE_CALLBACKS TTCb; //OS-specific defn HANDLE hCsr; // OCL per-device command stream receiver handle for aubcapture public: GmmPageTableMgr(); GmmPageTableMgr(GMM_DEVICE_CALLBACKS_INT *, uint32_t TTFlags, GmmClientContext *pClientContextIn); // Allocates memory for indicate TT’s root-tables, initializes common node-pool //GMM_VIRTUAL GMM_GFX_ADDRESS GetTRL3TableAddr(); GMM_VIRTUAL GMM_GFX_ADDRESS GetAuxL3TableAddr(); //Update TT root table address in context-image GMM_VIRTUAL GMM_STATUS InitContextAuxTableRegister(HANDLE initialBBHandle, GMM_ENGINE_TYPE engType); //Clients call it to update Aux-Table pointer in context-image, engType reqd. if @ context level //Aux TT management API GMM_VIRTUAL GMM_STATUS UpdateAuxTable(const GMM_DDI_UPDATEAUXTABLE*); //new API for updating Aux-Table to point to correct 16B-chunk //for given host page VA when base/Aux surf is mapped/unmapped GMM_VIRTUAL void __ReleaseUnusedPool(GMM_UMD_SYNCCONTEXT *UmdContext); GMM_VIRTUAL GMM_PAGETABLEPool * __GetFreePoolNode(uint32_t * FreePoolNodeIdx, POOL_TYPE PoolType); #if defined __linux__ //returns number of BOs for indicated TTs = NumNodePoolElements+1 BOs for root table and pools GMM_VIRTUAL int GetNumOfPageTableBOs(uint8_t TTFlags); //returns BO* list for indicated TT in client allocated memory GMM_VIRTUAL int GetPageTableBOList(uint8_t TTFlags, void* BOList); #endif //Destructor GMM_VIRTUAL ~GmmPageTableMgr(); //Clean-up page table structures // Inline Functions ///////////////////////////////////////////////////////////////////////////////////// /// Returns GmmClientContext associated with this PageTableMgr /// @return ::GmmClientContext ///////////////////////////////////////////////////////////////////////////////////// GMM_INLINE_VIRTUAL GmmClientContext* GetClientContext() { return pClientContext; } private: GMM_PAGETABLEPool * __AllocateNodePool(uint32_t AddrAlignment, POOL_TYPE Type); GMM_INLINE GMM_LIB_CONTEXT *GetLibContext() { return pClientContext->GetLibContext(); } }; } #endif // #ifdef __cplusplus #endif gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/inc/External/Common/GmmPlatformExt.h000066400000000000000000000606121466655022700267220ustar00rootroot00000000000000/*============================================================================== Copyright(c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ============================================================================*/ #pragma once typedef enum GMM_FLATCCS_FORMAT_ENUM { GMM_FLATCCS_FORMAT_R16S = 0, GMM_FLATCCS_FORMAT_R16U = GMM_FLATCCS_FORMAT_R16S, GMM_FLATCCS_FORMAT_RG16F = GMM_FLATCCS_FORMAT_R16S, GMM_FLATCCS_FORMAT_RG16U = GMM_FLATCCS_FORMAT_R16S, GMM_FLATCCS_FORMAT_RG16S = GMM_FLATCCS_FORMAT_R16S, GMM_FLATCCS_FORMAT_RGBA16S = GMM_FLATCCS_FORMAT_R16S, GMM_FLATCCS_FORMAT_RGBA16U = GMM_FLATCCS_FORMAT_R16S, GMM_FLATCCS_FORMAT_RGBA16F = GMM_FLATCCS_FORMAT_R16S, GMM_FLATCCS_MIN_RC_FORMAT = GMM_FLATCCS_FORMAT_R16S, GMM_FLATCCS_FORMAT_R32F, GMM_FLATCCS_FORMAT_R32S = GMM_FLATCCS_FORMAT_R32F, GMM_FLATCCS_FORMAT_R32U = GMM_FLATCCS_FORMAT_R32F, GMM_FLATCCS_FORMAT_RG32F = GMM_FLATCCS_FORMAT_R32F, GMM_FLATCCS_FORMAT_RG32S = GMM_FLATCCS_FORMAT_R32F, GMM_FLATCCS_FORMAT_RG32U = GMM_FLATCCS_FORMAT_R32F, GMM_FLATCCS_FORMAT_RGBA32F = GMM_FLATCCS_FORMAT_R32F, GMM_FLATCCS_FORMAT_RGBA32S = GMM_FLATCCS_FORMAT_R32F, GMM_FLATCCS_FORMAT_RGBA32U = GMM_FLATCCS_FORMAT_R32F, GMM_FLATCCS_FORMAT_RGB5A1, GMM_FLATCCS_FORMAT_RGBA4 = GMM_FLATCCS_FORMAT_RGB5A1, GMM_FLATCCS_FORMAT_B5G6R5 = GMM_FLATCCS_FORMAT_RGB5A1, GMM_FLATCCS_FORMAT_R8S = GMM_FLATCCS_FORMAT_RGB5A1, GMM_FLATCCS_FORMAT_R8U = GMM_FLATCCS_FORMAT_RGB5A1, GMM_FLATCCS_FORMAT_RG8S = GMM_FLATCCS_FORMAT_RGB5A1, GMM_FLATCCS_FORMAT_RG8U = GMM_FLATCCS_FORMAT_RGB5A1, GMM_FLATCCS_FORMAT_RGBA8S = GMM_FLATCCS_FORMAT_RGB5A1, GMM_FLATCCS_FORMAT_RGBA8U = GMM_FLATCCS_FORMAT_RGB5A1, GMM_FLATCCS_FORMAT_ML8 = GMM_FLATCCS_FORMAT_RGB5A1, GMM_FLATCCS_FORMAT_RGB10A2, GMM_FLATCCS_FORMAT_RG11B10, GMM_FLATCCS_FORMAT_R32F1, GMM_FLATCCS_FORMAT_R32S1 = GMM_FLATCCS_FORMAT_R32F1, GMM_FLATCCS_FORMAT_R32U1 = GMM_FLATCCS_FORMAT_R32F1, GMM_FLATCCS_FORMAT_D32U = GMM_FLATCCS_FORMAT_R32F1, GMM_FLATCCS_FORMAT_R16F1, GMM_FLATCCS_FORMAT_R16S1 = GMM_FLATCCS_FORMAT_R16F1, GMM_FLATCCS_FORMAT_R16U1 = GMM_FLATCCS_FORMAT_R16F1, GMM_FLATCCS_FORMAT_R8S1, GMM_FLATCCS_FORMAT_R8U1 = GMM_FLATCCS_FORMAT_R8S1, GMM_FLATCCS_MAX_RC_FORMAT = GMM_FLATCCS_FORMAT_R8U1, GMM_FLATCCS_MIN_MC_FORMAT = 0x21, //(0x1 <<5) ie Msb-5th bit turned on to identify MC encoding, to drop before SurfaceState usage GMM_FLATCCS_FORMAT_RGBA16_MEDIA = GMM_FLATCCS_MIN_MC_FORMAT, GMM_FLATCCS_FORMAT_Y210, GMM_FLATCCS_FORMAT_YUY2, GMM_FLATCCS_FORMAT_Y410, GMM_FLATCCS_FORMAT_Y216, GMM_FLATCCS_FORMAT_Y416, GMM_FLATCCS_FORMAT_P010, GMM_FLATCCS_FORMAT_P010_L = GMM_FLATCCS_FORMAT_P010, //MC 7h GMM_FLATCCS_FORMAT_P010_C = GMM_FLATCCS_FORMAT_P010, //MC 7h GMM_FLATCCS_FORMAT_P016, GMM_FLATCCS_FORMAT_P016_L = GMM_FLATCCS_FORMAT_P016, //MC 8h GMM_FLATCCS_FORMAT_P016_C = GMM_FLATCCS_FORMAT_P016, //MC 8h GMM_FLATCCS_FORMAT_AYUV, GMM_FLATCCS_FORMAT_ARGB8b, GMM_FLATCCS_FORMAT_SWAPY, GMM_FLATCCS_FORMAT_SWAPUV, GMM_FLATCCS_FORMAT_SWAPUVY, GMM_FLATCCS_FORMAT_RGB10b, GMM_FLATCCS_FORMAT_NV12, GMM_FLATCCS_FORMAT_NV12_L = GMM_FLATCCS_FORMAT_NV12, GMM_FLATCCS_FORMAT_NV12_C = GMM_FLATCCS_FORMAT_NV12, GMM_FLATCCS_FORMAT_YCRCB_SWAPUV = GMM_FLATCCS_FORMAT_SWAPUV, GMM_FLATCCS_FORMAT_YCRCB_SWAPUVY = GMM_FLATCCS_FORMAT_SWAPUVY, GMM_FLATCCS_FORMAT_YCRCB_SWAPY = GMM_FLATCCS_FORMAT_SWAPY, GMM_FLATCCS_MAX_MC_FORMAT = GMM_FLATCCS_FORMAT_NV12, //should always be equal to last format encoding GMM_FLATCCS_FORMAT_INVALID, //equal to last valid encoding plus one } GMM_FLATCCS_FORMAT; typedef enum GMM_XE2_UNIFIED_COMP_FORMAT_ENUM { GMM_XE2_UNIFIED_COMP_FORMAT_R8 = 0, //0h – bpc8 ‘R’ GMM_XE2_UNIFIED_COMP_MIN_FORMAT = GMM_XE2_UNIFIED_COMP_FORMAT_R8, GMM_XE2_UNIFIED_COMP_FORMAT_NV12_L = GMM_XE2_UNIFIED_COMP_FORMAT_R8, GMM_XE2_UNIFIED_COMP_FORMAT_D32U = GMM_XE2_UNIFIED_COMP_FORMAT_R8, GMM_XE2_UNIFIED_COMP_FORMAT_R8U = GMM_XE2_UNIFIED_COMP_FORMAT_R8, GMM_XE2_UNIFIED_COMP_FORMAT_R8S = GMM_XE2_UNIFIED_COMP_FORMAT_R8, GMM_XE2_UNIFIED_COMP_FORMAT_R8U1 = GMM_XE2_UNIFIED_COMP_FORMAT_R8, GMM_XE2_UNIFIED_COMP_FORMAT_R8S1 = GMM_XE2_UNIFIED_COMP_FORMAT_R8, GMM_XE2_UNIFIED_COMP_FORMAT_RG8, //1h – bpc8 ‘RG’ GMM_XE2_UNIFIED_COMP_FORMAT_RGB5A1 = GMM_XE2_UNIFIED_COMP_FORMAT_RG8, GMM_XE2_UNIFIED_COMP_FORMAT_RGBA4 = GMM_XE2_UNIFIED_COMP_FORMAT_RG8, GMM_XE2_UNIFIED_COMP_FORMAT_B5G6R5 = GMM_XE2_UNIFIED_COMP_FORMAT_RG8, GMM_XE2_UNIFIED_COMP_FORMAT_NV12_C = GMM_XE2_UNIFIED_COMP_FORMAT_RG8, GMM_XE2_UNIFIED_COMP_FORMAT_RG8U = GMM_XE2_UNIFIED_COMP_FORMAT_RG8, GMM_XE2_UNIFIED_COMP_FORMAT_RG8S = GMM_XE2_UNIFIED_COMP_FORMAT_RG8, GMM_XE2_UNIFIED_COMP_FORMAT_RGBA8, // 2h – bpc8 ‘RGBA’ GMM_XE2_UNIFIED_COMP_FORMAT_RGBA8U = GMM_XE2_UNIFIED_COMP_FORMAT_RGBA8, GMM_XE2_UNIFIED_COMP_FORMAT_RGBA8S = GMM_XE2_UNIFIED_COMP_FORMAT_RGBA8, GMM_XE2_UNIFIED_COMP_FORMAT_YUY2 = GMM_XE2_UNIFIED_COMP_FORMAT_RGBA8, GMM_XE2_UNIFIED_COMP_FORMAT_AYUV = GMM_XE2_UNIFIED_COMP_FORMAT_RGBA8, GMM_XE2_UNIFIED_COMP_FORMAT_YCRCB = GMM_XE2_UNIFIED_COMP_FORMAT_RGBA8, GMM_XE2_UNIFIED_COMP_FORMAT_SWAPY = GMM_XE2_UNIFIED_COMP_FORMAT_YCRCB, GMM_XE2_UNIFIED_COMP_FORMAT_SWAPUV = GMM_XE2_UNIFIED_COMP_FORMAT_YCRCB, GMM_XE2_UNIFIED_COMP_FORMAT_SWAPUVY = GMM_XE2_UNIFIED_COMP_FORMAT_YCRCB, GMM_XE2_UNIFIED_COMP_FORMAT_YCRCB_SWAPUV = GMM_XE2_UNIFIED_COMP_FORMAT_YCRCB, GMM_XE2_UNIFIED_COMP_FORMAT_YCRCB_SWAPUVY = GMM_XE2_UNIFIED_COMP_FORMAT_YCRCB, GMM_XE2_UNIFIED_COMP_FORMAT_YCRCB_SWAPY = GMM_XE2_UNIFIED_COMP_FORMAT_YCRCB, GMM_XE2_UNIFIED_COMP_FORMAT_RGB10A2, // 3h – 3bpc10_1bpc2 ‘RGBA10A2’ GMM_XE2_UNIFIED_COMP_FORMAT_Y410 = GMM_XE2_UNIFIED_COMP_FORMAT_RGB10A2, GMM_XE2_UNIFIED_COMP_FORMAT_RG11B10, // 4h - 2bpc11_1bpc10 ‘RG11B10’ GMM_XE2_UNIFIED_COMP_FORMAT_R16, // 5h - bpc16 ‘R’ GMM_XE2_UNIFIED_COMP_FORMAT_R16U = GMM_XE2_UNIFIED_COMP_FORMAT_R16, GMM_XE2_UNIFIED_COMP_FORMAT_R16S = GMM_XE2_UNIFIED_COMP_FORMAT_R16, GMM_XE2_UNIFIED_COMP_FORMAT_R16F1 = GMM_XE2_UNIFIED_COMP_FORMAT_R16, GMM_XE2_UNIFIED_COMP_FORMAT_R16U1 = GMM_XE2_UNIFIED_COMP_FORMAT_R16, GMM_XE2_UNIFIED_COMP_FORMAT_R16S1 = GMM_XE2_UNIFIED_COMP_FORMAT_R16, GMM_XE2_UNIFIED_COMP_FORMAT_P010_L = GMM_XE2_UNIFIED_COMP_FORMAT_R16, GMM_XE2_UNIFIED_COMP_FORMAT_P016_L = GMM_XE2_UNIFIED_COMP_FORMAT_R16, GMM_XE2_UNIFIED_COMP_FORMAT_RG16, // 6h – bpc16 ‘RG’ GMM_XE2_UNIFIED_COMP_FORMAT_RG16U = GMM_XE2_UNIFIED_COMP_FORMAT_RG16, GMM_XE2_UNIFIED_COMP_FORMAT_RG16F = GMM_XE2_UNIFIED_COMP_FORMAT_RG16, GMM_XE2_UNIFIED_COMP_FORMAT_RG16S = GMM_XE2_UNIFIED_COMP_FORMAT_RG16, GMM_XE2_UNIFIED_COMP_FORMAT_P010_C = GMM_XE2_UNIFIED_COMP_FORMAT_RG16, GMM_XE2_UNIFIED_COMP_FORMAT_P016_C = GMM_XE2_UNIFIED_COMP_FORMAT_RG16, GMM_XE2_UNIFIED_COMP_FORMAT_RGBA16, // 7h - bpc16 ‘RGBA’ GMM_XE2_UNIFIED_COMP_FORMAT_RGBA16U = GMM_XE2_UNIFIED_COMP_FORMAT_RGBA16, GMM_XE2_UNIFIED_COMP_FORMAT_RGBA16F = GMM_XE2_UNIFIED_COMP_FORMAT_RGBA16, GMM_XE2_UNIFIED_COMP_FORMAT_RGBA16S = GMM_XE2_UNIFIED_COMP_FORMAT_RGBA16, GMM_XE2_UNIFIED_COMP_FORMAT_R32, // 8h - bpc32 ‘R’ GMM_XE2_UNIFIED_COMP_FORMAT_R32U = GMM_XE2_UNIFIED_COMP_FORMAT_R32, GMM_XE2_UNIFIED_COMP_FORMAT_R32F = GMM_XE2_UNIFIED_COMP_FORMAT_R32, GMM_XE2_UNIFIED_COMP_FORMAT_R32S = GMM_XE2_UNIFIED_COMP_FORMAT_R32, GMM_XE2_UNIFIED_COMP_FORMAT_R32U1 = GMM_XE2_UNIFIED_COMP_FORMAT_R32, GMM_XE2_UNIFIED_COMP_FORMAT_R32F1 = GMM_XE2_UNIFIED_COMP_FORMAT_R32, GMM_XE2_UNIFIED_COMP_FORMAT_R32S1 = GMM_XE2_UNIFIED_COMP_FORMAT_R32, GMM_XE2_UNIFIED_COMP_FORMAT_RG32, // 9h - bpc32 ‘RG’ GMM_XE2_UNIFIED_COMP_FORMAT_RG32U = GMM_XE2_UNIFIED_COMP_FORMAT_RG32, GMM_XE2_UNIFIED_COMP_FORMAT_RG32F = GMM_XE2_UNIFIED_COMP_FORMAT_RG32, GMM_XE2_UNIFIED_COMP_FORMAT_RG32S = GMM_XE2_UNIFIED_COMP_FORMAT_RG32, GMM_XE2_UNIFIED_COMP_FORMAT_RGBA32, // 10h - bpc32 ‘RGBA’ GMM_XE2_UNIFIED_COMP_FORMAT_RGBA32U = GMM_XE2_UNIFIED_COMP_FORMAT_RGBA32, GMM_XE2_UNIFIED_COMP_FORMAT_RGBA32F = GMM_XE2_UNIFIED_COMP_FORMAT_RGBA32, GMM_XE2_UNIFIED_COMP_FORMAT_RGBA32S = GMM_XE2_UNIFIED_COMP_FORMAT_RGBA32, GMM_XE2_UNIFIED_COMP_FORMAT_Y210, // 11h – packed YUV (Y210, Y416, Y216) GMM_XE2_UNIFIED_COMP_FORMAT_Y216 = GMM_XE2_UNIFIED_COMP_FORMAT_Y210, GMM_XE2_UNIFIED_COMP_FORMAT_Y416 = GMM_XE2_UNIFIED_COMP_FORMAT_Y210, GMM_XE2_UNIFIED_COMP_FORMAT_RSVD1, // 12h – Unused GMM_XE2_UNIFIED_COMP_FORMAT_HW_RSVD, // 13h – HW Stateless from MMIO or Uncompressed GMM_XE2_UNIFIED_COMP_FORMAT_RSVD2_, // 13h – Stateless MMIO CMF? GMM_XE2_UNIFIED_COMP_FORMAT_ML8 = 0xF, // 15h – ML and Lossy-Compressed textures GMM_XE2_UNIFIED_COMP_MAX_FORMAT = GMM_XE2_UNIFIED_COMP_FORMAT_ML8, GMM_XE2_UNIFIED_COMP_FORMAT_INVALID, //equal to last valid encoding plus one } GMM_XE2_UNIFIED_COMP_FORMAT; typedef enum GMM_UNIFIED_COMP_FORMAT_ENUM { GMM_UNIFIED_COMP_FORMAT_RGBA32F = 0, //0h - bpc32 RGBA F/S GMM_UNIFIED_COMP_FORMAT_RGBA32S = GMM_UNIFIED_COMP_FORMAT_RGBA32F, GMM_UNIFIED_COMP_MIN_RC_FORMAT = GMM_UNIFIED_COMP_FORMAT_RGBA32F, GMM_UNIFIED_COMP_FORMAT_RGBA32U, //1h - bpc32 RGBA U GMM_UNIFIED_COMP_FORMAT_RG32F, // 2h - bpc32 RG F/S GMM_UNIFIED_COMP_FORMAT_RG32S = GMM_UNIFIED_COMP_FORMAT_RG32F, GMM_UNIFIED_COMP_FORMAT_RG32U, // 3h - bpc32 RG U GMM_UNIFIED_COMP_FORMAT_RGBA16U, // 4h - bpc16 RGBA U GMM_UNIFIED_COMP_FORMAT_RGBA16F, // 5h - bpc16 RGBA F/S GMM_UNIFIED_COMP_FORMAT_RGBA16S = GMM_UNIFIED_COMP_FORMAT_RGBA16F, GMM_UNIFIED_COMP_FORMAT_RG16U, // 6h - bpc16 RG U GMM_UNIFIED_COMP_FORMAT_RG16F, // 7h - bpc16 RG F/S GMM_UNIFIED_COMP_FORMAT_RG16S = GMM_UNIFIED_COMP_FORMAT_RG16F, GMM_UNIFIED_COMP_FORMAT_RGBA8U, // 8h - bpc8 RGBA U GMM_UNIFIED_COMP_FORMAT_RGBA8S, // 9h - bpc8 RGBA S GMM_UNIFIED_COMP_FORMAT_RGB5A1, // Ah - bpc8 GMM_UNIFIED_COMP_FORMAT_RGBA4 = GMM_UNIFIED_COMP_FORMAT_RGB5A1, GMM_UNIFIED_COMP_FORMAT_B5G6R5 = GMM_UNIFIED_COMP_FORMAT_RGB5A1, GMM_UNIFIED_COMP_FORMAT_RG8U = GMM_UNIFIED_COMP_FORMAT_RGB5A1, GMM_UNIFIED_COMP_FORMAT_RG8S, // Bh - bpc8 GMM_UNIFIED_COMP_FORMAT_RGB10A2, // Ch - bpc8 GMM_UNIFIED_COMP_FORMAT_RG11B10, // Dh - bpc8 GMM_UNIFIED_COMP_FORMAT_R32F = 0x10, // 10h - bpc32 R F/S GMM_UNIFIED_COMP_FORMAT_R32F1 = GMM_UNIFIED_COMP_FORMAT_R32F, GMM_UNIFIED_COMP_FORMAT_R32S = GMM_UNIFIED_COMP_FORMAT_R32F, GMM_UNIFIED_COMP_FORMAT_R32S1 = GMM_UNIFIED_COMP_FORMAT_R32F, GMM_UNIFIED_COMP_FORMAT_R32U, // 11h - bpc32 R U GMM_UNIFIED_COMP_FORMAT_R32U1 = GMM_UNIFIED_COMP_FORMAT_R32U, GMM_UNIFIED_COMP_FORMAT_D32U = GMM_UNIFIED_COMP_FORMAT_R32U, GMM_UNIFIED_COMP_FORMAT_R16U = 0x14, // 14h - bpc16 R U GMM_UNIFIED_COMP_FORMAT_R16U1 = GMM_UNIFIED_COMP_FORMAT_R16U, // 14h - bpc16 R U GMM_UNIFIED_COMP_FORMAT_R16F, // 15h - bpc16 R F/S GMM_UNIFIED_COMP_FORMAT_R16F1 = GMM_UNIFIED_COMP_FORMAT_R16F, GMM_UNIFIED_COMP_FORMAT_R16S = GMM_UNIFIED_COMP_FORMAT_R16F, GMM_UNIFIED_COMP_FORMAT_R16S1 = GMM_UNIFIED_COMP_FORMAT_R16F, GMM_UNIFIED_COMP_FORMAT_R8U = 0x18, // 18h - bpc8 R U GMM_UNIFIED_COMP_FORMAT_R8U1 = GMM_UNIFIED_COMP_FORMAT_R8U, GMM_UNIFIED_COMP_FORMAT_R8S, // 19h - bpc8 R S GMM_UNIFIED_COMP_FORMAT_R8S1 = GMM_UNIFIED_COMP_FORMAT_R8S, GMM_UNIFIED_COMP_FORMAT_ML8 = 0x1F, GMM_UNIFIED_COMP_MAX_RC_FORMAT = GMM_UNIFIED_COMP_FORMAT_ML8, GMM_UNIFIED_COMP_MIN_MC_FORMAT = 0x21, //(0x1 <<5) ie Msb-5th bit turned on to identify MC encoding, to drop before SurfaceState usage GMM_UNIFIED_COMP_FORMAT_RGBA16_MEDIA = GMM_UNIFIED_COMP_MIN_MC_FORMAT, //MC 1h GMM_UNIFIED_COMP_FORMAT_Y210, //MC 2h GMM_UNIFIED_COMP_FORMAT_YUY2, //MC 3h GMM_UNIFIED_COMP_FORMAT_Y410, //MC 4h GMM_UNIFIED_COMP_FORMAT_Y216, //MC 5h GMM_UNIFIED_COMP_FORMAT_Y416, //MC 6h GMM_UNIFIED_COMP_FORMAT_P010, //MC 7h GMM_UNIFIED_COMP_FORMAT_P010_L = GMM_UNIFIED_COMP_FORMAT_P010, GMM_UNIFIED_COMP_FORMAT_P010_C = GMM_UNIFIED_COMP_FORMAT_P010, GMM_UNIFIED_COMP_FORMAT_P016, //MC 8h GMM_UNIFIED_COMP_FORMAT_P016_L = GMM_UNIFIED_COMP_FORMAT_P016, GMM_UNIFIED_COMP_FORMAT_P016_C = GMM_UNIFIED_COMP_FORMAT_P016, GMM_UNIFIED_COMP_FORMAT_AYUV, //MC 9h GMM_UNIFIED_COMP_FORMAT_ARGB8b, //MC Ah GMM_UNIFIED_COMP_FORMAT_SWAPY, //MC Bh GMM_UNIFIED_COMP_FORMAT_SWAPUV, //MC Ch GMM_UNIFIED_COMP_FORMAT_SWAPUVY, //MC Dh GMM_UNIFIED_COMP_FORMAT_RGB10b, //MC Eh --Which media format is it? GMM_UNIFIED_COMP_FORMAT_NV12, //MC Fh GMM_UNIFIED_COMP_FORMAT_NV12_L = GMM_UNIFIED_COMP_FORMAT_NV12, GMM_UNIFIED_COMP_FORMAT_NV12_C = GMM_UNIFIED_COMP_FORMAT_NV12, GMM_UNIFIED_COMP_FORMAT_YCRCB_SWAPUV = GMM_UNIFIED_COMP_FORMAT_SWAPUV, GMM_UNIFIED_COMP_FORMAT_YCRCB_SWAPUVY = GMM_UNIFIED_COMP_FORMAT_SWAPUVY, GMM_UNIFIED_COMP_FORMAT_YCRCB_SWAPY = GMM_UNIFIED_COMP_FORMAT_SWAPY, GMM_UNIFIED_COMP_MAX_MC_FORMAT = GMM_UNIFIED_COMP_FORMAT_NV12, //should always be equal to last format encoding GMM_UNIFIED_COMP_FORMAT_INVALID, //equal to last valid encoding plus one } GMM_UNIFIED_COMP_FORMAT; #ifdef __cplusplus extern "C" { #endif /*__cplusplus*/ // Set packing alignment #pragma pack(push, 8) #ifndef __GMM_KMD__ #ifdef _WIN32 #ifndef PHYSICAL_ADDRESS #define PHYSICAL_ADDRESS LARGE_INTEGER #endif #endif #ifndef PAGE_SIZE #define PAGE_SIZE 4096 #endif #endif /*__GMM_KMD__*/ //=========================================================================== // typedef: // GMM_FORMAT_ENTRY // // Description: // This struct is used to describe each surface format in the // GMM_RESOURCE_FORMAT enum. Each surface format is desginated as a // supported format on the running platform, as well as if the format is // renderable. // //--------------------------------------------------------------------------- typedef struct GMM_FORMAT_ENTRY_REC { struct { uint32_t ASTC : 1; uint32_t Compressed : 1; uint32_t RenderTarget : 1; uint32_t Supported : 1; }; struct { uint16_t BitsPer; uint8_t Depth; uint8_t Height; uint8_t Width; } Element; GMM_SURFACESTATE_FORMAT SurfaceStateFormat; union { GMM_E2ECOMP_FORMAT AuxL1eFormat; uint8_t CompressionFormat; } CompressionFormat; }GMM_FORMAT_ENTRY; //=========================================================================== // typedef: // GMM_TILE_MODE_ENUM // // Description: // Enumeration of supported tile modes. // //-------------------------------------------------------------------------- #define DEFINE_TILE_BPEs(TileName) \ TILE_##TileName##_8bpe, \ TILE_##TileName##_16bpe, \ TILE_##TileName##_32bpe, \ TILE_##TileName##_64bpe, \ TILE_##TileName##_128bpe \ typedef enum GMM_TILE_MODE_ENUM { TILE_NONE, // Legacy Tile Modes LEGACY_TILE_X, LEGACY_TILE_Y, // Tile-W is a 64x64 tile swizzled // onto a 128x32 Tile-Y. // For allocation purposes Tile-W // can be treated like Tile-Y // TILE_W // Tiled Resource Modes (SKL+) DEFINE_TILE_BPEs( YF_1D ), DEFINE_TILE_BPEs( YS_1D ), DEFINE_TILE_BPEs( YF_2D ), DEFINE_TILE_BPEs( YF_2D_2X ), DEFINE_TILE_BPEs( YF_2D_4X ), DEFINE_TILE_BPEs( YF_2D_8X ), DEFINE_TILE_BPEs( YF_2D_16X ), DEFINE_TILE_BPEs( YF_3D ), DEFINE_TILE_BPEs( YS_2D ), DEFINE_TILE_BPEs( YS_2D_2X ), DEFINE_TILE_BPEs( YS_2D_4X ), DEFINE_TILE_BPEs( YS_2D_8X ), DEFINE_TILE_BPEs( YS_2D_16X ), DEFINE_TILE_BPEs( YS_3D ), // XE_HP/Xe2_LPG TILE4, DEFINE_TILE_BPEs( _64_1D ), DEFINE_TILE_BPEs( _64_2D ), DEFINE_TILE_BPEs( _64_2D_2X), DEFINE_TILE_BPEs( _64_2D_4X), DEFINE_TILE_BPEs( _64_3D), // Xe2 above DEFINE_TILE_BPEs(_64_2D_8X), DEFINE_TILE_BPEs(_64_2D_16X), GMM_TILE_MODES }GMM_TILE_MODE; #undef DEFINE_TILE_BPEs typedef struct __TEX_ALIGNMENT { uint32_t Width; // pixels uint32_t Height; // scanlines uint32_t Depth; // pixels } ALIGNMENT; //=========================================================================== // typedef: // GMM_TEXTURE_ALIGN // // Description: // The following struct describes the texture mip map unit alignment // required for each map format. The alignment values are platform // dependent. // //--------------------------------------------------------------------------- typedef struct GMM_TEXTURE_ALIGN_REC { ALIGNMENT Compressed, Depth, Depth_D16_UNORM_1x_4x_16x, Depth_D16_UNORM_2x_8x, SeparateStencil, YUV422, XAdapter, AllOther; struct { ALIGNMENT Align; uint32_t MaxPitchinTiles; } CCS; }GMM_TEXTURE_ALIGN; //=========================================================================== // typedef: // __GMM_BUFFER_TYPE_REC // // Description: // This structure represents a buffer type. Common buffer types are // Display buffers, Color buffers, Linear buffers and ring buffers. // Each buffer type has platform specific size, dimension and alignment // restricions that are stored here. // //--------------------------------------------------------------------------- typedef struct __GMM_BUFFER_TYPE_REC { uint32_t Alignment; // Base Address Alignment uint32_t PitchAlignment; // Pitch Alignment restriction. uint32_t RenderPitchAlignment; // Pitch Alignment for render surface uint32_t LockPitchAlignment; // Pitch Alignment for locked surface uint32_t MinPitch; // Minimum pitch GMM_GFX_SIZE_T MaxPitch; // Maximum pitch GMM_GFX_SIZE_T MinAllocationSize; // Minimum Allocation size requirement uint32_t MinHeight; // Mininum height in bytes GMM_GFX_SIZE_T MinWidth; // Minimum width in bytes uint32_t MinDepth; // Minimum depth (only for volume) GMM_GFX_SIZE_T MaxHeight; // Maximum height in bytes GMM_GFX_SIZE_T MaxWidth; // Maximum Width in bytes uint32_t MaxDepth; // Maximum depth (only for volume) uint32_t MaxArraySize; uint8_t NeedPow2LockAlignment; // Locking surface need to be power of 2 aligned } __GMM_BUFFER_TYPE; //=========================================================================== // typedef: // __GMM_PLATFORM_RESOURCE // // Description: // This structure represents various platform specific restrictions for // - buffer types // - tile dimensions // - # of fences regisers platform supports // - # of addressable bits // - aperture size // //---------------------------------------------------------------------------- typedef struct __GMM_PLATFORM_RESOURCE_REC { PLATFORM Platform; // // Define memory type req., alignment, min allocation size; // __GMM_BUFFER_TYPE Vertex; // Vertex Buffer restrictions __GMM_BUFFER_TYPE Index; // Index Buffer restrictions __GMM_BUFFER_TYPE Constant; // __GMM_BUFFER_TYPE StateDx9ConstantBuffer; // Dx9 Constant Buffer pool restrictions __GMM_BUFFER_TYPE Texture2DSurface; // 2D texture surface __GMM_BUFFER_TYPE Texture2DLinearSurface; // 2D Linear media surface __GMM_BUFFER_TYPE Texture3DSurface; // 3D texture surface __GMM_BUFFER_TYPE CubeSurface; // cube texture surface __GMM_BUFFER_TYPE BufferType; // Buffer type surface __GMM_BUFFER_TYPE Color; // Color (Render Target) Buffer __GMM_BUFFER_TYPE Depth; // Depth Buffer Restriction __GMM_BUFFER_TYPE Stencil; // Stencil Buffer Restrictions __GMM_BUFFER_TYPE HiZ; // Hierarchical Depth Buffer Resrictions __GMM_BUFFER_TYPE Stream; // __GMM_BUFFER_TYPE Video; // Video Planar surface restrictions __GMM_BUFFER_TYPE MotionComp; // Motion Compensation buffer __GMM_BUFFER_TYPE Overlay; // Overlay Buffer __GMM_BUFFER_TYPE Nndi; // Non native display buffer restrictions __GMM_BUFFER_TYPE ASyncFlipSurface; // ASync flip chain Buffers __GMM_BUFFER_TYPE HardwareMBM; // Buffer Restrictions __GMM_BUFFER_TYPE InterlacedScan; // __GMM_BUFFER_TYPE TextApi; // __GMM_BUFFER_TYPE Linear; // Linear(Generic) Buffer restrictions __GMM_BUFFER_TYPE Cursor; // Cursor surface restrictions __GMM_BUFFER_TYPE NoRestriction; // Motion Comp Buffer __GMM_BUFFER_TYPE XAdapter; // Cross adapter linear buffer restrictions GMM_TEXTURE_ALIGN TexAlign; // Alignment Units for Texture Maps // // various tile dimension based on platform // GMM_TILE_INFO TileInfo[GMM_TILE_MODES]; // // General platform Restriction // uint32_t NumberFenceRegisters; uint32_t MinFenceSize; // 1 MB for Napa, 512 KB for Almador uint32_t FenceLowBoundShift; uint32_t FenceLowBoundMask; uint32_t PageTableSteer; // Default for page table steer register uint32_t PagingBufferPrivateDataSize; uint32_t MaxLod; uint32_t FBCRequiredStolenMemorySize; // Stolen Memory size required for FBC GMM_FORMAT_ENTRY FormatTable[GMM_RESOURCE_FORMATS]; uint32_t ResAllocTag[GMM_MAX_HW_RESOURCE_TYPE]; // uint32_t = 4 8-bit ASCII characters uint32_t SurfaceStateYOffsetGranularity; uint32_t SamplerFetchGranularityWidth; uint32_t SamplerFetchGranularityHeight; int64_t SurfaceMaxSize; // int64_t - Surface size is 64 bit for all configurations uint32_t MaxGpuVirtualAddressBitsPerResource; uint32_t MaxSLMSize; uint8_t HiZPixelsPerByte; //HiZ-Bpp is < 1, keep inverse uint64_t ReconMaxHeight; uint64_t ReconMaxWidth; uint8_t NoOfBitsSupported; // No of bits supported for System physcial address on GPU uint64_t HighestAcceptablePhysicalAddress; // Highest acceptable System physical Address }__GMM_PLATFORM_RESOURCE, GMM_PLATFORM_INFO; //*************************************************************************** // // GMM_PLATFORM_INFO API // //*************************************************************************** uint32_t GMM_STDCALL GmmPlatformGetBppFromGmmResourceFormat(void *pLibContext, GMM_RESOURCE_FORMAT Format); // Reset packing alignment to project default #pragma pack(pop) #ifdef __cplusplus } #endif /*__cplusplus*/ gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/inc/External/Common/GmmProto.h000066400000000000000000000031511466655022700255530ustar00rootroot00000000000000/*============================================================================== Copyright(c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ============================================================================*/ #pragma once ////////////////////////////////////////////////////////////////////////////////////// // GmmRestrictions.c ////////////////////////////////////////////////////////////////////////////////////// void __GmmGetCubeTexRestrictions(GMM_PLATFORM_INFO* pPlatformResource, GMM_RESOURCE_INFO* pResourceInfo, __GMM_BUFFER_TYPE* pBuff); gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/inc/External/Common/GmmResourceFlags.h000066400000000000000000000317341466655022700272240ustar00rootroot00000000000000/*============================================================================== Copyright(c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ============================================================================*/ #pragma once #ifdef __cplusplus extern "C" { #endif /*__cplusplus*/ // Set packing alignment #pragma pack(push, 8) //=========================================================================== // typedef: // GMM_RESOURCE_FLAG // // Description: // This structure describe flags that are used for each allocation //--------------------------------------------------------------------------- typedef struct GMM_RESOURCE_FLAG_REC { // Gpu: Used to describe how the surface will be used by the GPU struct { uint32_t CameraCapture : 1; // Camera Capture Buffer flag to be registered with DXGK for Camera Child VRAM buffer sharing uint32_t CCS : 1; // Color Control Surface (Gen9+ for MSAA Compression or Non-MSAA Fast Color Clear) + Apply CCS restrictions when padding/aligning this resource (see GmmRestrictions.c) uint32_t ColorDiscard : 1; // Tile-pass color discard uint32_t ColorSeparation : 1; // Color Separated surface (Sakura display), surface scanned out as 16bpp uint32_t ColorSeparationRGBX : 1; // Color Separated surface (Sakura display), surface scanned out as 24bpp (stored as 32bpp) uint32_t Constant : 1; uint32_t Depth : 1; uint32_t FlipChain : 1; // Indicating that this buffer is to be (potentially) scanned out by the display engine. uint32_t FlipChainPreferred : 1; // .FlipChain & .Overlay are softer, in that they will be cleared in the result if other parameters cause conflict -- e.g. Info.TiledY. uint32_t HistoryBuffer : 1; // History buffer for performace timestamp feature uint32_t HiZ : 1; uint32_t Index : 1; uint32_t IndirectClearColor : 1; // Hardware managed clear color uint32_t InstructionFlat : 1; // (Not for heaps!) EU Instruction Resource (addressed by *flat* STATE_BASE_ADDRESS:InstructionState--Do NOT use for STATE_BASE_ADDRESS heap resources!!) uint32_t InterlacedScan : 1; uint32_t MCS : 1; // Multisample Control Surface (Pre-Gen9 for MSAA Compression or Non-MSAA Fast Color Clear) uint32_t MMC : 1; // Media Memory Compression (Gen9+): (right-side) extension to the pixel buffer for media oriented clear-compression data for texture sampling. uint32_t MotionComp : 1; uint32_t NoRestriction : 1; // Apply no (more correctly, minimal) restrictions when padding/aligning this resource (see GmmRestrictions.c) e.g. BLOBS. uint32_t Overlay : 1; // Equivalent to FlipChain, mutually exclusive to it. Legacy (pre gen9) name for sprite plane scane-out buffer.. uint32_t Presentable : 1; // The pixel format is to be validated against those supported by the render core (GPU). uint32_t ProceduralTexture : 1; uint32_t Query : 1; uint32_t RenderTarget : 1; // Apply RenderTarget restrictions when padding/aligning this resource (see GmmRestrictions.c) uint32_t S3d : 1; uint32_t S3dDx : 1; uint32_t __S3dNonPacked : 1; // For OS unaware S3D only uint32_t __S3dWidi : 1; // For OS unaware S3D only uint32_t ScratchFlat : 1; // (Not for heaps!) General State Resource (addressed by *flat* STATE_BASE_ADDRESS:GeneralState--Do NOT use for STATE_BASE_ADDRESS heap resources!!) uint32_t SeparateStencil : 1; uint32_t State : 1; uint32_t StateDx9ConstantBuffer : 1; // Use w/ HSW+ cmd 3DSTATE_DX9_CONSTANT_BUFFER_POOL_ALLOC uint32_t Stream : 1; // Stream-Output Resource (e.g. the target of DX10's Stream-Output Stage) uint32_t TextApi : 1; uint32_t Texture : 1; // Apply Texture restrictions when padding/aligning this resource (see GmmRestrictions.c) uint32_t TiledResource : 1; // Used for DirectX11.2 tiled resources aka sparse resources uint32_t TilePool : 1; // Used for DirectX11.2 tiled resources uint32_t UnifiedAuxSurface : 1; // Flag to indicate unified aux surfaces where a number of buffers are allocated as one resource creation call (e.g. for Android/gralloc when a combined CCS with its partner MSAA). A conveneince over making two GmmResCreate calls. Gen9+. uint32_t Vertex : 1; uint32_t Video : 1; // Apply Video restrictions when padding/aligning this resource (see GmmRestrictions.c) uint32_t __NonMsaaTileXCcs : 1; // Internal GMM flag--Clients don't set. uint32_t __NonMsaaTileYCcs : 1; // Internal GMM flag--Clients don't set. uint32_t __MsaaTileMcs : 1; // Internal GMM flag--Clients don't set. uint32_t __NonMsaaLinearCCS : 1; // Internal GMM flag--Clients don't set. uint32_t __Remaining : 20;// Defining rather than letting float for the two zero-and-memcmp we do with the .Gpu struct (in case ={0} doesn't zero unnamed fields). } Gpu; // Info: Used to specify preferences at surface creation time struct { uint32_t AllowVirtualPadding : 1; uint32_t BigPage : 1; uint32_t Cacheable : 1; uint32_t ContigPhysMemoryForiDART : 1; // iDART clients only; resource allocation must be physically contiguous. uint32_t CornerTexelMode : 1; // Corner Texel Mode uint32_t ExistingSysMem : 1; uint32_t ForceResidency : 1; // (SVM Only) Forces CPU/GPU residency of the allocation's backing pages at creation. uint32_t Gfdt : 1; uint32_t GttMapType : 5; uint32_t HardwareProtected : 1; uint32_t KernelModeMapped : 1; // Sets up pGmmBlock->pKernelModeMapping to allow kernel-mode mapping of the backing memory uint32_t LayoutBelow : 1; // Indicates the orientation of MIP data in the buffer. This is the surviving option and may be inferred as the default. uint32_t LayoutMono : 1; // Legacy, deprecated MIP layout. Used for internal debugging. uint32_t LayoutRight : 1; // Legacy, deprecated MIP layout. uint32_t LocalOnly : 1; uint32_t Linear : 1; // (non-)tiling preference for the allocation. (lowest priority) Y>X>W>L. See GmmLib::GmmTextureCalc::SetTileMode() uint32_t MediaCompressed : 1; uint32_t NoOptimizationPadding : 1; // don't swell size for sake of 64KB pages - FtrWddm2_1_64kbPages uint32_t NoPhysMemory : 1; // KMD Gfx Client Submission. Client miniport drivers may want to map their physical pages to Gfx memory space instead of allocating Gfx physical memory. uint32_t NotLockable : 1; // Resource is GPU-exclusive and shall not be reference by the CPU. Relevant to memory allocation components as an optimisation opportunity for mapping buffers in CPU-side. uint32_t NonLocalOnly : 1; uint32_t StdSwizzle : 1; // Standard Swizzle (YS) support on SKL+ uint32_t PseudoStdSwizzle : 1; // Only applicable to D3D12+ UMD's, for special-case of limited Standard Swizzle (YS) support on HSW/BDW/CHV. uint32_t Undefined64KBSwizzle : 1; // Only applicable if system doesn't support StdSwizzle (i.e. Pre-Gen9). If set, surface is using one of the INTEL_64KB_UNDEFINED_* swizzles. uint32_t RedecribedPlanes : 1; // The resource has redescribed planar surfaces uint32_t RenderCompressed : 1; uint32_t Rotated : 1; uint32_t Shared : 1; uint32_t SoftwareProtected : 1; // Resource is driver protected against CPU R/W access uint32_t SVM : 1; // Shared Virtual Memory (i.e. GfxAddr = CpuAddr) Can only be set for ExistingSysMem allocations. uint32_t TiledW : 1; // Tiling preference for the allocation. (second lowest priority) Y>X>W>L. Special use case. uint32_t TiledX : 1; // Tiling preference for the allocation. (second highest priority) Y>X>W>L. Common use case. uint32_t TiledY : 1; // Tiling preference for the allocation. (highest priority) Y>X>W>L. Common use case. Displayable GEn9+ uint32_t TiledYf : 1; // Tiling modifier for the allocation. Affects Linear and Y preferences. Gen9+ uint32_t TiledYs : 1; // Tiling modifier for the allocation. Affects Linear and Y preferences. Gen9+ uint32_t WddmProtected : 1; // Sets the DXGK_ALLOCATIONINFOFLAGS.Protected flag uint32_t XAdapter : 1; // For WinBlue: to support Hybrid graphics uint32_t __PreallocatedResInfo : 1; // Internal GMM flag--Clients don't set. uint32_t __PreWddm2SVM : 1; // Internal GMM flag--Clients don't set. uint32_t Tile4 : 1; // 4KB tile uint32_t Tile64 : 1; // 64KB tile uint32_t NotCompressed : 1; // UMD to set this for a resource, this will be a request to GMM which need not be honoured always uint32_t __MapCompressible : 1; // Internal GMM flag which marks a resource as compressed during map, used for tracking uint32_t __MapUnCompressible : 1; // Internal GMM flag which marks a resource as not compressed during map, used for tracking } Info; // Wa: Any Surface specific Work Around will go in here struct { uint32_t GTMfx2ndLevelBatchRingSizeAlign : 1; // GT steppings prior to C0 require MFX 2nd level bb's to have certain alignment. uint32_t ILKNeedAvcMprRowStore32KAlign : 1; // ILK A0 requires 32K align WA for AVC MPR RowStore uint32_t ILKNeedAvcDmvBuffer32KAlign : 1; // ILK A0 requires 32K align WA for AVC DMV Buffers uint32_t NoBufferSamplerPadding : 1; // GMM not to add pre-BDW buffer sampler padding--UMD's take responsibility to flush L3 after sampling, etc. uint32_t NoLegacyPlanarLinearVideoRestrictions : 1; // GMM not to apply Legacy Planar "Linear Video" Restrictions (64B pitch alignment) uint32_t CHVAstcSkipVirtualMips : 1; // GMM adjusts mip-map allocation to skip mip0 size uint32_t DisablePackedMipTail : 1; // Disables Yf/Ys MIP Tail packing--forcing each MIP to its own tile boundary. uint32_t __ForceOtherHVALIGN4 : 1; uint32_t DisableDisplayCcsClearColor : 1; // Disables display clear color uint32_t DisableDisplayCcsCompression : 1; // Disables display decompression on the surface (it disables display awareness of both fast clear/render compression) uint32_t PreGen12FastClearOnly : 1; // i.e. AUX_CCS_D (instead of AUX_CCS_E). Flag carried by GMM between UMDÂ’s to support shared resources. uint32_t MediaPipeUsage : 1; // TileHeight Aligned ArrayQPitch on Tile4/TileY uint32_t ForceStdAllocAlign : 1; // Align standard allocation to 2MB, allowing 64K-PageTable. Set by KMD, not be used by UMDs uint32_t DeniableLocalOnlyForCompression : 1; // Align standard allocation to 2MB, allowing 64K-PageTable. Set by KMD, not be used by UMDs } Wa; } GMM_RESOURCE_FLAG; // Reset packing alignment to project default #pragma pack(pop) #ifdef __cplusplus } #endif /*__cplusplus*/ gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/inc/External/Common/GmmResourceInfo.h000066400000000000000000000110061466655022700270510ustar00rootroot00000000000000/*============================================================================== Copyright(c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ============================================================================*/ #pragma once #ifdef __cplusplus extern "C" { #endif /*__cplusplus*/ // Set packing alignment #pragma pack(push, 8) extern const uint32_t __GmmMSAAConversion[5][2]; extern const uint32_t __GmmTileYConversionTable[5][2]; // // Normally, GMM_RESOURCE_INFO should not contain any user mode pointers because // if the resource is shared, then the pointer will be invalid in the other process. // However, the pointers below are OK because pMappedTiles and pTiledPoolArray are // associated with a TR surface, which is not shareable. AuxInfo.pTilePoolInfo is associated // with tile pools; Tile Pools are shareable, but Aux tile pool aren't. // typedef struct TILE_POOL_INFO_REC { uint64_t UsedTiles[4]; // Tiles being used in 1 tile pool GMM_GFX_ADDRESS StartingGfxAddress; // GfxAddress associated with the TilePool } TILE_POOL_INFO; typedef struct GMM_TILED_RESOURCE_INFO_REC { GMM_GFX_ADDRESS TiledResourceGfxAddress; // used for tiled resources uint64_t pMappedTiles; // tracks which tiles have been mapped uint64_t pTilePoolArray; // list of tile pool allocation // handles (D3DKMT_HANDLE), // only used for tiled resources uint64_t pAuxTilePoolResArray; // list of aux tile pool allocation resource, and handles uint32_t TilePoolArraySize; uint32_t AuxTilePoolArraySize; struct { uint64_t pTilePoolInfo; uint64_t PagingFenceValue; uint32_t TilePoolInfoTotalNumElements; // Number of elements in pTilePoolInfo array uint32_t TilePoolInfoFreeNumElements; // Number of free tile pools } AuxInfo; } GMM_TILED_RESOURCE_INFO; typedef struct GMM_EXISTING_SYS_MEM_REC { // 64bit kernel mode drivers must validate sizeof structs passed from // 32bit & 64bit user mode drivers. Store as 64bit to keep uniform size. uint64_t pExistingSysMem; //Original buffer address. uint64_t pVirtAddress; uint64_t pGfxAlignedVirtAddress; #if(LHDM) D3DKMT_HANDLE hParentAllocation; #endif GMM_GFX_SIZE_T Size; uint8_t IsGmmAllocated; } GMM_EXISTING_SYS_MEM; //=========================================================================== // typedef: // GMM_RESOURCE_INFO // // Description: // Struct describing the attributes and properties of a user mode resource // //---------------------------------------------------------------------------- #ifndef _WIN32 #include "../Linux/GmmResourceInfoLin.h" #endif // Reset packing alignment to project default #pragma pack(pop) uint8_t GMM_STDCALL GmmResValidateParams(GMM_RESOURCE_INFO *pResourceInfo); void GMM_STDCALL GmmResGetRestrictions(GMM_RESOURCE_INFO* pResourceInfo, __GMM_BUFFER_TYPE* pRestrictions); uint8_t __CanSupportStdTiling(GMM_TEXTURE_INFO Surface, GMM_LIB_CONTEXT *pGmmLibContext); #ifdef __cplusplus } #endif /*__cplusplus*/ gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/inc/External/Common/GmmResourceInfoCommon.h000066400000000000000000003160241466655022700302320ustar00rootroot00000000000000/*============================================================================== Copyright(c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ============================================================================*/ #pragma once #ifdef __cplusplus #include "GmmMemAllocator.hpp" #include "GmmCachePolicy.h" #include "GmmUtil.h" #include "GmmInfoExt.h" #include "GmmInfo.h" #include "../../../Platform/GmmPlatforms.h" #include "../../../../inc/common/gfxmacro.h" #include "GmmClientContext.h" // Macro definitions #ifndef __GMM_ASSERT // Needs to be defined before including this file. If not defined, then // we'll nop these macros. #define __GMM_ASSERT(expr) #define GMM_ASSERTDPF(expr, ret) #define __GMM_ASSERTPTR(expr, ret) #endif ///////////////////////////////////////////////////////////////////////////////////// /// @file GmmResourceInfoCommon.h /// @brief This file contains the functions and members of GmmResourceInfo that is /// common for both Linux and Windows. /// ///////////////////////////////////////////////////////////////////////////////////// namespace GmmLib { ///////////////////////////////////////////////////////////////////////// /// Contains functions and members that are common between Linux and /// Windows implementation. This class is inherited by the Linux and /// Windows specific class, so clients shouldn't have to ever interact /// with this class directly. ///////////////////////////////////////////////////////////////////////// class GMM_LIB_API NON_PAGED_SECTION GmmResourceInfoCommon: public GmmMemAllocator { protected: /// Type of Client type using the library. Can be used by GmmLib to /// implement client specific functionality. GMM_CLIENT ClientType; GMM_TEXTURE_INFO Surf; ///< Contains info about the surface being created GMM_TEXTURE_INFO AuxSurf; ///< Contains info about the auxiliary surface if using Unified Auxiliary surfaces. GMM_TEXTURE_INFO AuxSecSurf; ///< For multi-Aux surfaces, contains info about the secondary auxiliary surface uint32_t RotateInfo; GMM_EXISTING_SYS_MEM ExistingSysMem; ///< Info about resources initialized with existing system memory GMM_GFX_ADDRESS SvmAddress; ///< Driver managed SVM address uint64_t pGmmUmdLibContext; ///< Pointer to GmmLib context created in DLL passed in during Create() uint64_t pGmmKmdLibContext; ///< Pointer to GmmLib context created in KMD passed in during Create() uint64_t pPrivateData; ///< Allows clients to attach any private data to GmmResourceInfo #ifdef __GMM_KMD__ void *pClientContext; ///< void * in order to of same size for the ResInfo Object across KMD and UMD #else GmmClientContext *pClientContext; ///< ClientContext of the client creating this Resource #endif GMM_MULTI_TILE_ARCH MultiTileArch; private: GMM_STATUS ApplyExistingSysMemRestrictions(); protected: /* Function prototypes */ GMM_VIRTUAL bool IsPresentableformat(); // Move GMM Restrictions to it's own class? virtual bool CopyClientParams(GMM_RESCREATE_PARAMS &CreateParams); GMM_VIRTUAL const GMM_PLATFORM_INFO& GetPlatformInfo(); ///////////////////////////////////////////////////////////////////////////////////// /// Returns tile mode for SURFACE_STATE programming. /// @return Tiled Mode ///////////////////////////////////////////////////////////////////////////////////// GMM_INLINE uint32_t GetTileModeSurfaceState(const GMM_TEXTURE_INFO *pTextureInfo) { uint32_t TiledMode = 0; if(GMM_IS_TILEY(GetGmmLibContext())) { TiledMode = pTextureInfo->Flags.Info.Linear ? 0 : pTextureInfo->Flags.Info.TiledW ? 1 : pTextureInfo->Flags.Info.TiledX ? 2 : /* Y/YF/YS */ 3; __GMM_ASSERT((TiledMode != 3) || (pTextureInfo->Flags.Info.TiledY || pTextureInfo->Flags.Info.TiledYf || pTextureInfo->Flags.Info.TiledYs)); } else { TiledMode = (GMM_IS_4KB_TILE(pTextureInfo->Flags)) ? 3 : (GMM_IS_64KB_TILE(pTextureInfo->Flags)) ? 1 : pTextureInfo->Flags.Info.TiledX ? 2 : /* Linear */ 0; __GMM_ASSERT(TiledMode || pTextureInfo->Flags.Info.Linear); } return TiledMode; } public: /* Constructors */ GmmResourceInfoCommon(): ClientType(), Surf(), AuxSurf(), AuxSecSurf(), RotateInfo(), ExistingSysMem(), SvmAddress(), pGmmUmdLibContext(), pGmmKmdLibContext(), pPrivateData(), pClientContext(), MultiTileArch() { } #ifndef __GMM_KMD__ GmmResourceInfoCommon(GmmClientContext *pClientContextIn) : ClientType(), Surf(), AuxSurf(), AuxSecSurf(), RotateInfo(), ExistingSysMem(), SvmAddress(), pGmmUmdLibContext(), pGmmKmdLibContext(), pPrivateData(), pClientContext(), MultiTileArch() { pClientContext = pClientContextIn; } #endif GmmResourceInfoCommon& operator=(const GmmResourceInfoCommon& rhs) { ClientType = rhs.ClientType; Surf = rhs.Surf; AuxSurf = rhs.AuxSurf; AuxSecSurf = rhs.AuxSecSurf; RotateInfo = rhs.RotateInfo; ExistingSysMem = rhs.ExistingSysMem; SvmAddress = rhs.SvmAddress; pPrivateData = rhs.pPrivateData; MultiTileArch = rhs.MultiTileArch; return *this; } virtual ~GmmResourceInfoCommon() { if (ExistingSysMem.pVirtAddress && ExistingSysMem.IsGmmAllocated) { GMM_FREE((void *)ExistingSysMem.pVirtAddress); } } /* Function prototypes */ // Overloaded Create function to keep backward compatible. This shall be deprecated soon GMM_VIRTUAL GMM_STATUS GMM_STDCALL Create(Context &GmmLibContext, GMM_RESCREATE_PARAMS &CreateParams); GMM_VIRTUAL uint8_t GMM_STDCALL ValidateParams(); GMM_VIRTUAL GMM_STATUS GMM_STDCALL Create(GMM_RESCREATE_PARAMS &CreateParams); GMM_VIRTUAL void GMM_STDCALL GetRestrictions(__GMM_BUFFER_TYPE& Restrictions); GMM_VIRTUAL uint32_t GMM_STDCALL GetPaddedWidth(uint32_t MipLevel); GMM_VIRTUAL uint32_t GMM_STDCALL GetPaddedHeight(uint32_t MipLevel); GMM_VIRTUAL uint32_t GMM_STDCALL GetPaddedPitch(uint32_t MipLevel); GMM_VIRTUAL uint32_t GMM_STDCALL GetQPitch(); GMM_VIRTUAL GMM_STATUS GMM_STDCALL GetOffset(GMM_REQ_OFFSET_INFO &ReqInfo); GMM_VIRTUAL uint8_t GMM_STDCALL CpuBlt(GMM_RES_COPY_BLT *pBlt); GMM_VIRTUAL uint8_t GMM_STDCALL GetMappingSpanDesc(GMM_GET_MAPPING *pMapping); GMM_VIRTUAL uint8_t GMM_STDCALL Is64KBPageSuitable(); GMM_VIRTUAL void GMM_STDCALL GetTiledResourceMipPacking(uint32_t *pNumPackedMips, uint32_t *pNumTilesForPackedMips); GMM_VIRTUAL uint32_t GMM_STDCALL GetPackedMipTailStartLod(); GMM_VIRTUAL bool GMM_STDCALL IsMipRCCAligned(uint8_t &MisAlignedLod); GMM_VIRTUAL uint8_t GMM_STDCALL GetDisplayFastClearSupport(); GMM_VIRTUAL uint8_t GMM_STDCALL GetDisplayCompressionSupport(); GMM_VIRTUAL GMM_GFX_SIZE_T GMM_STDCALL GetMipWidth(uint32_t MipLevel); GMM_VIRTUAL uint32_t GMM_STDCALL GetMipHeight(uint32_t MipLevel); GMM_VIRTUAL uint32_t GMM_STDCALL GetMipDepth(uint32_t MipLevel); GMM_VIRTUAL uint64_t GMM_STDCALL GetFastClearWidth(uint32_t MipLevel); GMM_VIRTUAL uint32_t GMM_STDCALL GetFastClearHeight(uint32_t MipLevel); /* inline functions */ #ifndef __GMM_KMD__ ///////////////////////////////////////////////////////////////////////////////////// /// Returns GmmClientContext associated with this resource /// @return ::GmmClientContext ///////////////////////////////////////////////////////////////////////////////////// GMM_INLINE_VIRTUAL GMM_INLINE_EXPORTED GmmClientContext* GetGmmClientContext() { return pClientContext; } ///////////////////////////////////////////////////////////////////////////////////// /// Sets GmmClientContext to be associated with this resource /// @return ::void ///////////////////////////////////////////////////////////////////////////////////// GMM_INLINE_VIRTUAL GMM_INLINE_EXPORTED void SetGmmClientContext(GmmClientContext* pGmmClientContext) { pClientContext = pGmmClientContext; GET_GMM_CLIENT_TYPE(pGmmClientContext, ClientType); } #endif ///////////////////////////////////////////////////////////////////////////////////// /// This function Sets GmmLibContext in GmmResInfo. /// GMMResInfo gets passed as private data from UMDs to KMD during // GMMCreateAllocation and GmmOpenAllocation /// Member functions of ResInfo class need to access the LibContext object. But since /// the LibContext object present in ResInfo is created by UMDs in UMD space, /// and this UMD space object cant be used in KMD space, /// we need this API to set the KMD LibContext in ResInfo object. /// @return ::void ///////////////////////////////////////////////////////////////////////////////////// GMM_INLINE_VIRTUAL GMM_INLINE_EXPORTED void SetGmmLibContext(void *pLibContext) { #if(defined(__GMM_KMD__)) pGmmKmdLibContext = reinterpret_cast(pLibContext); #else pGmmUmdLibContext = reinterpret_cast(pLibContext); #endif } ///////////////////////////////////////////////////////////////////////////////////// /// Returns either UMD or KMD GMMLibContext that needs to be used when the ResInfo /// Member functions are executed at KMD or UMD level /// @return ::Context ///////////////////////////////////////////////////////////////////////////////////// GMM_INLINE_VIRTUAL GMM_INLINE_EXPORTED Context *GetGmmLibContext() { #if(defined(__GMM_KMD__)) return ((Context *)pGmmKmdLibContext); #else return ((Context *)pGmmUmdLibContext); #endif } ///////////////////////////////////////////////////////////////////////////////////// /// Returns GMM_CLIENT Type that has created this resource /// @return ::GMM_CLIENT ///////////////////////////////////////////////////////////////////////////////////// GMM_INLINE_VIRTUAL GMM_INLINE_EXPORTED void SetClientType(GMM_CLIENT Client) { ClientType = Client; } ///////////////////////////////////////////////////////////////////////////////////// /// Returns GMM_CLIENT Type that has created this resource /// @return ::GMM_CLIENT ///////////////////////////////////////////////////////////////////////////////////// GMM_INLINE_VIRTUAL GMM_INLINE_EXPORTED GMM_CLIENT GetClientType() { return ClientType; } ///////////////////////////////////////////////////////////////////////////////////// /// Returns the system memory pointer. It selectively returns either the natural /// pointer or a value appropriately page aligned for D3DDI_ALLOCATIONINFO, /// depending on what the caller request. /// @param[in] IsD3DDdiAllocation: Specifies where allocation was made by a D3D client /// @return Pointer to system memory. NULL if not available. ///////////////////////////////////////////////////////////////////////////////////// GMM_INLINE_VIRTUAL GMM_INLINE_EXPORTED void* GMM_STDCALL GetSystemMemPointer(uint8_t IsD3DDdiAllocation) { if (IsD3DDdiAllocation) { return (void *)GMM_GFX_ADDRESS_CANONIZE(ExistingSysMem.pGfxAlignedVirtAddress); } else { return (void *)GMM_GFX_ADDRESS_CANONIZE(ExistingSysMem.pVirtAddress); } } ///////////////////////////////////////////////////////////////////////////////////// /// Returns the system memory size. /// @return Size of memory. ///////////////////////////////////////////////////////////////////////////////////// GMM_INLINE_VIRTUAL GMM_INLINE_EXPORTED GMM_GFX_SIZE_T GMM_STDCALL GetSystemMemSize() { return ExistingSysMem.Size; } ///////////////////////////////////////////////////////////////////////////////////// /// Returns a reference to the surface flags. /// @return Reference to ::GMM_RESOURCE_FLAGS ///////////////////////////////////////////////////////////////////////////////////// GMM_INLINE_VIRTUAL GMM_INLINE_EXPORTED GMM_RESOURCE_FLAG& GMM_STDCALL GetResFlags() { return Surf.Flags; } ///////////////////////////////////////////////////////////////////////////////////// /// Returns the resource type /// @return ::GMM_RESOURCE_TYPE ///////////////////////////////////////////////////////////////////////////////////// GMM_INLINE_VIRTUAL GMM_INLINE_EXPORTED GMM_RESOURCE_TYPE GMM_STDCALL GetResourceType() { return Surf.Type; } ///////////////////////////////////////////////////////////////////////////////////// /// Returns the resource format /// @return ::GMM_RESOURCE_FORMAT ///////////////////////////////////////////////////////////////////////////////////// GMM_INLINE_VIRTUAL GMM_INLINE_EXPORTED GMM_RESOURCE_FORMAT GMM_STDCALL GetResourceFormat() { return Surf.Format; } ///////////////////////////////////////////////////////////////////////////////////// /// Returns the resource width /// @return width ///////////////////////////////////////////////////////////////////////////////////// GMM_INLINE_VIRTUAL GMM_INLINE_EXPORTED GMM_GFX_SIZE_T GMM_STDCALL GetBaseWidth() { return Surf.BaseWidth; } ///////////////////////////////////////////////////////////////////////////////////// /// Returns the resource height /// @return height ///////////////////////////////////////////////////////////////////////////////////// GMM_INLINE_VIRTUAL GMM_INLINE_EXPORTED uint32_t GMM_STDCALL GetBaseHeight() { return Surf.BaseHeight; } ///////////////////////////////////////////////////////////////////////////////////// /// Returns the resource depth /// @return depth ///////////////////////////////////////////////////////////////////////////////////// GMM_INLINE_VIRTUAL GMM_INLINE_EXPORTED uint32_t GMM_STDCALL GetBaseDepth() { return Surf.Depth; } ///////////////////////////////////////////////////////////////////////////////////// /// Returns the resource's base alignment /// @return Base Alignment ///////////////////////////////////////////////////////////////////////////////////// GMM_INLINE_VIRTUAL GMM_INLINE_EXPORTED uint32_t GMM_STDCALL GetBaseAlignment() { return Surf.Alignment.BaseAlignment; } ///////////////////////////////////////////////////////////////////////////////////// /// Returns the resource's max lod /// @return Max Lod ///////////////////////////////////////////////////////////////////////////////////// GMM_INLINE_VIRTUAL GMM_INLINE_EXPORTED uint32_t GMM_STDCALL GetMaxLod() { return Surf.MaxLod; } ///////////////////////////////////////////////////////////////////////////////////// /// Returns the resource's max array size /// @return Max Array Size ///////////////////////////////////////////////////////////////////////////////////// GMM_INLINE_VIRTUAL GMM_INLINE_EXPORTED uint32_t GMM_STDCALL GetArraySize() { return Surf.ArraySize; } ///////////////////////////////////////////////////////////////////////////////////// /// Returns the resource's rotation info /// @return rotation info ///////////////////////////////////////////////////////////////////////////////////// GMM_INLINE_VIRTUAL GMM_INLINE_EXPORTED uint32_t GMM_STDCALL GetRotateInfo() { return RotateInfo; } ///////////////////////////////////////////////////////////////////////////////////// /// Returns the resource's maximum remaining list length /// @return maximum remaining list length ///////////////////////////////////////////////////////////////////////////////////// GMM_INLINE_VIRTUAL uint32_t GMM_STDCALL GetMaximumRenamingListLength() { return Surf.MaximumRenamingListLength; } ///////////////////////////////////////////////////////////////////////////////////// /// Returns the auxiliary resource's QPitch /// @return Aux QPitch ///////////////////////////////////////////////////////////////////////////////////// GMM_INLINE_VIRTUAL GMM_INLINE_EXPORTED uint32_t GMM_STDCALL GetAuxQPitch() { const GMM_PLATFORM_INFO *pPlatform; pPlatform = (GMM_PLATFORM_INFO *)GMM_OVERRIDE_EXPORTED_PLATFORM_INFO(&Surf, GetGmmLibContext()); if (Surf.Flags.Gpu.UnifiedAuxSurface) { if (GMM_IS_PLANAR(Surf.Format)) { return static_cast(AuxSurf.OffsetInfo.Plane.ArrayQPitch); } else if (AuxSurf.Flags.Gpu.HiZ) { // HiZ ==> HZ_PxPerByte * HZ_QPitch return AuxSurf.Alignment.QPitch * pPlatform->HiZPixelsPerByte; } else { return AuxSurf.Alignment.QPitch; } } else { return GetQPitch(); } } ///////////////////////////////////////////////////////////////////////////////////// /// Returns the planar resource's QPitch /// @return planar QPitch in rows ///////////////////////////////////////////////////////////////////////////////////// GMM_INLINE_VIRTUAL GMM_INLINE_EXPORTED uint32_t GMM_STDCALL GetQPitchPlanar(GMM_YUV_PLANE Plane) { uint32_t QPitch; const GMM_PLATFORM_INFO *pPlatform; __GMM_ASSERT(GMM_IS_PLANAR(Surf.Format)); GMM_UNREFERENCED_LOCAL_VARIABLE(Plane); pPlatform = (GMM_PLATFORM_INFO *)GMM_OVERRIDE_EXPORTED_PLATFORM_INFO(&Surf, GetGmmLibContext()); __GMM_ASSERT(GFX_GET_CURRENT_RENDERCORE(pPlatform->Platform) >= IGFX_GEN8_CORE); GMM_UNREFERENCED_PARAMETER(pPlatform); QPitch = static_cast(Surf.OffsetInfo.Plane.ArrayQPitch / Surf.Pitch); return QPitch; } ///////////////////////////////////////////////////////////////////////////////////// /// Returns distance in bytes between array elements (or pseudo-array-elements--e.g. /// cube faces, MSFMT_MSS sample planes). /// @return QPitch ///////////////////////////////////////////////////////////////////////////////////// GMM_INLINE_VIRTUAL GMM_INLINE_EXPORTED GMM_GFX_SIZE_T GMM_STDCALL GetQPitchInBytes() { return Surf.OffsetInfo.Texture2DOffsetInfo.ArrayQPitchRender; } ///////////////////////////////////////////////////////////////////////////////////// /// Returns resource's pitch /// @return Pitch ///////////////////////////////////////////////////////////////////////////////////// GMM_INLINE_VIRTUAL GMM_INLINE_EXPORTED GMM_GFX_SIZE_T GMM_STDCALL GetRenderPitch() { return Surf.Pitch; } ///////////////////////////////////////////////////////////////////////////////////// /// Returns resource's pitch in tiles /// @return Pitch in tiles ///////////////////////////////////////////////////////////////////////////////////// GMM_INLINE_VIRTUAL GMM_INLINE_EXPORTED uint32_t GMM_STDCALL GetRenderPitchTiles() { uint32_t PitchInTiles; const GMM_PLATFORM_INFO *pPlatform; GMM_TILE_MODE TileMode; __GMM_ASSERT(!Surf.Flags.Info.Linear); TileMode = Surf.TileMode; __GMM_ASSERT(TileMode < GMM_TILE_MODES); pPlatform = (GMM_PLATFORM_INFO *)GMM_OVERRIDE_EXPORTED_PLATFORM_INFO(&Surf, GetGmmLibContext()); if (pPlatform->TileInfo[TileMode].LogicalTileWidth != 0) { // In case of Depth/Stencil buffer MSAA TileYs surface, the LogicalTileWidth/Height is smaller than non-MSAA ones // Thus introducing the below variable to get the right PitchInTiles uint32_t MSAASpecialFactorForDepthAndStencil = 1; if ((Surf.Flags.Gpu.Depth || Surf.Flags.Gpu.SeparateStencil) && (Surf.MSAA.NumSamples > 1 && (GMM_IS_64KB_TILE(Surf.Flags) || Surf.Flags.Info.TiledYf))) { switch (Surf.MSAA.NumSamples) { case 2: MSAASpecialFactorForDepthAndStencil = 2; if (GetGmmLibContext()->GetSkuTable().FtrXe2PlusTiling && (Surf.BitsPerPixel == 128)) { MSAASpecialFactorForDepthAndStencil = 1; } break; case 4: MSAASpecialFactorForDepthAndStencil = 2; break; case 8: MSAASpecialFactorForDepthAndStencil = 4; if (GetGmmLibContext()->GetSkuTable().FtrXe2PlusTiling) { if (Surf.BitsPerPixel == 32 || Surf.BitsPerPixel == 8) { MSAASpecialFactorForDepthAndStencil = 2; } } else if (!GetGmmLibContext()->GetSkuTable().FtrTileY && !GetGmmLibContext()->GetSkuTable().FtrXe2PlusTiling) { MSAASpecialFactorForDepthAndStencil = 2; // same as 4X } break; case 16: MSAASpecialFactorForDepthAndStencil = 4; if (GetGmmLibContext()->GetSkuTable().FtrXe2PlusTiling) { if (Surf.BitsPerPixel == 64) { MSAASpecialFactorForDepthAndStencil = 8; } } else if (!GetGmmLibContext()->GetSkuTable().FtrTileY && !GetGmmLibContext()->GetSkuTable().FtrXe2PlusTiling) { MSAASpecialFactorForDepthAndStencil = 2; // same as 4X } break; default: break; } } PitchInTiles = static_cast(Surf.Pitch / pPlatform->TileInfo[TileMode].LogicalTileWidth); PitchInTiles /= MSAASpecialFactorForDepthAndStencil; } else { // Surf.TileMode not set correctly __GMM_ASSERT(false); PitchInTiles = 0; } return PitchInTiles; } ///////////////////////////////////////////////////////////////////////////////////// /// Returns unified auxiliary resource's pitch in tiles /// @return Aux Pitch in bytes ///////////////////////////////////////////////////////////////////////////////////// GMM_INLINE_VIRTUAL GMM_INLINE_EXPORTED GMM_GFX_SIZE_T GMM_STDCALL GetUnifiedAuxPitch() { return AuxSurf.Pitch; } ///////////////////////////////////////////////////////////////////////////////////// /// Returns auxiliary resource's pitch in tiles /// @return Aux Pitch in tiles ///////////////////////////////////////////////////////////////////////////////////// GMM_INLINE_VIRTUAL GMM_INLINE_EXPORTED uint32_t GMM_STDCALL GetRenderAuxPitchTiles() { uint32_t PitchInTiles = 0; const GMM_PLATFORM_INFO *pPlatform; __GMM_ASSERT(!AuxSurf.Flags.Info.Linear); pPlatform = (GMM_PLATFORM_INFO *)GMM_OVERRIDE_EXPORTED_PLATFORM_INFO(&AuxSurf, GetGmmLibContext()); if (Surf.Flags.Gpu.UnifiedAuxSurface) { const GMM_TILE_MODE TileMode = AuxSurf.TileMode; __GMM_ASSERT(TileMode < GMM_TILE_MODES); if (pPlatform->TileInfo[TileMode].LogicalTileWidth) { PitchInTiles = static_cast(AuxSurf.Pitch / pPlatform->TileInfo[TileMode].LogicalTileWidth); } } else { PitchInTiles = GetRenderPitchTiles(); } return PitchInTiles; } ///////////////////////////////////////////////////////////////////////////////////// /// Returns resource's bits per pixel /// @return bpp ///////////////////////////////////////////////////////////////////////////////////// GMM_INLINE_VIRTUAL GMM_INLINE_EXPORTED uint32_t GMM_STDCALL GetBitsPerPixel() { return Surf.BitsPerPixel; } ///////////////////////////////////////////////////////////////////////////////////// /// Returns unified aux resource's bits per pixel /// @return aux bpp ///////////////////////////////////////////////////////////////////////////////////// GMM_INLINE_VIRTUAL GMM_INLINE_EXPORTED uint32_t GMM_STDCALL GetUnifiedAuxBitsPerPixel() { __GMM_ASSERT(Surf.Flags.Gpu.UnifiedAuxSurface); return AuxSurf.BitsPerPixel; } ///////////////////////////////////////////////////////////////////////////////////// /// Returns layout of the mips: right or below. /// @return ::GMM_TEXTURE_LAYOUT ///////////////////////////////////////////////////////////////////////////////////// GMM_INLINE_VIRTUAL GMM_INLINE_EXPORTED GMM_TEXTURE_LAYOUT GMM_STDCALL GetTextureLayout() { return Surf.Flags.Info.LayoutRight? GMM_2D_LAYOUT_RIGHT : GMM_2D_LAYOUT_BELOW; } ///////////////////////////////////////////////////////////////////////////////////// /// Returns resource's tile type /// @return ::GMM_TILE_TYPE ///////////////////////////////////////////////////////////////////////////////////// GMM_INLINE_VIRTUAL GMM_INLINE_EXPORTED GMM_TILE_TYPE GMM_STDCALL GetTileType() { if (Surf.Flags.Info.TiledW) { return GMM_TILED_W; } else if (Surf.Flags.Info.TiledX) { return GMM_TILED_X; } // Surf.Flags.Info.TiledYs/Yf tiling are only in // conjunction with Surf.Flags.Info.TiledY/Linear depending on resource type (1D). else if (Surf.Flags.Info.TiledY) { return GMM_TILED_Y; } else if (Surf.Flags.Info.Tile4) { return GMM_TILED_4; } else if (Surf.Flags.Info.Tile64) { return GMM_TILED_64; } return GMM_NOT_TILED; } ///////////////////////////////////////////////////////////////////////////////////// /// Returns resource's tile mode /// @return ::GMM_TILE_MODE ///////////////////////////////////////////////////////////////////////////////////// GMM_INLINE_VIRTUAL GMM_INLINE_EXPORTED GMM_TILE_MODE GMM_STDCALL GmmGetTileMode() { return Surf.TileMode; } ///////////////////////////////////////////////////////////////////////////////////// /// Returns CPU cacheability information /// @return ::GMM_CPU_CACHE_TYPE ///////////////////////////////////////////////////////////////////////////////////// GMM_INLINE_VIRTUAL GMM_INLINE_EXPORTED GMM_CPU_CACHE_TYPE GMM_STDCALL GetCpuCacheType() { if (Surf.Flags.Info.Cacheable) { return GMM_CACHEABLE; } return GMM_NOTCACHEABLE; } ///////////////////////////////////////////////////////////////////////////////////// /// Returns Media Memory Compression mode. /// @param[in] ArrayIndex ArrayIndex for which this info is needed /// @return Media Memory Compression Mode (Disabled, Horizontal, Vertical) ///////////////////////////////////////////////////////////////////////////////////// GMM_INLINE_VIRTUAL GMM_INLINE_EXPORTED GMM_RESOURCE_MMC_INFO GMM_STDCALL GetMmcMode(uint32_t ArrayIndex) { __GMM_ASSERT(ArrayIndex < GMM_MAX_MMC_INDEX); return (ArrayIndex < GMM_MAX_MMC_INDEX) ? (GMM_RESOURCE_MMC_INFO)Surf.MmcMode[ArrayIndex] : GMM_MMC_DISABLED; } ///////////////////////////////////////////////////////////////////////////////////// /// Sets Media Memory Compression mode. /// @param[in] Mode Media Memory Compression Mode (Disabled, Horizontal, Vertical) /// @param[in] ArrayIndex ArrayIndex for which this info needs to be set ///////////////////////////////////////////////////////////////////////////////////// GMM_INLINE_VIRTUAL GMM_INLINE_EXPORTED void GMM_STDCALL SetMmcMode(GMM_RESOURCE_MMC_INFO Mode, uint32_t ArrayIndex) { __GMM_ASSERT((Mode == GMM_MMC_DISABLED) || (Mode == GMM_MMC_HORIZONTAL) || (Mode == GMM_MMC_VERTICAL)); __GMM_ASSERT(ArrayIndex < GMM_MAX_MMC_INDEX); if (ArrayIndex < GMM_MAX_MMC_INDEX) { Surf.MmcMode[ArrayIndex] = static_cast(Mode); } } ///////////////////////////////////////////////////////////////////////////////////// /// Returns whether Media Memory Compression enabled or not. /// @param[in] ArrayIndex ArrayIndex for which this info is needed /// @return 1 (enabled), 0 (disabled) ///////////////////////////////////////////////////////////////////////////////////// GMM_INLINE_VIRTUAL GMM_INLINE_EXPORTED uint8_t GMM_STDCALL IsMediaMemoryCompressed(uint32_t ArrayIndex) { __GMM_ASSERT(ArrayIndex < GMM_MAX_MMC_INDEX); return (ArrayIndex < GMM_MAX_MMC_INDEX) ? Surf.MmcMode[ArrayIndex] != GMM_MMC_DISABLED : 0; } ///////////////////////////////////////////////////////////////////////////////////// /// Returns mmc hints. /// @param[in] ArrayIndex ArrayIndex for which this info is needed /// @return 1/0 ///////////////////////////////////////////////////////////////////////////////////// GMM_INLINE_VIRTUAL GMM_INLINE_EXPORTED GMM_RESOURCE_MMC_HINT GMM_STDCALL GetMmcHint(uint32_t ArrayIndex) { __GMM_ASSERT(ArrayIndex < GMM_MAX_MMC_INDEX); return Surf.MmcHint[ArrayIndex] ? GMM_MMC_HINT_OFF : GMM_MMC_HINT_ON; } ///////////////////////////////////////////////////////////////////////////////////// /// Sets mmc hints. /// @param[in] Hint Mmc hint to store /// @param[in] ArrayIndex ArrayIndex for which this info is needed /// @return ///////////////////////////////////////////////////////////////////////////////////// GMM_INLINE_VIRTUAL GMM_INLINE_EXPORTED void GMM_STDCALL SetMmcHint(GMM_RESOURCE_MMC_HINT Hint, uint32_t ArrayIndex) { __GMM_ASSERT(ArrayIndex < GMM_MAX_MMC_INDEX); __GMM_ASSERT(GMM_MMC_HINT_ON == 0); __GMM_ASSERT(GMM_MMC_HINT_OFF == 1); Surf.MmcHint[ArrayIndex] = static_cast(Hint); } ///////////////////////////////////////////////////////////////////////////////////// /// Returns the MSAA Sample Counter /// @return Sample count ///////////////////////////////////////////////////////////////////////////////////// GMM_INLINE_VIRTUAL GMM_INLINE_EXPORTED uint32_t GMM_STDCALL GetNumSamples() { return Surf.MSAA.NumSamples; } ///////////////////////////////////////////////////////////////////////////////////// /// Returns the MSAA Sample Pattern /// @return Sample pattern ///////////////////////////////////////////////////////////////////////////////////// GMM_INLINE_VIRTUAL GMM_INLINE_EXPORTED GMM_MSAA_SAMPLE_PATTERN GMM_STDCALL GetSamplePattern() { return Surf.MSAA.SamplePattern; } ///////////////////////////////////////////////////////////////////////////////////// /// Returns the X offset of planar surface /// @param[in] Plane: Plane for which the offset is needed /// @return X offset ///////////////////////////////////////////////////////////////////////////////////// GMM_INLINE_VIRTUAL GMM_INLINE_EXPORTED GMM_GFX_SIZE_T GMM_STDCALL GetPlanarXOffset(GMM_YUV_PLANE Plane) { __GMM_ASSERT(Plane < GMM_MAX_PLANE); return Surf.OffsetInfo.Plane.X[Plane]; } ///////////////////////////////////////////////////////////////////////////////////// /// Returns the Y offset of planar surface /// @param[in] Plane: Plane for which the offset is needed /// @return Y offset ///////////////////////////////////////////////////////////////////////////////////// GMM_INLINE_VIRTUAL GMM_INLINE_EXPORTED GMM_GFX_SIZE_T GMM_STDCALL GetPlanarYOffset(GMM_YUV_PLANE Plane) { __GMM_ASSERT(Plane < GMM_MAX_PLANE); return Surf.OffsetInfo.Plane.Y[Plane]; } ///////////////////////////////////////////////////////////////////////////////////// /// Returns the Aux offset of planar surface /// @param[in] ArrayIndex: Surf index for which aux offset is required /// @param[in] GmmAuxType: Aux Plane for which the offset is needed /// @return Y_CCS offset/ UV_CCS offset/ Media compression state ///////////////////////////////////////////////////////////////////////////////////// GMM_INLINE_VIRTUAL GMM_INLINE_EXPORTED GMM_GFX_SIZE_T GMM_STDCALL GetPlanarAuxOffset(uint32_t ArrayIndex, GMM_UNIFIED_AUX_TYPE GmmAuxType) { GMM_GFX_SIZE_T Offset = 0; __GMM_ASSERT(ArrayIndex < Surf.ArraySize); __GMM_ASSERT(GMM_IS_PLANAR(Surf.Format)); if (Surf.Flags.Gpu.UnifiedAuxSurface && !(GetGmmLibContext()->GetSkuTable().FtrFlatPhysCCS)) { if (GmmAuxType == GMM_AUX_Y_CCS) { Offset = Surf.Size; } else if (GmmAuxType == GMM_AUX_UV_CCS) { Offset = Surf.Size + (AuxSurf.Pitch * AuxSurf.OffsetInfo.Plane.Y[GMM_PLANE_U]); //Aux Offset in HwLayout if (Surf.Flags.Gpu.CCS && AuxSurf.Flags.Gpu.__NonMsaaLinearCCS) { Offset = Surf.Size + AuxSurf.OffsetInfo.Plane.X[GMM_PLANE_U]; } else if (Surf.Flags.Gpu.MMC && AuxSurf.Flags.Gpu.__NonMsaaLinearCCS ) { Offset = Surf.Size + AuxSurf.OffsetInfo.Plane.X[GMM_PLANE_Y]; } } else if (GmmAuxType == GMM_AUX_COMP_STATE) { Offset = Surf.Size + AuxSurf.OffsetInfo.Plane.X[GMM_PLANE_Y] + AuxSurf.OffsetInfo.Plane.X[GMM_PLANE_U]; } Offset += AuxSurf.OffsetInfo.Plane.ArrayQPitch * ArrayIndex; } else { Offset = 0; } return Offset; } ///////////////////////////////////////////////////////////////////////////////////// /// Returns the resource Horizontal alignment /// @return HAlign ///////////////////////////////////////////////////////////////////////////////////// GMM_INLINE_VIRTUAL GMM_INLINE_EXPORTED uint32_t GMM_STDCALL GetHAlign() { const __GMM_PLATFORM_RESOURCE *pPlatformResource; uint32_t HAlign; pPlatformResource = (GMM_PLATFORM_INFO *)GMM_OVERRIDE_EXPORTED_PLATFORM_INFO(&Surf, GetGmmLibContext()); if ((GFX_GET_CURRENT_RENDERCORE(pPlatformResource->Platform) >= IGFX_GEN9_CORE) && !(Surf.Flags.Info.TiledYf || GMM_IS_64KB_TILE(Surf.Flags))) { HAlign = Surf.Alignment.HAlign / GetCompressionBlockWidth(); } else { HAlign = Surf.Alignment.HAlign; } return HAlign; } ///////////////////////////////////////////////////////////////////////////////////// /// Returns the resource Vertical alignment /// @return VAlign ///////////////////////////////////////////////////////////////////////////////////// GMM_INLINE_VIRTUAL GMM_INLINE_EXPORTED uint32_t GMM_STDCALL GetVAlign() { const __GMM_PLATFORM_RESOURCE *pPlatformResource; uint32_t VAlign; pPlatformResource = (GMM_PLATFORM_INFO *)GMM_OVERRIDE_EXPORTED_PLATFORM_INFO(&Surf, GetGmmLibContext()); if ((GFX_GET_CURRENT_RENDERCORE(pPlatformResource->Platform) >= IGFX_GEN9_CORE) && !(GetResFlags().Info.TiledYf || GMM_IS_64KB_TILE(GetResFlags()))) { VAlign = Surf.Alignment.VAlign / GetCompressionBlockHeight(); } else { VAlign = Surf.Alignment.VAlign; } return VAlign; } ///////////////////////////////////////////////////////////////////////////////////// /// Returns the auxiliary resource Horizontal alignment /// @return HAlign ///////////////////////////////////////////////////////////////////////////////////// GMM_INLINE_VIRTUAL GMM_INLINE_EXPORTED uint32_t GMM_STDCALL GetAuxHAlign() { if (Surf.Flags.Gpu.UnifiedAuxSurface) { return AuxSurf.Alignment.HAlign; } else { return GetHAlign(); } } ///////////////////////////////////////////////////////////////////////////////////// /// Returns the auxiliary resource Vertical alignment /// @return HAlign ///////////////////////////////////////////////////////////////////////////////////// GMM_INLINE_VIRTUAL GMM_INLINE_EXPORTED uint32_t GMM_STDCALL GetAuxVAlign() { if (Surf.Flags.Gpu.UnifiedAuxSurface) { return AuxSurf.Alignment.VAlign; } else { return GetVAlign(); } } ///////////////////////////////////////////////////////////////////////////////////// /// Returns indication of whether resource uses the MSFMT_DEPTH_STENCIL Multisampled /// Surface Storage Format. /// @return 1/0 ///////////////////////////////////////////////////////////////////////////////////// GMM_INLINE_VIRTUAL GMM_INLINE_EXPORTED uint8_t GMM_STDCALL IsMsaaFormatDepthStencil() { // Gen7 MSAA (non-Depth/Stencil) render targets use (MSFMT_DEPTH_MSS) array // expansion instead of (MSFMT_DEPTH_STENCIL) Width/Height expansion. return (Surf.MSAA.NumSamples > 1) && (Surf.Flags.Gpu.Depth || Surf.Flags.Gpu.SeparateStencil); } ///////////////////////////////////////////////////////////////////////////////////// /// Returns indication of whether resource is SVM or not /// @return 1/0 ///////////////////////////////////////////////////////////////////////////////////// GMM_INLINE_VIRTUAL GMM_INLINE_EXPORTED uint8_t GMM_STDCALL IsSvm() { return static_cast(Surf.Flags.Info.SVM); } ///////////////////////////////////////////////////////////////////////////////////// /// Allows clients to attach a private data to the resource /// @param[in] pNewPrivateData: pointer to opaque private data from clients ///////////////////////////////////////////////////////////////////////////////////// GMM_INLINE_VIRTUAL GMM_INLINE_EXPORTED void GMM_STDCALL SetPrivateData(void *pNewPrivateData) { this->pPrivateData = reinterpret_cast(pNewPrivateData); } ///////////////////////////////////////////////////////////////////////////////////// /// Returns private data attached to the resource /// @return Pointer to opaque private data ///////////////////////////////////////////////////////////////////////////////////// GMM_INLINE_VIRTUAL GMM_INLINE_EXPORTED void* GMM_STDCALL GetPrivateData() { return reinterpret_cast(pPrivateData); } ///////////////////////////////////////////////////////////////////////////////////// /// Returns the resource GFX address /// @return Gfx Address ///////////////////////////////////////////////////////////////////////////////////// GMM_INLINE_VIRTUAL GMM_INLINE_EXPORTED GMM_GFX_ADDRESS GMM_STDCALL GetGfxAddress() { // Support for Sparse/Tiled resources will be unified in later if (SvmAddress) { return GMM_GFX_ADDRESS_CANONIZE(SvmAddress); } else { return 0; } } ///////////////////////////////////////////////////////////////////////////////////// /// This function returns the total height of an S3D tall buffer. For non-S3D /// resources, it returns base height. /// @return Surface height ///////////////////////////////////////////////////////////////////////////////////// GMM_INLINE_VIRTUAL GMM_INLINE_EXPORTED uint32_t GMM_STDCALL GetTallBufferHeight() { if (Surf.Flags.Gpu.S3d) { return Surf.S3d.TallBufferHeight; } else { GMM_ASSERTDPF(0, "Unsupported S3D Resource Type!"); return Surf.BaseHeight; } }; ///////////////////////////////////////////////////////////////////////////////////// /// Returns size of the surface depending on the surface parameters. /// @return Size of surface /// /// Below legacy API to query surface size are deprecated and will be removed in /// later gmm releases. Client must move to unified GetSize() api. /// - GmmResGetSizeSurface()/ pResInfo->GetSizeSurface() /// - GmmResGetSizeMainSurface()/ pResInfo->GetSizeAllocation() /// - GmmResGetSizeAllocation()/ pResInfo->GetSizeMainSurface() ///////////////////////////////////////////////////////////////////////////////////// GMM_INLINE_VIRTUAL GMM_INLINE_EXPORTED GMM_GFX_SIZE_T GMM_STDCALL GetSize(GMM_SIZE_PARAM GmmSizeParam) { GMM_GFX_SIZE_T Size = 0; switch (GmmSizeParam) { case GMM_MAIN_SURF: Size = Surf.Size; break; case GMM_MAIN_PLUS_AUX_SURF: Size = Surf.Size + AuxSurf.Size + AuxSecSurf.Size; break; case GMM_TOTAL_SURF: Size = Surf.Size + AuxSurf.Size + AuxSecSurf.Size; if (Is64KBPageSuitable()) { Size = GFX_ALIGN(Surf.Size + AuxSurf.Size + AuxSecSurf.Size, GMM_KBYTE(64)); } break; case GMM_TOTAL_SURF_PHYSICAL: if(GMM_IS_PLANAR(Surf.Format) && Is1MBAlignedAuxTPlanarSurface()) { Size = (Surf.OffsetInfo.PlaneXe_LPG.Physical.Height[GMM_PLANE_Y] + Surf.OffsetInfo.PlaneXe_LPG.Physical.Height[GMM_PLANE_U] + Surf.OffsetInfo.PlaneXe_LPG.Physical.Height[GMM_PLANE_V]) * Surf.OffsetInfo.PlaneXe_LPG.PhysicalPitch; Size *= GFX_MAX(Surf.ArraySize, 1); Size += AuxSurf.Size + AuxSecSurf.Size; } else { // Physical Size = VA Size Size = GetSize(GMM_TOTAL_SURF); } break; case GMM_MAIN_SURF_PHYSICAL: if(GMM_IS_PLANAR(Surf.Format) && Is1MBAlignedAuxTPlanarSurface()) { Size = (Surf.OffsetInfo.PlaneXe_LPG.Physical.Height[GMM_PLANE_Y] + Surf.OffsetInfo.PlaneXe_LPG.Physical.Height[GMM_PLANE_U] + Surf.OffsetInfo.PlaneXe_LPG.Physical.Height[GMM_PLANE_V]) * Surf.OffsetInfo.PlaneXe_LPG.PhysicalPitch; Size *= GFX_MAX(Surf.ArraySize, 1); } else { // Physical Size = VA Size Size = GetSize(GMM_MAIN_SURF); } break; default: __GMM_ASSERT(0); } return Size; } ///////////////////////////////////////////////////////////////////////////////////// /// Returns size of the main surface only. Aux surface size not included. /// @return Size of main surface ///////////////////////////////////////////////////////////////////////////////////// GMM_INLINE_VIRTUAL GMM_INLINE_EXPORTED GMM_GFX_SIZE_T GMM_STDCALL GetSizeMainSurface() const { return Surf.Size; } ///////////////////////////////////////////////////////////////////////////////////// /// Returns the number of bytes that are required to back this padded and aligned /// resource. The calculation takes into consideration more than simply width /// height and bits per pixel. Width padding (stride), pixel formats, inter-plane /// padding depts/array-size and so on also for part of the list of factors. /// @return Surface Size ///////////////////////////////////////////////////////////////////////////////////// GMM_INLINE_VIRTUAL GMM_INLINE_EXPORTED GMM_GFX_SIZE_T GMM_STDCALL GetSizeSurface() { GMM_OVERRIDE_SIZE_64KB_ALLOC(GetGmmLibContext()); return (Surf.Size + AuxSurf.Size + AuxSecSurf.Size); } ///////////////////////////////////////////////////////////////////////////////////// /// Returns surface size(GetSizeSurface) plus additional padding due to 64kb pages /// @return Allocation Size ///////////////////////////////////////////////////////////////////////////////////// GMM_INLINE_VIRTUAL GMM_INLINE_EXPORTED GMM_GFX_SIZE_T GMM_STDCALL GetSizeAllocation() { if (Is64KBPageSuitable()) { return(GFX_ALIGN(Surf.Size + AuxSurf.Size + AuxSecSurf.Size, GMM_KBYTE(64))); } else { return (Surf.Size + AuxSurf.Size + AuxSecSurf.Size); } } ///////////////////////////////////////////////////////////////////////////////////// /// Returns max no of GpuVa bits supported per resource on a given platform /// @return Max # of GpuVA bits per resource ///////////////////////////////////////////////////////////////////////////////////// GMM_INLINE_VIRTUAL GMM_INLINE_EXPORTED uint32_t GMM_STDCALL GetMaxGpuVirtualAddressBits() { const GMM_PLATFORM_INFO *pPlatform = (GMM_PLATFORM_INFO *)GMM_OVERRIDE_EXPORTED_PLATFORM_INFO(&Surf, GetGmmLibContext()); __GMM_ASSERTPTR(pPlatform, 0); return pPlatform->MaxGpuVirtualAddressBitsPerResource; } ///////////////////////////////////////////////////////////////////////////////////// /// Returns the surface offset for unified allocations /// @param[in] GmmAuxType: the type of aux the offset is needed for /// @return Surface Offset in bytes ///////////////////////////////////////////////////////////////////////////////////// GMM_INLINE_VIRTUAL GMM_INLINE_EXPORTED GMM_GFX_SIZE_T GMM_STDCALL GetUnifiedAuxSurfaceOffset(GMM_UNIFIED_AUX_TYPE GmmAuxType) { GMM_GFX_SIZE_T Offset = 0; const GMM_PLATFORM_INFO *pPlatform; pPlatform = (GMM_PLATFORM_INFO *)GMM_OVERRIDE_EXPORTED_PLATFORM_INFO(&Surf, GetGmmLibContext()); GMM_UNREFERENCED_PARAMETER(pPlatform); if (Surf.Flags.Gpu.UnifiedAuxSurface) { if ((GmmAuxType == GMM_AUX_CCS) || (GmmAuxType == GMM_AUX_SURF) || (GmmAuxType == GMM_AUX_Y_CCS) || (GmmAuxType == GMM_AUX_HIZ) || (GmmAuxType == GMM_AUX_MCS)) { Offset = Surf.Size; if (GmmAuxType == GMM_AUX_CCS && AuxSecSurf.Type != RESOURCE_INVALID && (Surf.Flags.Gpu.CCS && (Surf.MSAA.NumSamples > 1 || Surf.Flags.Gpu.Depth))) { Offset += AuxSurf.Size; } } else if (GmmAuxType == GMM_AUX_UV_CCS) { Offset = Surf.Size + (AuxSurf.Pitch * AuxSurf.OffsetInfo.Plane.Y[GMM_PLANE_U]); //Aux Offset in HwLayout if (Surf.Flags.Gpu.CCS && AuxSurf.Flags.Gpu.__NonMsaaLinearCCS) { Offset = Surf.Size + AuxSurf.OffsetInfo.Plane.X[GMM_PLANE_U]; } else if (Surf.Flags.Gpu.MMC && AuxSurf.Flags.Gpu.__NonMsaaLinearCCS ) { Offset = Surf.Size + AuxSurf.OffsetInfo.Plane.X[GMM_PLANE_Y]; } } else if ((GmmAuxType == GMM_AUX_CC) && (Surf.Flags.Gpu.IndirectClearColor || Surf.Flags.Gpu.ColorDiscard)) { Offset = Surf.Size + AuxSurf.UnpaddedSize; if (GetGmmLibContext()->GetSkuTable().FtrXe2Compression) { if (Surf.MSAA.NumSamples > 1) { Offset = Surf.Size; // Beginning of MCS which is first 4K of AuxSurf, Clear colour is stored only for MSAA surfaces } } } else if (GmmAuxType == GMM_AUX_COMP_STATE) { Offset = Surf.Size + AuxSurf.OffsetInfo.Plane.X[GMM_PLANE_Y] + AuxSurf.OffsetInfo.Plane.X[GMM_PLANE_U]; } else if ((GmmAuxType == GMM_AUX_ZCS) && Surf.Flags.Gpu.Depth && Surf.Flags.Gpu.CCS) { if (AuxSecSurf.Type != RESOURCE_INVALID) { Offset = Surf.Size + AuxSurf.Size; } } } else if(GmmAuxType == GMM_AUX_CC && Surf.Flags.Gpu.IndirectClearColor && Surf.Flags.Gpu.HiZ) { Offset = Surf.Size - GMM_HIZ_CLEAR_COLOR_SIZE; } else if (GmmAuxType == GMM_AUX_CC && Surf.Flags.Gpu.ColorDiscard && !Surf.Flags.Gpu.CCS) { Offset = Surf.Size; } else { Offset = 0; } if((GetGmmLibContext()->GetSkuTable().FtrFlatPhysCCS) && !Surf.Flags.Gpu.ProceduralTexture && (GmmAuxType == GMM_AUX_CCS || GmmAuxType == GMM_AUX_ZCS || GmmAuxType == GMM_AUX_Y_CCS || GmmAuxType == GMM_AUX_UV_CCS)) { Offset = 0; } return Offset; } ///////////////////////////////////////////////////////////////////////////////////// /// Returns the surface size for unified allocations /// @param[in] GmmAuxType: the type of aux the size is needed for /// @return Surface Size in bytes ///////////////////////////////////////////////////////////////////////////////////// GMM_INLINE_VIRTUAL GMM_INLINE_EXPORTED GMM_GFX_SIZE_T GMM_STDCALL GetSizeAuxSurface(GMM_UNIFIED_AUX_TYPE GmmAuxType) { if (GmmAuxType == GMM_AUX_SURF) { return (AuxSurf.Size + AuxSecSurf.Size); } else if (GmmAuxType == GMM_AUX_CCS || GmmAuxType == GMM_AUX_HIZ || GmmAuxType == GMM_AUX_MCS) { if(GmmAuxType == GMM_AUX_CCS && GetGmmLibContext()->GetSkuTable().FtrFlatPhysCCS && !Surf.Flags.Gpu.ProceduralTexture) { return 0; } if (GmmAuxType == GMM_AUX_CCS && AuxSecSurf.Type != RESOURCE_INVALID && (Surf.Flags.Gpu.CCS && (Surf.MSAA.NumSamples > 1 || Surf.Flags.Gpu.Depth))) { return AuxSecSurf.Size; } else { return (AuxSurf.UnpaddedSize); } } else if (GmmAuxType == GMM_AUX_COMP_STATE) { return GMM_MEDIA_COMPRESSION_STATE_SIZE; } else if (GmmAuxType == GMM_AUX_CC) { if (!Surf.Flags.Gpu.UnifiedAuxSurface && Surf.Flags.Gpu.HiZ) { return GMM_HIZ_CLEAR_COLOR_SIZE; } else { if (GetGmmLibContext()->GetSkuTable().FtrXe2Compression) { if (Surf.MSAA.NumSamples > 1) { return (AuxSurf.UnpaddedSize); // CC is part of MCS } else { return 0; // fixed CC values used, not stored as part of Aux } } else { return (AuxSurf.CCSize); } } } else if (GmmAuxType == GMM_AUX_ZCS) { if (Surf.Flags.Gpu.UnifiedAuxSurface && AuxSecSurf.Type != RESOURCE_INVALID) { return AuxSecSurf.Size; } else { return 0; } } else { return 0; } } ///////////////////////////////////////////////////////////////////////// /// This function returns or sets the value of the hardware protected flag /// associated with the given GMM resource within same process. /// @param[in] GetIsEncrypted: Read encryption status /// @param[in] SetIsEncrypted: Write encryption status /// @return Whether surface is encrypted or not ///////////////////////////////////////////////////////////////////////// virtual GMM_INLINE_EXPORTED uint8_t GMM_STDCALL GetSetHardwareProtection(uint8_t GetIsEncrypted, uint8_t SetIsEncrypted) { uint8_t IsEncrypted = 0; if (GetIsEncrypted) { IsEncrypted = Surf.Flags.Info.HardwareProtected; } else { Surf.Flags.Info.HardwareProtected = IsEncrypted = SetIsEncrypted; } return IsEncrypted; } ///////////////////////////////////////////////////////////////////////// /// This function returns or sets the value of the Cp surface tag /// associated with the given GMM resource within same process. /// @param[in] IsSet: true for updating tag in gmm /// @param[in] CpTag: Cp surface tag value /// @return current cp surface tag in gmm ///////////////////////////////////////////////////////////////////////// GMM_INLINE_VIRTUAL GMM_INLINE uint32_t GMM_STDCALL GetSetCpSurfTag(uint8_t IsSet, uint32_t CpTag) { if (IsSet) { Surf.CpTag = CpTag; } return Surf.CpTag; } ///////////////////////////////////////////////////////////////////////// /// Returns the size of the surface in StdLayout format /// @return Size in bytes of Standard Layout version of surface. ///////////////////////////////////////////////////////////////////////// GMM_INLINE_VIRTUAL GMM_INLINE_EXPORTED GMM_GFX_SIZE_T GMM_STDCALL GetStdLayoutSize() { GMM_REQ_OFFSET_INFO GetOffset = {}; GetOffset.ReqStdLayout = 1; GetOffset.StdLayout.Offset = static_cast(-1); // Special Req for StdLayout Size this->GetOffset(GetOffset); return GetOffset.StdLayout.Offset; } ///////////////////////////////////////////////////////////////////////// /// Returns whether resource is color separated target /// @return 1 if the resource is color separated target, 0 otherwise ///////////////////////////////////////////////////////////////////////// GMM_INLINE_VIRTUAL GMM_INLINE_EXPORTED uint8_t GMM_STDCALL IsColorSeparation() { return Surf.Flags.Gpu.ColorSeparation || Surf.Flags.Gpu.ColorSeparationRGBX; } ///////////////////////////////////////////////////////////////////////// /// Translate packed source x coordinate to color separation target x coordinate /// @param[in] x: X coordinate /// @return Translated color separation target x coordinate ///////////////////////////////////////////////////////////////////////// GMM_INLINE_VIRTUAL GMM_INLINE_EXPORTED uint32_t GMM_STDCALL TranslateColorSeparationX(uint32_t x) { uint32_t ret = x; if (Surf.Flags.Gpu.ColorSeparation) { ret /= GMM_COLOR_SEPARATION_WIDTH_DIVISION; } else if (Surf.Flags.Gpu.ColorSeparationRGBX) { ret /= GMM_COLOR_SEPARATION_RGBX_WIDTH_DIVISION; } return ret; } ///////////////////////////////////////////////////////////////////////// /// Returns the array size of a color separated target resource. /// @return Array size of a color separated target resource ///////////////////////////////////////////////////////////////////////// GMM_INLINE_VIRTUAL GMM_INLINE_EXPORTED uint32_t GMM_STDCALL GetColorSeparationArraySize() { if (Surf.Flags.Gpu.ColorSeparation || Surf.Flags.Gpu.ColorSeparationRGBX) { return GMM_COLOR_SEPARATION_ARRAY_SIZE; } else { return Surf.ArraySize; } } ///////////////////////////////////////////////////////////////////////// /// Returns the physical width of a color separated target resource /// @return physical width of a color separated target resource ///////////////////////////////////////////////////////////////////////// GMM_INLINE_VIRTUAL GMM_INLINE_EXPORTED uint32_t GMM_STDCALL GetColorSeparationPhysicalWidth() { if (Surf.Flags.Gpu.ColorSeparation) { return ((uint32_t)Surf.BaseWidth * Surf.ArraySize) / GMM_COLOR_SEPARATION_WIDTH_DIVISION; } else if (Surf.Flags.Gpu.ColorSeparationRGBX) { return ((uint32_t)Surf.BaseWidth * Surf.ArraySize) / GMM_COLOR_SEPARATION_RGBX_WIDTH_DIVISION; } else { return (uint32_t)Surf.BaseWidth; } } ///////////////////////////////////////////////////////////////////////// /// Returns whether surface can be faulted on /// @return 1 is surface can be faulted on ///////////////////////////////////////////////////////////////////////// virtual GMM_INLINE_EXPORTED uint8_t GMM_STDCALL IsSurfaceFaultable() { return 0; } ///////////////////////////////////////////////////////////////////////////////////// /// Returns the cache policy usage associated with this surface. /// @return Cache Policy Usage ///////////////////////////////////////////////////////////////////////////////////// GMM_INLINE_VIRTUAL GMM_INLINE_EXPORTED GMM_RESOURCE_USAGE_TYPE GMM_STDCALL GetCachePolicyUsage() { return Surf.CachePolicy.Usage; } //################################################################################## // Functions that can help clients program the SURFACE_STATE with appropriate values. //################################################################################## ///////////////////////////////////////////////////////////////////////////////////// /// Returns the surface state value for Mip Tail Start LOD /// @return Mip Tail Start ///////////////////////////////////////////////////////////////////////////////////// GMM_INLINE_VIRTUAL GMM_INLINE_EXPORTED uint32_t GMM_STDCALL GetMipTailStartLodSurfaceState() { return Surf.Alignment.MipTailStartLod; } ///////////////////////////////////////////////////////////////////////////////////// /// Returns the Tile Address Mapping Mode, for SURFACE_STATE programming and is /// applicable only for 3D surface /// @return Tile Address Mapping Mode ///////////////////////////////////////////////////////////////////////////////////// GMM_INLINE_VIRTUAL GMM_INLINE_EXPORTED uint32_t GMM_STDCALL GetTileAddressMappingModeSurfaceState() { return 0; } ///////////////////////////////////////////////////////////////////////////////////// /// Returns the horizontal alignment for SURFACE_STATE programming. /// @return HAlign ///////////////////////////////////////////////////////////////////////////////////// GMM_INLINE_VIRTUAL GMM_INLINE_EXPORTED uint32_t GMM_STDCALL GetHAlignSurfaceState() { uint32_t HAlign = 0; const GMM_PLATFORM_INFO *pPlatform; pPlatform = (GMM_PLATFORM_INFO *)GMM_OVERRIDE_EXPORTED_PLATFORM_INFO(&Surf, GetGmmLibContext()); if (GFX_GET_CURRENT_RENDERCORE(pPlatform->Platform) >= IGFX_GEN8_CORE) { if (GetResFlags().Info.TiledYf || GMM_IS_64KB_TILE(GetResFlags())) { HAlign = 1; // Ignored, but we'll return valid encoding nonetheless. } else { if(GMM_IS_TILEY(GetGmmLibContext())) { switch (GetHAlign()) { case 4: HAlign = 1; break; case 8: HAlign = 2; break; case 16: HAlign = 3; break; default: HAlign = 1; // Change back to 0 + assert after packed YUV handling corrected. } } else { uint32_t Align = GetHAlign() * (GetBitsPerPixel() >> 3); if (Surf.BitsPerPixel == 24 || Surf.BitsPerPixel == 48 || Surf.BitsPerPixel == 96) { Align = GetHAlign(); } switch (Align) { case 16: HAlign = 0; break; case 32: HAlign = 1; break; case 64: HAlign = 2; break; case 128: case 256: HAlign = 3; break; default: HAlign = 0; __GMM_ASSERT(0); } } } } else { switch (Surf.Alignment.HAlign) { case 4: HAlign = 0; break; case 8: HAlign = 1; break; default: HAlign = 0; __GMM_ASSERT(0); } } return HAlign; } ///////////////////////////////////////////////////////////////////////////////////// /// Returns the vertical alignment for SURFACE_STATE programming. /// @return HAlign ///////////////////////////////////////////////////////////////////////////////////// GMM_INLINE_VIRTUAL GMM_INLINE_EXPORTED uint32_t GMM_STDCALL GetVAlignSurfaceState() { uint32_t VAlign; const GMM_PLATFORM_INFO *pPlatform; pPlatform = (GMM_PLATFORM_INFO *)GMM_OVERRIDE_EXPORTED_PLATFORM_INFO(&Surf, GetGmmLibContext()); if (GFX_GET_CURRENT_RENDERCORE(pPlatform->Platform) >= IGFX_GEN8_CORE) { if (GetResFlags().Info.TiledYf || GMM_IS_64KB_TILE(GetResFlags())) { VAlign = 1; // Ignored, but we'll return valid encoding nonetheless. } else { switch (GetVAlign()) { case 4: VAlign = 1; break; case 8: VAlign = 2; break; case 16: VAlign = 3; break; default: VAlign = 1; } } } else { switch (Surf.Alignment.VAlign) { case 2: VAlign = 0; break; case 4: VAlign = 1; break; default: VAlign = 0; __GMM_ASSERT(0); } } return VAlign; } ///////////////////////////////////////////////////////////////////////////////////// /// Returns tile mode for SURFACE_STATE programming. /// @return Tiled Mode ///////////////////////////////////////////////////////////////////////////////////// GMM_INLINE_VIRTUAL GMM_INLINE_EXPORTED uint32_t GMM_STDCALL GetTileModeSurfaceState() { return GetTileModeSurfaceState(&Surf); } ///////////////////////////////////////////////////////////////////////////////////// /// Returns tile mode for AUX SURFACE_STATE programming. /// @return Tiled Mode ///////////////////////////////////////////////////////////////////////////////////// GMM_INLINE_VIRTUAL GMM_INLINE_EXPORTED uint32_t GMM_STDCALL GetAuxTileModeSurfaceState() { return GetTileModeSurfaceState(&AuxSurf); } ///////////////////////////////////////////////////////////////////////////////////// /// Returns tiled resource mode for SURFACE_STATE programming. /// @return Tiled Resource Mode ///////////////////////////////////////////////////////////////////////////////////// GMM_INLINE_VIRTUAL GMM_INLINE_EXPORTED uint32_t GMM_STDCALL GetTiledResourceModeSurfaceState() { uint32_t TiledResourceMode = 0; if(GMM_IS_TILEY(GetGmmLibContext())) { if (Surf.Flags.Info.TiledYf) { TiledResourceMode = 1; } else if (Surf.Flags.Info.TiledYs) { TiledResourceMode = 2; } else { TiledResourceMode = 0; } } else { __GMM_ASSERT(0); } return TiledResourceMode; } //################################################################################### // Functions that allows clients to override certain members // of ResourceInfo. Client assumes the risk of using these functions. // May cause unintended side-affects. //################################################################################## ///////////////////////////////////////////////////////////////////////////////////// /// Overrides the main surface size /// @param[in] Size: new size of the resource ///////////////////////////////////////////////////////////////////////////////////// GMM_INLINE_VIRTUAL GMM_INLINE_EXPORTED void GMM_STDCALL OverrideSize(GMM_GFX_SIZE_T Size) { Surf.Size = Size; } ///////////////////////////////////////////////////////////////////////////////////// /// Overrides the surface pitch /// @param[in] Pitch: new pitch of the resource ///////////////////////////////////////////////////////////////////////////////////// GMM_INLINE_VIRTUAL GMM_INLINE_EXPORTED void GMM_STDCALL OverridePitch(GMM_GFX_SIZE_T Pitch) { Surf.Pitch = Pitch; } ///////////////////////////////////////////////////////////////////////////////////// /// Overrides the aux surface pitch /// @param[in] Pitch: new pitch of the aux surface ///////////////////////////////////////////////////////////////////////////////////// GMM_INLINE_VIRTUAL GMM_INLINE_EXPORTED void GMM_STDCALL OverrideUnifiedAuxPitch(GMM_GFX_SIZE_T Pitch) { __GMM_ASSERT(Surf.Flags.Gpu.UnifiedAuxSurface); AuxSurf.Pitch = Pitch; } ///////////////////////////////////////////////////////////////////////////////////// /// Overrides the allocation flags /// @param[in] Flags: new set of flags for the resource ///////////////////////////////////////////////////////////////////////////////////// GMM_INLINE_VIRTUAL GMM_INLINE_EXPORTED void GMM_STDCALL OverrideAllocationFlags(GMM_RESOURCE_FLAG& Flags) { Surf.Flags = Flags; } ///////////////////////////////////////////////////////////////////////////////////// /// Overrides the resource HAlign /// @param[in] HAlign: new HAlign for the resource ///////////////////////////////////////////////////////////////////////////////////// GMM_INLINE_VIRTUAL GMM_INLINE_EXPORTED void GMM_STDCALL OverrideHAlign(uint32_t HAlign) { Surf.Alignment.HAlign = HAlign; } ///////////////////////////////////////////////////////////////////////////////////// /// Overrides the resource BaseAlignment /// @param[in] Alignment: new BaseAlignment for the resource ///////////////////////////////////////////////////////////////////////////////////// GMM_INLINE_VIRTUAL GMM_INLINE_EXPORTED void GMM_STDCALL OverrideBaseAlignment(uint32_t Alignment) { Surf.Alignment.BaseAlignment = Alignment; } ///////////////////////////////////////////////////////////////////////////////////// /// Overrides the resource BaseWidth /// @param[in] BaseWidth: new BaseWidth for the resource ///////////////////////////////////////////////////////////////////////////////////// GMM_INLINE_VIRTUAL GMM_INLINE_EXPORTED void GMM_STDCALL OverrideBaseWidth(GMM_GFX_SIZE_T BaseWidth) { Surf.BaseWidth = BaseWidth; } ///////////////////////////////////////////////////////////////////////////////////// /// Overrides the resource BaseHeight /// @param[in] BaseHeight: new BaseHeight for the resource ///////////////////////////////////////////////////////////////////////////////////// GMM_INLINE_VIRTUAL GMM_INLINE_EXPORTED void GMM_STDCALL OverrideBaseHeight(uint32_t BaseHeight) { Surf.BaseHeight = BaseHeight; } ///////////////////////////////////////////////////////////////////////////////////// /// Overrides the resource Depth /// @param[in] Depth: new Depth for the resource ///////////////////////////////////////////////////////////////////////////////////// GMM_INLINE_VIRTUAL GMM_INLINE_EXPORTED void GMM_STDCALL OverrideDepth(uint32_t Depth) { Surf.Depth = Depth; } ///////////////////////////////////////////////////////////////////////////////////// /// Overrides the resource tile mode /// @param[in] TileMode: new tile mode for the resource ///////////////////////////////////////////////////////////////////////////////////// GMM_INLINE_VIRTUAL GMM_INLINE_EXPORTED void GMM_STDCALL OverrideTileMode(GMM_TILE_MODE TileMode) { Surf.TileMode = TileMode; } ///////////////////////////////////////////////////////////////////////////////////// /// Overrides the resource tile mode /// @param[in] TileMode: new tile mode for the resource ///////////////////////////////////////////////////////////////////////////////////// GMM_INLINE_VIRTUAL GMM_INLINE_EXPORTED void GMM_STDCALL OverrideUnifiedAuxTileMode(GMM_TILE_MODE TileMode) { __GMM_ASSERT(Surf.Flags.Gpu.UnifiedAuxSurface); AuxSurf.TileMode = TileMode; } ///////////////////////////////////////////////////////////////////////////////////// /// Overrides the surface format /// @param[in] Format: new format for the resource ///////////////////////////////////////////////////////////////////////////////////// GMM_INLINE_VIRTUAL GMM_INLINE_EXPORTED void GMM_STDCALL OverrideSurfaceFormat(GMM_RESOURCE_FORMAT Format) { Surf.Format = Format; } ///////////////////////////////////////////////////////////////////////////////////// /// Overrides the surface type /// @param[in] Type: new surface type for the resource ///////////////////////////////////////////////////////////////////////////////////// GMM_INLINE_VIRTUAL GMM_INLINE_EXPORTED void GMM_STDCALL OverrideSurfaceType(GMM_RESOURCE_TYPE Type) { Surf.Type = Type; } ///////////////////////////////////////////////////////////////////////////////////// /// Overrides the svm gfx address /// @param[in] SvmGfxAddress: new svm gfx address for the resource ///////////////////////////////////////////////////////////////////////////////////// GMM_INLINE_VIRTUAL GMM_INLINE_EXPORTED void GMM_STDCALL OverrideSvmGfxAddress(GMM_GFX_ADDRESS SvmGfxAddress) { this->SvmAddress = SvmGfxAddress; } ///////////////////////////////////////////////////////////////////////////////////// /// Overrides the resource array size /// @param[in] ArraySize: new array size for the resource ///////////////////////////////////////////////////////////////////////////////////// GMM_INLINE_VIRTUAL GMM_INLINE_EXPORTED void GMM_STDCALL OverrideArraySize(uint32_t ArraySize) { Surf.ArraySize = ArraySize; } ///////////////////////////////////////////////////////////////////////////////////// /// Overrides the resource max LOD /// @param[in] MaxLod: new max LOD for the resource ///////////////////////////////////////////////////////////////////////////////////// GMM_INLINE_VIRTUAL GMM_INLINE_EXPORTED void GMM_STDCALL OverrideMaxLod(uint32_t MaxLod) { Surf.MaxLod = MaxLod; } ///////////////////////////////////////////////////////////////////////////////////// /// Overrides the resource cache policy usage /// @param[in] Usage: new usage for the resource ///////////////////////////////////////////////////////////////////////////////////// GMM_INLINE_VIRTUAL GMM_INLINE_EXPORTED void GMM_STDCALL OverrideCachePolicyUsage(GMM_RESOURCE_USAGE_TYPE Usage) { Surf.CachePolicy.Usage = Usage; } ///////////////////////////////////////////////////////////////////////////////////// /// Overrides the platform associated with this resource /// @param[in] Platform: new platform for the resource /// @note Function only available for Debug/Release-Internal builds. ///////////////////////////////////////////////////////////////////////////////////// #if(_DEBUG || _RELEASE_INTERNAL) GMM_INLINE_VIRTUAL GMM_INLINE_EXPORTED void GMM_STDCALL OverridePlatform(PLATFORM Platform) { Surf.Platform = Platform; } #endif ///////////////////////////////////////////////////////////////////////////////////// /// Overrides the GmmLibContext associated with this resource /// @param[in] pNewGmmLibContext: new GmmLibContext for the resource ///////////////////////////////////////////////////////////////////////////////////// GMM_INLINE_VIRTUAL GMM_INLINE_EXPORTED void GMM_STDCALL OverrideGmmLibContext(Context *pNewGmmLibContext) { #if(defined(__GMM_KMD__)) this->pGmmKmdLibContext = reinterpret_cast(pNewGmmLibContext); #else this->pGmmUmdLibContext = reinterpret_cast(pNewGmmLibContext); #endif } ///////////////////////////////////////////////////////////////////////////////////// /// Overrides the X offset of planar surface /// @param[in] Plane: Plane for which the offset needs to be overriden /// @param[in] XOffset: X offset ///////////////////////////////////////////////////////////////////////////////////// GMM_INLINE_VIRTUAL GMM_INLINE_EXPORTED void GMM_STDCALL OverridePlanarXOffset(GMM_YUV_PLANE Plane, GMM_GFX_SIZE_T XOffset) { __GMM_ASSERT(Plane < GMM_MAX_PLANE); Surf.OffsetInfo.Plane.X[Plane] = XOffset; } ///////////////////////////////////////////////////////////////////////////////////// /// Overrides the Y offset of planar surface /// @param[in] Plane: Plane for which the offset needs to be overriden /// @param[in] YOffset: Y offset ///////////////////////////////////////////////////////////////////////////////////// GMM_INLINE_VIRTUAL GMM_INLINE_EXPORTED void GMM_STDCALL OverridePlanarYOffset(GMM_YUV_PLANE Plane, GMM_GFX_SIZE_T YOffset) { __GMM_ASSERT(Plane < GMM_MAX_PLANE); Surf.OffsetInfo.Plane.Y[Plane] = YOffset; } GMM_VIRTUAL GMM_STATUS GMM_STDCALL CreateCustomRes(Context& GmmLibContext, GMM_RESCREATE_CUSTOM_PARAMS& CreateParams); protected: GMM_VIRTUAL void UpdateUnAlignedParams(); public: ///////////////////////////////////////////////////////////////////////////////////// /// Returns the resource's compressions block width /// @return Compression block width ///////////////////////////////////////////////////////////////////////////////////// GMM_INLINE_VIRTUAL GMM_INLINE_EXPORTED uint32_t GMM_STDCALL GetCompressionBlockWidth() { GMM_RESOURCE_FORMAT Format; Format = Surf.Format; __GMM_ASSERT((Format > GMM_FORMAT_INVALID) && (Format < GMM_RESOURCE_FORMATS)); return GetGmmLibContext()->GetPlatformInfo().FormatTable[Format].Element.Width; } ///////////////////////////////////////////////////////////////////////////////////// /// Returns the resource's compressions block height /// @return Compression block width ///////////////////////////////////////////////////////////////////////////////////// GMM_INLINE_VIRTUAL GMM_INLINE_EXPORTED uint32_t GMM_STDCALL GetCompressionBlockHeight() { GMM_RESOURCE_FORMAT Format; Format = Surf.Format; __GMM_ASSERT((Format > GMM_FORMAT_INVALID) && (Format < GMM_RESOURCE_FORMATS)); return GetGmmLibContext()->GetPlatformInfo().FormatTable[Format].Element.Height; } ///////////////////////////////////////////////////////////////////////////////////// /// Returns the resource's compressions block depth /// @return Compression block width ///////////////////////////////////////////////////////////////////////////////////// GMM_INLINE_VIRTUAL GMM_INLINE_EXPORTED uint32_t GMM_STDCALL GetCompressionBlockDepth() { GMM_RESOURCE_FORMAT Format; Format = Surf.Format; __GMM_ASSERT((Format > GMM_FORMAT_INVALID) && (Format < GMM_RESOURCE_FORMATS)); return GetGmmLibContext()->GetPlatformInfo().FormatTable[Format].Element.Depth; } ///////////////////////////////////////////////////////////////////////////////////// /// Returns whether resource uses LOD0-only or Full array spacing /// @return 1/0 ///////////////////////////////////////////////////////////////////////////////////// GMM_INLINE_VIRTUAL GMM_INLINE_EXPORTED uint8_t GMM_STDCALL IsArraySpacingSingleLod() { __GMM_ASSERT(GFX_GET_CURRENT_RENDERCORE(GetGmmLibContext()->GetPlatformInfo().Platform) < IGFX_GEN8_CORE); return Surf.Alignment.ArraySpacingSingleLod; } ///////////////////////////////////////////////////////////////////////////////////// /// Returns whether resource is ASTC /// @return 1/0 ///////////////////////////////////////////////////////////////////////////////////// GMM_INLINE_VIRTUAL GMM_INLINE_EXPORTED uint8_t GMM_STDCALL IsASTC() { GMM_RESOURCE_FORMAT Format; Format = Surf.Format; return (Format > GMM_FORMAT_INVALID) && (Format < GMM_RESOURCE_FORMATS) && GetGmmLibContext()->GetPlatformInfo().FormatTable[Format].ASTC; } ///////////////////////////////////////////////////////////////////////////////////// /// Returns MOCS associated with the resource /// @param[in] MOCS ///////////////////////////////////////////////////////////////////////////////////// GMM_INLINE_VIRTUAL GMM_INLINE_EXPORTED MEMORY_OBJECT_CONTROL_STATE GMM_STDCALL GetMOCS() { const GMM_CACHE_POLICY_ELEMENT *CachePolicy = GetGmmLibContext()->GetCachePolicyUsage(); GMM_RESOURCE_USAGE_TYPE Usage = GetCachePolicyUsage(); __GMM_ASSERT(CachePolicy[Usage].Initialized); // Prevent wrong Usage for XAdapter resources. UMD does not call GetMemoryObject on shader resources but, // when they add it someone could call it without knowing the restriction. if(Surf.Flags.Info.XAdapter && (Usage != GMM_RESOURCE_USAGE_XADAPTER_SHARED_RESOURCE)) { __GMM_ASSERT(false); } if((CachePolicy[Usage].Override & CachePolicy[Usage].IDCode) || (CachePolicy[Usage].Override == ALWAYS_OVERRIDE)) { return CachePolicy[Usage].MemoryObjectOverride; } return CachePolicy[Usage].MemoryObjectNoOverride; } ///////////////////////////////////////////////////////////////////////////////////// /// Returns the surface state value for Standard Tiling Mode Extension /// @return Standard Tiling Mode Extension ///////////////////////////////////////////////////////////////////////////////////// GMM_INLINE_VIRTUAL GMM_INLINE_EXPORTED uint32_t GMM_STDCALL GetStdTilingModeExtSurfaceState() { __GMM_ASSERT(GFX_GET_CURRENT_RENDERCORE(GetGmmLibContext()->GetPlatformInfo().Platform) > IGFX_GEN10_CORE); if(GetGmmLibContext()->GetSkuTable().FtrStandardMipTailFormat) { return 1; } return 0; } ///////////////////////////////////////////////////////////////////////////////////// /// Returns the surface state value for Resource Format /// @return Resource Format ///////////////////////////////////////////////////////////////////////////////////// GMM_INLINE_VIRTUAL GMM_INLINE_EXPORTED GMM_SURFACESTATE_FORMAT GMM_STDCALL GetResourceFormatSurfaceState() { GMM_RESOURCE_FORMAT Format; Format = Surf.Format; __GMM_ASSERT((Format > GMM_FORMAT_INVALID) && (Format < GMM_RESOURCE_FORMATS)); return GetGmmLibContext()->GetPlatformInfo().FormatTable[Format].SurfaceStateFormat; } GMM_INLINE_VIRTUAL GMM_INLINE_EXPORTED const GMM_MULTI_TILE_ARCH& GetMultiTileArch() { return MultiTileArch; } ///////////////////////////////////////////////////////////////////////////////////// /// Returns the Flat Phys CCS Size for the resource /// @return CCS size in bytes ///////////////////////////////////////////////////////////////////////////////////// GMM_INLINE_VIRTUAL GMM_INLINE_EXPORTED GMM_GFX_SIZE_T GMM_STDCALL GetFlatPhysCcsSize() { if((GetGmmLibContext()->GetSkuTable().FtrFlatPhysCCS) && !(Surf.Flags.Info.AllowVirtualPadding || Surf.Flags.Info.ExistingSysMem || Surf.Flags.Info.NonLocalOnly)) { if (GetGmmLibContext()->GetSkuTable().FtrXe2Compression) { return GFX_CEIL_DIV(Surf.Size, 512); } else { return GFX_CEIL_DIV(Surf.Size, 256); } } return 0; } ///////////////////////////////////////////////////////////////////////////////////// /// Returns Tiled mode for DEPTH_BUFFER_STATE/STENCIL_BUFFER_STATE/ HIER_DEPTH_BUFFER programming. /// HIZ is always 4kb tiling, XeHP+ TileMode for HIZ is Tile4 and main surface can be /// Tile64 , GMM_AUX_INVALID, will return data for main depth/stencil resource , /// GMM_AUX_HiZ returns data for HIZ resource /// @return Tiled Resource Mode(PreGen12) / Tiled Mode(Gen12+) ///////////////////////////////////////////////////////////////////////////////////// GMM_INLINE_VIRTUAL GMM_INLINE_EXPORTED uint32_t GMM_STDCALL GetTiledModeDepthStencilState( GMM_UNIFIED_AUX_TYPE AuxType = GMM_AUX_INVALID) { uint32_t TiledMode = 0; if(GMM_IS_TILEY(GetGmmLibContext())) { TiledMode = Surf.Flags.Info.TiledYf ? 1 : Surf.Flags.Info.TiledYs ? 2 : /*TILE_NONE*/ 0; } else { //1 and 3 are only valid value , 0 and 2 are reserved for XeHP+ if( (AuxType == GMM_AUX_HIZ) && AuxSurf.Flags.Gpu.HiZ ) { TiledMode = AuxSurf.Flags.Info.Tile4 ? 3 : AuxSurf.Flags.Info.Tile64 ? 1 : /* Default */ 0; __GMM_ASSERT(TiledMode == 3); } else { TiledMode = Surf.Flags.Info.Tile4 ? 3 : Surf.Flags.Info.Tile64 ? 1 : /* Default */ 0; __GMM_ASSERT( TiledMode ); } } return TiledMode; } #ifndef __GMM_KMD__ GMM_VIRTUAL GMM_STATUS GMM_STDCALL CreateCustomRes_2(Context &GmmLibContext, GMM_RESCREATE_CUSTOM_PARAMS_2 &CreateParams); #endif ///////////////////////////////////////////////////////////////////////////////////// /// Returns physical size of the main surface only. Aux surface size not included. /// @return Physical Size of main surface ///////////////////////////////////////////////////////////////////////////////////// GMM_INLINE_VIRTUAL GMM_INLINE_EXPORTED GMM_GFX_SIZE_T GMM_STDCALL GetSizeMainSurfacePhysical() { GMM_GFX_SIZE_T Size; if(GMM_IS_PLANAR(Surf.Format) && Is1MBAlignedAuxTPlanarSurface()) { Size = ((Surf.OffsetInfo.PlaneXe_LPG.Physical.Height[GMM_PLANE_Y] + Surf.OffsetInfo.PlaneXe_LPG.Physical.Height[GMM_PLANE_U] + Surf.OffsetInfo.PlaneXe_LPG.Physical.Height[GMM_PLANE_V]) * Surf.OffsetInfo.PlaneXe_LPG.PhysicalPitch); Size *= GFX_MAX(Surf.ArraySize, 1); } else { // Physical Size = VA Size Size = GetSizeMainSurface(); } return Size; } ///////////////////////////////////////////////////////////////////////////////////// /// Returns total physical size of surface. /// @return Surface Size ///////////////////////////////////////////////////////////////////////////////////// GMM_INLINE_VIRTUAL GMM_INLINE_EXPORTED GMM_GFX_SIZE_T GMM_STDCALL GetSizeSurfacePhysical() { GMM_GFX_SIZE_T Size; if(GMM_IS_PLANAR(Surf.Format) && Is1MBAlignedAuxTPlanarSurface()) { Size = (Surf.OffsetInfo.PlaneXe_LPG.Physical.Height[GMM_PLANE_Y] + Surf.OffsetInfo.PlaneXe_LPG.Physical.Height[GMM_PLANE_U] + Surf.OffsetInfo.PlaneXe_LPG.Physical.Height[GMM_PLANE_V]) * Surf.OffsetInfo.PlaneXe_LPG.PhysicalPitch; Size *= GFX_MAX(Surf.ArraySize, 1); Size += AuxSurf.Size + AuxSecSurf.Size; } else { // Physical Size = VA Size Size = GetSizeSurface(); }; return Size; } ///////////////////////////////////////////////////////////////////////////////////// /// Returns if a resource is 1MB aligned AuxT enabled planar surface /// @return Is1MBAuxTAlignedPlanes Flag ///////////////////////////////////////////////////////////////////////////////////// GMM_INLINE_VIRTUAL GMM_INLINE_EXPORTED uint32_t GMM_STDCALL Is1MBAlignedAuxTPlanarSurface() { const GMM_PLATFORM_INFO *pPlatform = (GMM_PLATFORM_INFO *)GMM_OVERRIDE_EXPORTED_PLATFORM_INFO(&Surf, GetGmmLibContext()); if(GMM_IS_1MB_AUX_TILEALIGNEDPLANES(pPlatform->Platform, Surf)) { return Surf.OffsetInfo.PlaneXe_LPG.Is1MBAuxTAlignedPlanes; } return 0; } GMM_INLINE_VIRTUAL GMM_INLINE_EXPORTED uint32_t GMM_STDCALL IsResourceMappedCompressible() { uint32_t CompressedRes = 0; if (GetGmmLibContext()->GetSkuTable().FtrXe2Compression) { CompressedRes = !Surf.Flags.Info.NotCompressed; } else { CompressedRes = Surf.Flags.Info.RenderCompressed || Surf.Flags.Info.MediaCompressed; } return CompressedRes; } ///////////////////////////////////////////////////////////////////////////////////// /// Returns true for displayable resources /// @return ///////////////////////////////////////////////////////////////////////////////////// GMM_INLINE_VIRTUAL GMM_INLINE_EXPORTED bool GMM_STDCALL IsDisplayable() { return ((Surf.Type == RESOURCE_PRIMARY) || (Surf.Type == RESOURCE_CURSOR) || Surf.Flags.Gpu.FlipChain || Surf.Flags.Gpu.Overlay); } GMM_INLINE_VIRTUAL GMM_INLINE_EXPORTED uint64_t GMM_STDCALL GetDriverProtectionBits(GMM_OVERRIDE_VALUES OverrideData) { GMM_DRIVERPROTECTION DriverProtection = {{0}}; const GMM_PLATFORM_INFO *pPlatform; GMM_RESOURCE_USAGE_TYPE Usage; pPlatform = (GMM_PLATFORM_INFO *)GMM_OVERRIDE_EXPORTED_PLATFORM_INFO(&Surf, GetGmmLibContext()); if (GFX_GET_CURRENT_PRODUCT(pPlatform->Platform) < IGFX_PVC) { return 0; } Usage = Surf.CachePolicy.Usage; if ((OverrideData.Usage > GMM_RESOURCE_USAGE_UNKNOWN) && (OverrideData.Usage < GMM_RESOURCE_USAGE_MAX)) { Usage = (GMM_RESOURCE_USAGE_TYPE)OverrideData.Usage; } if (GetGmmLibContext()->GetSkuTable().FtrXe2Compression) { if (OverrideData.CompressionDis) { DriverProtection.CompressionEnReq = 0; } else { DriverProtection.CompressionEnReq = !Surf.Flags.Info.NotCompressed; } } bool IscompressionEn = DriverProtection.CompressionEnReq ? true : false; DriverProtection.CacheableNoSnoop = false; DriverProtection.PATIndex = GetGmmLibContext()->GetCachePolicyObj()->CachePolicyGetPATIndex(NULL, Usage, &IscompressionEn, (bool)(Surf.Flags.Info.Cacheable)); DriverProtection.CompressionEnReq = IscompressionEn ? true : false; return DriverProtection.Value; } GMM_VIRTUAL uint64_t GMM_STDCALL Get2DFastClearSurfaceWidthFor3DSurface(uint32_t MipLevel); GMM_VIRTUAL uint64_t GMM_STDCALL Get2DFastClearSurfaceHeightFor3DSurface(uint32_t MipLevel); }; } // namespace GmmLib #endif // #ifdef __cplusplus gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/inc/External/Common/GmmResourceInfoExt.h000066400000000000000000001210021466655022700275300ustar00rootroot00000000000000/*============================================================================== Copyright(c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ============================================================================*/ #pragma once #ifdef __cplusplus extern "C" { #endif /*__cplusplus*/ #if _WIN32 #ifndef __GMM_KMD__ typedef LONG NTSTATUS; #include #include #include #endif #endif // Set packing alignment #pragma pack(push, 8) // Rotation bitmap fields #define GMM_KMD_ROTATE 0x00000001 // this is to inform KMD to enable // rotation in Full screen case // Color separation textures width division factors and array size #define GMM_COLOR_SEPARATION_WIDTH_DIVISION 4 #define GMM_COLOR_SEPARATION_RGBX_WIDTH_DIVISION 3 #define GMM_COLOR_SEPARATION_ARRAY_SIZE 4 // XXX: Change that to 3 once 2nd green scanout using sprites is validated //=========================================================================== // typedef: // GMM_RESOURCE_MMC_INFO // // Description: // This struct is used to describe Media Memory Compression information. //--------------------------------------------------------------------------- typedef enum GMM_RESOURCE_MMC_INFO_REC { GMM_MMC_DISABLED = 0, GMM_MMC_HORIZONTAL, GMM_MMC_VERTICAL, }GMM_RESOURCE_MMC_INFO; //=========================================================================== // typedef: // GMM_RESOURCE_MMC_HINT // // Description: // This struct is used to indicate if Media Memory Compression is needed. //--------------------------------------------------------------------------- typedef enum GMM_RESOURCE_MMC_HINT_REC { GMM_MMC_HINT_ON = 0, GMM_MMC_HINT_OFF, }GMM_RESOURCE_MMC_HINT; //=========================================================================== // typedef: // GMM_MSAA_SAMPLE_PATTERN // // Description: // This enum details the sample pattern of a MSAA texture //--------------------------------------------------------------------------- typedef enum GMM_MSAA_SAMPLE_PATTERN_REC { GMM_MSAA_DISABLED = 0, GMM_MSAA_STANDARD, GMM_MSAA_CENTEROID, GMM_MSAA_REGULAR }GMM_MSAA_SAMPLE_PATTERN; typedef enum GMM_TILE_RANGE_FLAG_ENUM { GMM_TILE_RANGE_NULL = 0x00000001, GMM_TILE_RANGE_SKIP = 0x00000002, GMM_TILE_RANGE_REUSE_SINGLE_TILE = 0x00000004, } GMM_TILE_RANGE_FLAG; //=========================================================================== // typedef: // GMM_RESOURCE_MSAA_INFO // // Description: // This struct is used to describe MSAA information. //--------------------------------------------------------------------------- typedef struct GMM_RESOURCE_MSAA_INFO_REC { GMM_MSAA_SAMPLE_PATTERN SamplePattern; uint32_t NumSamples; }GMM_RESOURCE_MSAA_INFO; //=========================================================================== // typedef: // GMM_RESOURCE_ALIGNMENT_UNITS // // Description: // Various alignment units of an allocation. // NOTE: H/VAlign and QPitch stored *UNCOMPRESSED* here, despite Gen9+ // SURFACE_STATE using compressed!!! //--------------------------------------------------------------------------- typedef struct GMM_RESOURCE_ALIGNMENT_REC { uint8_t ArraySpacingSingleLod; // Single-LOD/Full Array Spacing uint32_t BaseAlignment; // Base Alignment uint32_t HAlign, VAlign, DAlign; // Alignment Unit Width/Height uint32_t MipTailStartLod; // Mip Tail (SKL+) uint32_t PackedMipStartLod; // Packed Mip (Pre-Gen9 / Undefined64KBSwizzle) uint32_t PackedMipWidth; // Packed Mip Width in # of 64KB Tiles (Pre-Gen9 / Undefined64KBSwizzle) uint32_t PackedMipHeight; // Packed Mip Height in # of 64KB Tiles (Pre-Gen9 / Undefined64KBSwizzle) uint32_t QPitch; // Programmable QPitch (BDW+) }GMM_RESOURCE_ALIGNMENT; //=========================================================================== // typedef: // GMM_PAGETABLE_MGR // // Description: // This struct is used to describe page table manager. // Forward Declaration: Defined in GmmPageTableMgr.h //--------------------------------------------------------------------------- #ifdef __cplusplus namespace GmmLib { class GmmPageTableMgr; } typedef GmmLib::GmmPageTableMgr GMM_PAGETABLE_MGR; #else typedef struct GmmPageTableMgr GMM_PAGETABLE_MGR; #endif #ifdef __cplusplus namespace GmmLib { class Context; } // namespace GmmLib typedef GmmLib::Context GMM_LIB_CONTEXT; #else typedef struct GmmLibContext GMM_LIB_CONTEXT; #endif //=========================================================================== // typedef: // GMM_RESOURCE_INFO // // Description: // This struct is used to describe resource allocations. // Forward Declaration: Defined in GmmResourceInfo*.h //--------------------------------------------------------------------------- #ifdef __cplusplus namespace GmmLib { #ifdef _WIN32 class GmmResourceInfoWin; typedef GmmResourceInfoWin GmmResourceInfo; #else class GmmResourceInfoLin; typedef GmmResourceInfoLin GmmResourceInfo; #endif } typedef GmmLib::GmmResourceInfo GMM_RESOURCE_INFO; typedef GmmLib::GmmResourceInfo GMM_RESOURCE_INFO_REC; typedef GmmLib::GmmResourceInfo* PGMM_RESOURCE_INFO; #else typedef struct GmmResourceInfo GMM_RESOURCE_INFO; typedef struct GmmResourceInfo* PGMM_RESOURCE_INFO; #endif //=========================================================================== // Place holder for GMM_RESOURCE_FLAG definition. //--------------------------------------------------------------------------- #include "GmmResourceFlags.h" #if defined __linux__ #include "External/Linux/GmmResourceInfoLinExt.h" #endif //========================================================================== // typedef: // GMM_S3D_OFFSET_INFO // // Description: // Contains offset info for S3D resources. // //-------------------------------------------------------------------------- typedef struct GMM_S3D_OFFSET_INFO_REC { uint32_t AddressOffset; uint32_t OffsetX; uint32_t OffsetY; uint32_t LineOffsetY; } GMM_S3D_OFFSET_INFO; //========================================================================== // typedef: // GMM_S3D_INFO // // Description: // Describes properties of S3D feature. // //-------------------------------------------------------------------------- typedef struct GMM_S3D_INFO_REC { uint32_t DisplayModeHeight; // Current display mode resolution uint32_t NumBlankActiveLines; // Number of blank lines uint32_t RFrameOffset; // R frame offset uint32_t BlankAreaOffset; // Blank area offset uint32_t TallBufferHeight; // Tall buffer height uint32_t TallBufferSize; // Tall buffer size uint8_t IsRFrame; // Flag indicating this is the R frame } GMM_S3D_INFO; //=========================================================================== // typedef: // GMM_MULTI_TILE_ARCH // // Description: // This structure is provides an advanced allocation interface for 4xXeHP // multi tile Gpu support //--------------------------------------------------------------------------- typedef struct GMM_MULTI_TILE_ARCH_REC // FtrMultiTileArch Advanced Parameters... { uint8_t Enable : 1; // When FALSE, this struct is ignored // and GMM will make such decisions // based on the process's default // tile assignment from KMD. uint8_t TileInstanced : 1; // When TRUE allocation is Tile // instanced resource uint8_t GpuVaMappingSet; // Bitmask indicating which tiles // should receive page table updates // when this allocation is mapped. // For all tiles set ADAPTER_INFO.MultiTileArch.TileMask uint8_t LocalMemEligibilitySet; // Bitmask indicating which tile's // Local Memory this allocation // can reside in--i.e. in addition to // its preferred set, which others // can it be migrated to under memory // pressure. Entirely zeroed mask // would be used for NonLocalOnly // allocations. uint8_t LocalMemPreferredSet; // Bitmask indicating subset of above // eligibility set that is preferred // above the others. Entirely zeroed // mask is equivalent to mask of all // ones--i.e. "no preference within // eligibility set". uint32_t Reserved; } GMM_MULTI_TILE_ARCH; //=========================================================================== // typedef: // GMM_RESCREATE_PARAMS // // Description: // This structure is used to describe an resource allocation request. // Please note that AllocationReuse makes use of member order. // more info: oskl.h: AllocationReusePredicate and Functor //--------------------------------------------------------------------------- typedef struct GMM_RESCREATE_PARAMS_REC { GMM_RESOURCE_TYPE Type; // 1D/2D/.../SCRATCH/... GMM_RESOURCE_FORMAT Format; // Pixel format e.g. NV12, GENERIC_8BIT GMM_RESOURCE_FLAG Flags; // See substructure type. GMM_RESOURCE_MSAA_INFO MSAA; // How to sample this resource for anti-alisaing. GMM_RESOURCE_USAGE_TYPE Usage; // Intended use for this resource. See enumerated type. uint32_t CpTag; union { uint32_t BaseWidth; // Aligned width of buffer (aligned according to .Format) GMM_GFX_SIZE_T BaseWidth64; // The HW buffer types, BUFFER and STRBUF, are arrays of user-defined // struct's. Their natural sizing parameters are (1) the struct size // and (2) the numer of array elements (i.e. the number of structs). // However, the GMM allows these to be allocated in either of two ways: // (1) Client computes total allocation size and passes via BaseWidth // (leaving ArraySize 0), or (2) Client passes natural sizing parameters // via BaseWidth and ArraySize. To make the latter more readable, // clients can use the BaseWidth union alias, BufferStructSize (as well // as the GmmResGetBaseWidth alias, GmmResGetBufferStructSize). uint32_t BufferStructSize; // Note: If ever de-union'ing, mind the GmmResGetBufferStructSize #define. }; uint32_t BaseHeight; // Aligned height of buffer (aligned according to .Format) uint32_t Depth; // For 3D resources Depth>1, for 1D/2D, a default of 0 is uplifted to 1. uint32_t MaxLod; uint32_t ArraySize; // A number of n-dimensional buffers can be allocated together. uint32_t BaseAlignment; uint32_t OverridePitch; #if(LHDM) D3DDDI_RATIONAL DdiRefreshRate; D3DDDI_RESOURCEFLAGS DdiD3d9Flags; D3DDDIFORMAT DdiD3d9Format; D3DDDI_VIDEO_PRESENT_SOURCE_ID DdiVidPnSrcId; #endif uint32_t RotateInfo; uint64_t pExistingSysMem; GMM_GFX_SIZE_T ExistingSysMemSize; #ifdef _WIN32 D3DKMT_HANDLE hParentAllocation; //For ExistingSysMem Virtual Padding #endif #if __GMM_KMD__ uint32_t CpuAccessible; // Kernel mode clients set if CPU pointer to resource is required. GMM_S3D_INFO S3d; void *pDeviceContext; #endif uint32_t MaximumRenamingListLength; uint8_t NoGfxMemory; GMM_RESOURCE_INFO *pPreallocatedResInfo; GMM_MULTI_TILE_ARCH MultiTileArch; } GMM_RESCREATE_PARAMS; typedef struct GMM_RESCREATE_CUSTOM_PARAMS__REC { GMM_RESOURCE_TYPE Type; // 1D/2D/.../SCRATCH/... GMM_RESOURCE_FORMAT Format; // Pixel format e.g. NV12, GENERIC_8BIT GMM_RESOURCE_FLAG Flags; // See substructure type. GMM_RESOURCE_USAGE_TYPE Usage; // Intended use for this resource. See enumerated type. GMM_GFX_SIZE_T BaseWidth64; uint32_t BaseHeight; // Aligned height of buffer (aligned according to .Format) uint32_t Pitch; GMM_GFX_SIZE_T Size; uint32_t BaseAlignment; struct { uint32_t X[GMM_MAX_PLANE]; uint32_t Y[GMM_MAX_PLANE]; }PlaneOffset; uint32_t NoOfPlanes; uint32_t CpTag; }GMM_RESCREATE_CUSTOM_PARAMS; typedef union GMM_DRIVERPROTECTION_BITS { struct { uint64_t PATIndex : 5; // PATIndex uint64_t Reserved : 25; uint64_t CacheableNoSnoop: 1; // disregard OS's coherent request in UpdatePageTable uint64_t CompressionEnReq: 1; // C/NC request from UMD uint64_t Reserved1 : 32; //DO NOT SET !! Reserved for OS Refer: D3DGPU_UNIQUE_DRIVER_PROTECTION }; uint64_t Value; } GMM_DRIVERPROTECTION; #ifndef __GMM_KMD__ typedef struct GMM_RESCREATE_CUSTOM_PARAMS_2_REC : public GMM_RESCREATE_CUSTOM_PARAMS { struct { uint32_t Pitch; GMM_GFX_SIZE_T Size; uint32_t BaseAlignment; struct { uint32_t X[GMM_MAX_PLANE]; uint32_t Y[GMM_MAX_PLANE]; } PlaneOffset; } AuxSurf; uint64_t Reserved; uint64_t Reserved1; }GMM_RESCREATE_CUSTOM_PARAMS_2; #endif typedef struct GMM_OVERRIDE_VALUES_REC { uint32_t Usage; // GMM_RESOURCE_USAGE_TYPE uint8_t CompressionDis; } GMM_OVERRIDE_VALUES; //=========================================================================== // enum : // GMM_UNIFIED_AUX_TYPE // // Description: // This enumarates various aux surface types in a unified // auxiliary surface //--------------------------------------------------------------------------- // Usage : // UMD client use this enum to request the aux offset and size. // using via GmmResGetAuxSurfaceOffset, GmmResGetSizeAuxSurface // // RT buffer with Clear Color // ________________________________________________ // | | // | | // | | // | Pixel Data | // | | // | | // | | // | | // | | // | | // A | | // -->|________________________________________________| // | | | // | | | // | Tag plane | | // | (a.k.a mcs, aux-plane,ccs) | ------------|->GmmResGetSizeAuxSurface(pRes, GMM_AUX_CCS) // | | | // -->|__________________________________| | // B | CC FV | CC NV | ------------------------------|--->GmmResGetSizeAuxSurface(pRes, GMM_AUX_CC) // |_______|________| | // | | // | | // | Padded to Main Surf's(TileHeight & SurfPitch)| --> Padding needed for Global GTT aliasing // -->|________________________________________________| // C | | // | Tag plane | // | for MSAA/Depth compr | // | (a.k.a ccs, zcs) ------------|->GmmResGetSizeAuxSurface(pRes, GMM_AUX_CCS or GMM_AUX_ZCS) // |________________________________________________| // // Where // FV. Clear color Float Value // NV. Clear color Native Value // A. GmmResGetAuxSurfaceOffset(pRes, GMM_AUX_CCS) // B. GmmResGetAuxSurfaceOffset(pRes, GMM_AUX_CC) // C. GmmResGetAuxSurfaceOffset(pRes, GMM_AUX_CCS or GMM_AUX_ZCS) typedef enum { GMM_AUX_INVALID, // Main resource GMM_AUX_CCS, // RT buffer's color control surface (Unpadded) GMM_AUX_Y_CCS, // color control surface for Y-plane GMM_AUX_UV_CCS, // color control surface for UV-plane GMM_AUX_CC, // clear color value (4kb granularity) GMM_AUX_COMP_STATE, // Media compression state (cacheline aligned 64B) GMM_AUX_HIZ, // HiZ surface for unified Depth buffer GMM_AUX_MCS, // multi-sample control surface for unified MSAA GMM_AUX_ZCS, // CCS for Depth Z compression GMM_AUX_SURF // Total Aux Surface (CCS + CC + Padding) } GMM_UNIFIED_AUX_TYPE; //=========================================================================== // enum : // GMM_SIZE_PARAM // // Description: // This enumarates various surface size parameters available for GetSize query. // Refer GmmResourceInfoCommon.h GetSize() api // // Note: // Below legacy API to query surface size are deprecated and will be removed in // later gmm releases. // - GmmResGetSizeSurface()/ pResInfo->GetSizeSurface() // - GmmResGetSizeMainSurface()/ pResInfo->GetSizeAllocation() // - GmmResGetSizeAllocation()/ pResInfo->GetSizeMainSurface() //--------------------------------------------------------------------------- // Usage : // UMD client use this enum to request the surface size. //=========================================================================== typedef enum { GMM_INVALID_PARAM, // Leave 0 as invalid to force client to explictly set GMM_MAIN_SURF, // Main surface size(w/o aux data) GMM_MAIN_PLUS_AUX_SURF, // Main surface plus auxilary data, includes ccs, cc, zcs, mcs metadata. Renderable portion of the surface. GMM_TOTAL_SURF, // Main+Aux with additional padding based on hardware PageSize. GMM_MAPGPUVA_SIZE = GMM_TOTAL_SURF,// To be used for mapping gpu virtual address space. GMM_TOTAL_SURF_PHYSICAL, GMM_MAIN_SURF_PHYSICAL, } GMM_SIZE_PARAM; //=========================================================================== // typedef: // GMM_RES_COPY_BLT // // Description: // Describes a GmmResCpuBlt operation. //--------------------------------------------------------------------------- typedef struct GMM_RES_COPY_BLT_REC { struct // GPU Surface Description... { void *pData; // Pointer to base of the mapped resource data (e.g. D3DDDICB_LOCK.pData). uint32_t Slice; // Array/Volume Slice or Cube Face; zero if N/A. uint32_t MipLevel; // Index of applicable MIP, or zero if N/A. //uint32_t MsaaSample; // Index of applicable MSAA sample, or zero if N/A. uint32_t OffsetX; // Pixel offset from left-edge of specified (Slice/MipLevel) subresource. uint32_t OffsetY; // Pixel row offset from top of specified subresource. uint32_t OffsetSubpixel; // Byte offset into the surface pixel of the applicable subpixel. } Gpu; // Surface description of GPU resource involved in BLT. struct // System Surface Description... { void *pData; // Pointer to system memory surface. uint32_t RowPitch; // Row pitch in bytes of pData surface. uint32_t SlicePitch; // Slice pitch in bytes of pData surface; ignored if Blt.Slices <= 1. uint32_t PixelPitch; // Number of bytes from one pData pixel to its horizontal neighbor; 0 = "Same as GPU Resource". //uint32_t MsaaSamplePitch;// Number of bytes from one pData MSAA sample to the next; ignored if Blt.MsaaSamples <= 1. uint32_t BufferSize; // Number of bytes at pData. (Value used only in asserts to catch overuns.) } Sys; // Description of system memory surface being BLT'ed to/from the GPU surface. struct // BLT Description... { uint32_t Width; // Copy width in pixels; 0 = "Full Width" of specified subresource. uint32_t Height; // Copy height in pixel rows; 0 = "Full Height" of specified subresource. uint32_t Slices; // Number of slices being copied; 0 = 1 = "N/A or single slice". uint32_t BytesPerPixel; // Number of bytes to copy, per pixel; 0 = "Same as Sys.PixelPitch". //uint32_t MsaaSamples; // Number of samples to copy per pixel; 0 = 1 = "N/A or single sample". uint8_t Upload; // true = Sys-->Gpu; false = Gpu-->Sys. } Blt; // Description of the BLT being performed. } GMM_RES_COPY_BLT; //=========================================================================== // typedef: // GMM_GET_MAPPING // // Description: // GmmResGetMappingSpanDesc interface and inter-call state. //--------------------------------------------------------------------------- typedef enum { GMM_MAPPING_NULL = 0, GMM_MAPPING_LEGACY_Y_TO_STDSWIZZLE_SHAPE, GMM_MAPPING_GEN9_YS_TO_STDSWIZZLE, GMM_MAPPING_YUVPLANAR, GMM_MAPPING_YUVPLANAR_AUX, } GMM_GET_MAPPING_TYPE; typedef struct GMM_GET_MAPPING_REC { GMM_GET_MAPPING_TYPE Type; struct { GMM_GFX_SIZE_T VirtualOffset; GMM_GFX_SIZE_T PhysicalOffset; GMM_GFX_SIZE_T Size; } Span, __NextSpan; struct { struct { uint32_t Width, Height, Depth; // in Uncompressed Pixels } Element, Tile; struct { GMM_GFX_SIZE_T Physical, Virtual; } Slice0MipOffset, SlicePitch; uint32_t EffectiveLodMax, Lod, Row, RowPitchVirtual, Rows, Slice, Slices; GMM_YUV_PLANE Plane, LastPlane; } Scratch; // Zero on initial call to GmmResGetMappingSpanDesc and then let persist. } GMM_GET_MAPPING; //*************************************************************************** // // GMM_RESOURCE_INFO API // //*************************************************************************** uint8_t GMM_STDCALL GmmIsPlanar(GMM_RESOURCE_FORMAT Format); uint8_t GMM_STDCALL GmmIsP0xx(GMM_RESOURCE_FORMAT Format); uint8_t GMM_STDCALL GmmIsUVPacked(GMM_RESOURCE_FORMAT Format); bool GMM_STDCALL GmmIsYUVFormatLCUAligned(GMM_RESOURCE_FORMAT Format); #define GmmIsYUVPlanar GmmIsPlanar // TODO(Benign): Support old name until we have a chance to correct in UMD(s) using this. No longer YUV since there are now RGB planar formats. uint8_t GMM_STDCALL GmmIsReconstructableSurface(GMM_RESOURCE_FORMAT Format); uint8_t GMM_STDCALL GmmIsCompressed(void *pLibContext, GMM_RESOURCE_FORMAT Format); uint8_t GMM_STDCALL GmmIsYUVPacked(GMM_RESOURCE_FORMAT Format); uint8_t GMM_STDCALL GmmIsRedecribedPlanes(GMM_RESOURCE_INFO *pGmmResource); uint8_t GMM_STDCALL GmmResApplyExistingSysMem(GMM_RESOURCE_INFO *pGmmResource, void *pExistingSysMem, GMM_GFX_SIZE_T ExistingSysMemSize); uint8_t GMM_STDCALL GmmGetLosslessCompressionType(void *pLibContext, GMM_RESOURCE_FORMAT Format); GMM_RESOURCE_INFO* GMM_STDCALL GmmResCopy(GMM_RESOURCE_INFO *pGmmResource); void GMM_STDCALL GmmResMemcpy(void *pDst, void *pSrc); uint8_t GMM_STDCALL GmmResCpuBlt(GMM_RESOURCE_INFO *pGmmResource, GMM_RES_COPY_BLT *pBlt); GMM_RESOURCE_INFO *GMM_STDCALL GmmResCreate(GMM_RESCREATE_PARAMS *pCreateParams, GMM_LIB_CONTEXT *pLibContext); void GMM_STDCALL GmmResFree(GMM_RESOURCE_INFO *pGmmResource); GMM_GFX_SIZE_T GMM_STDCALL GmmResGetSizeMainSurface(const GMM_RESOURCE_INFO *pResourceInfo); GMM_GFX_SIZE_T GMM_STDCALL GmmResGetSizeSurface(GMM_RESOURCE_INFO *pResourceInfo); GMM_GFX_SIZE_T GMM_STDCALL GmmResGetSizeAllocation(GMM_RESOURCE_INFO *pResourceInfo); uint32_t GMM_STDCALL GmmResGetArraySize(GMM_RESOURCE_INFO *pGmmResource); uint32_t GMM_STDCALL GmmResGetAuxBitsPerPixel(GMM_RESOURCE_INFO *pGmmResource); uint32_t GMM_STDCALL GmmResGetAuxPitch(GMM_RESOURCE_INFO *pGmmResource); uint32_t GMM_STDCALL GmmResGetAuxQPitch(GMM_RESOURCE_INFO *pGmmResource); uint8_t GMM_STDCALL GmmResIs64KBPageSuitable(GMM_RESOURCE_INFO *pGmmResource); uint32_t GMM_STDCALL GmmResGetAuxSurfaceOffset(GMM_RESOURCE_INFO *pGmmResource, GMM_UNIFIED_AUX_TYPE GmmAuxType); GMM_GFX_SIZE_T GMM_STDCALL GmmResGetAuxSurfaceOffset64(GMM_RESOURCE_INFO *pGmmResource, GMM_UNIFIED_AUX_TYPE GmmAuxType); GMM_GFX_SIZE_T GMM_STDCALL GmmResGetSizeAuxSurface(GMM_RESOURCE_INFO *pGmmResource, GMM_UNIFIED_AUX_TYPE GmmAuxType); uint32_t GMM_STDCALL GmmResGetAuxHAlign(GMM_RESOURCE_INFO *pGmmResource); uint32_t GMM_STDCALL GmmResGetAuxVAlign(GMM_RESOURCE_INFO *pGmmResource); uint32_t GMM_STDCALL GmmResGetBaseAlignment(GMM_RESOURCE_INFO *pGmmResource); uint32_t GMM_STDCALL GmmResGetBaseHeight(GMM_RESOURCE_INFO *pGmmResource); uint32_t GMM_STDCALL GmmResGetBaseWidth(GMM_RESOURCE_INFO *pGmmResource); GMM_GFX_SIZE_T GMM_STDCALL GmmResGetBaseWidth64(GMM_RESOURCE_INFO *pGmmResource); uint32_t GMM_STDCALL GmmResGetBitsPerPixel(GMM_RESOURCE_INFO *pGmmResource); #define GmmResGetBufferStructSize GmmResGetBaseWidth // See GMM_RESCREATE_PARAMS.BufferStructSize comment. uint32_t GMM_STDCALL GmmResGetCompressionBlockDepth(GMM_RESOURCE_INFO *pGmmResource); uint32_t GMM_STDCALL GmmResGetCompressionBlockHeight(GMM_RESOURCE_INFO *pGmmResource); uint32_t GMM_STDCALL GmmResGetCompressionBlockWidth(GMM_RESOURCE_INFO *pGmmResource); GMM_CPU_CACHE_TYPE GMM_STDCALL GmmResGetCpuCacheType(GMM_RESOURCE_INFO *pGmmResource); uint32_t GMM_STDCALL GmmResGetDepth(GMM_RESOURCE_INFO *pGmmResource); void GMM_STDCALL GmmResGetFlags(GMM_RESOURCE_INFO *pGmmResource, GMM_RESOURCE_FLAG *pFlags /*output*/); //TODO: Remove after changing all UMDs GMM_RESOURCE_FLAG GMM_STDCALL GmmResGetResourceFlags(const GMM_RESOURCE_INFO *pGmmResource); GMM_GFX_ADDRESS GMM_STDCALL GmmResGetGfxAddress(GMM_RESOURCE_INFO *pGmmResource); uint32_t GMM_STDCALL GmmResGetHAlign(GMM_RESOURCE_INFO *pGmmResource); #define GmmResGetLockPitch GmmResGetRenderPitch // Support old name until UMDs drop use. uint8_t GMM_STDCALL GmmResGetMappingSpanDesc(GMM_RESOURCE_INFO *pGmmResource, GMM_GET_MAPPING *pMapping); uint32_t GMM_STDCALL GmmResGetMaxLod(GMM_RESOURCE_INFO *pGmmResource); GMM_GFX_SIZE_T GMM_STDCALL GmmResGetStdLayoutSize(GMM_RESOURCE_INFO *pGmmResource); uint32_t GMM_STDCALL GmmResGetSurfaceStateMipTailStartLod(GMM_RESOURCE_INFO *pGmmResource); uint32_t GMM_STDCALL GmmResGetSurfaceStateTileAddressMappingMode(GMM_RESOURCE_INFO *pGmmResource); uint32_t GMM_STDCALL GmmResGetSurfaceStateStdTilingModeExt(GMM_RESOURCE_INFO *pGmmResource); GMM_RESOURCE_MMC_INFO GMM_STDCALL GmmResGetMmcMode(GMM_RESOURCE_INFO *pGmmResource, uint32_t ArrayIndex); uint32_t GMM_STDCALL GmmResGetNumSamples(GMM_RESOURCE_INFO *pGmmResource); GMM_STATUS GMM_STDCALL GmmResGetOffset(GMM_RESOURCE_INFO *pGmmResource, GMM_REQ_OFFSET_INFO *pReqInfo); GMM_STATUS GMM_STDCALL GmmResGetOffsetFor64KBTiles(GMM_RESOURCE_INFO *pGmmResource, GMM_REQ_OFFSET_INFO *pReqInfo); uint32_t GMM_STDCALL GmmResGetPaddedHeight(GMM_RESOURCE_INFO *pGmmResource, uint32_t MipLevel); uint32_t GMM_STDCALL GmmResGetPaddedWidth(GMM_RESOURCE_INFO *pGmmResource, uint32_t MipLevel); uint32_t GMM_STDCALL GmmResGetPaddedPitch(GMM_RESOURCE_INFO *pGmmResource, uint32_t MipLevel); void* GMM_STDCALL GmmResGetPrivateData(GMM_RESOURCE_INFO *pGmmResource); uint32_t GMM_STDCALL GmmResGetQPitch(GMM_RESOURCE_INFO *pGmmResource); uint32_t GMM_STDCALL GmmResGetQPitchPlanar(GMM_RESOURCE_INFO *pGmmResource, GMM_YUV_PLANE Plane); GMM_GFX_SIZE_T GMM_STDCALL GmmResGetQPitchInBytes(GMM_RESOURCE_INFO *pGmmResource); uint32_t GMM_STDCALL GmmResGetRenderAuxPitchTiles(GMM_RESOURCE_INFO *pGmmResource); uint32_t GMM_STDCALL GmmResGetRenderPitch(GMM_RESOURCE_INFO *pGmmResource); uint32_t GMM_STDCALL GmmResGetRenderPitchIn64KBTiles(GMM_RESOURCE_INFO *pGmmResource); uint32_t GMM_STDCALL GmmResGetRenderPitchTiles(GMM_RESOURCE_INFO *pGmmResource); GMM_RESOURCE_FORMAT GMM_STDCALL GmmResGetResourceFormat(GMM_RESOURCE_INFO *pGmmResource); GMM_RESOURCE_TYPE GMM_STDCALL GmmResGetResourceType(GMM_RESOURCE_INFO *pGmmResource); uint32_t GMM_STDCALL GmmResGetRotateInfo(GMM_RESOURCE_INFO *pGmmResource); GMM_MSAA_SAMPLE_PATTERN GMM_STDCALL GmmResGetSamplePattern(GMM_RESOURCE_INFO *pGmmResource); uint32_t GMM_STDCALL GmmResGetSizeOfStruct(void); GMM_SURFACESTATE_FORMAT GMM_STDCALL GmmResGetSurfaceStateFormat(GMM_RESOURCE_INFO *pGmmResource); GMM_SURFACESTATE_FORMAT GMM_STDCALL GmmGetSurfaceStateFormat(GMM_RESOURCE_FORMAT Format,GMM_LIB_CONTEXT* pGmmLibContext); uint32_t GMM_STDCALL GmmResGetSurfaceStateHAlign(GMM_RESOURCE_INFO *pGmmResource); uint32_t GMM_STDCALL GmmResGetSurfaceStateVAlign(GMM_RESOURCE_INFO *pGmmResource); uint32_t GMM_STDCALL GmmResGetSurfaceStateTiledResourceMode(GMM_RESOURCE_INFO *pGmmResource); void* GMM_STDCALL GmmResGetSystemMemPointer(GMM_RESOURCE_INFO *pGmmResource, uint8_t IsD3DDdiAllocation); GMM_GFX_SIZE_T GMM_STDCALL GmmResGetSystemMemSize( GMM_RESOURCE_INFO* pRes ); uint32_t GMM_STDCALL GmmResGetTallBufferHeight(GMM_RESOURCE_INFO *pResourceInfo); uint32_t GMM_STDCALL GmmResGetMipHeight(GMM_RESOURCE_INFO *pResourceInfo, uint32_t MipLevel); GMM_GFX_SIZE_T GMM_STDCALL GmmResGetMipWidth(GMM_RESOURCE_INFO *pResourceInfo, uint32_t MipLevel); uint32_t GMM_STDCALL GmmResGetMipDepth(GMM_RESOURCE_INFO *pResourceInfo, uint32_t MipLevel); uint8_t GMM_STDCALL GmmResGetCornerTexelMode(GMM_RESOURCE_INFO *pGmmResource); GMM_TEXTURE_LAYOUT GMM_STDCALL GmmResGetTextureLayout(GMM_RESOURCE_INFO *pGmmResource); GMM_TILE_TYPE GMM_STDCALL GmmResGetTileType(GMM_RESOURCE_INFO *pGmmResource); uint32_t GMM_STDCALL GmmResGetVAlign(GMM_RESOURCE_INFO *pGmmResource); uint8_t GMM_STDCALL GmmResIsArraySpacingSingleLod(GMM_RESOURCE_INFO *pGmmResource); uint8_t GMM_STDCALL GmmResIsASTC(GMM_RESOURCE_INFO *pGmmResource); uint8_t GMM_STDCALL GmmResIsLockDiscardCompatible(GMM_RESOURCE_INFO *pGmmResource); uint8_t GMM_STDCALL GmmResIsMediaMemoryCompressed(GMM_RESOURCE_INFO *pGmmResource, uint32_t ArrayIndex); uint8_t GMM_STDCALL GmmResIsMsaaFormatDepthStencil(GMM_RESOURCE_INFO *pGmmResource); uint8_t GMM_STDCALL GmmResIsSvm(GMM_RESOURCE_INFO *pGmmResource); void GMM_STDCALL GmmResSetMmcMode(GMM_RESOURCE_INFO *pGmmResource, GMM_RESOURCE_MMC_INFO Mode, uint32_t ArrayIndex); void GMM_STDCALL GmmResSetMmcHint(GMM_RESOURCE_INFO *pGmmResource, GMM_RESOURCE_MMC_HINT Hint, uint32_t ArrayIndex); GMM_RESOURCE_MMC_HINT GMM_STDCALL GmmResGetMmcHint(GMM_RESOURCE_INFO *pGmmResource, uint32_t ArrayIndex); uint8_t GMM_STDCALL GmmResIsColorSeparation(GMM_RESOURCE_INFO *pGmmResource); uint32_t GMM_STDCALL GmmResTranslateColorSeparationX(GMM_RESOURCE_INFO *pGmmResource, uint32_t x); uint32_t GMM_STDCALL GmmResGetColorSeparationArraySize(GMM_RESOURCE_INFO *pGmmResource); uint32_t GMM_STDCALL GmmResGetColorSeparationPhysicalWidth(GMM_RESOURCE_INFO *pGmmResource); uint8_t GMM_STDCALL GmmResGetSetHardwareProtection(GMM_RESOURCE_INFO *pGmmResource, uint8_t GetIsEncrypted, uint8_t SetIsEncrypted); uint32_t GMM_STDCALL GmmResGetMaxGpuVirtualAddressBits(GMM_RESOURCE_INFO *pGmmResource, GMM_LIB_CONTEXT* pGmmLibContext); uint8_t GMM_STDCALL GmmIsSurfaceFaultable(GMM_RESOURCE_INFO *pGmmResource); uint32_t GMM_STDCALL GmmResGetMaximumRenamingListLength(GMM_RESOURCE_INFO* pGmmResource); GMM_GFX_SIZE_T GMM_STDCALL GmmResGetPlanarGetXOffset(GMM_RESOURCE_INFO *pGmmResource, GMM_YUV_PLANE Plane); GMM_GFX_SIZE_T GMM_STDCALL GmmResGetPlanarGetYOffset(GMM_RESOURCE_INFO *pGmmResource, GMM_YUV_PLANE Plane); GMM_GFX_SIZE_T GMM_STDCALL GmmResGetPlanarAuxOffset(GMM_RESOURCE_INFO *pGmmResource, uint32_t ArrayIndex, GMM_UNIFIED_AUX_TYPE Plane); void GMM_STDCALL GmmResSetLibContext(GMM_RESOURCE_INFO *pGmmResource, void *pLibContext); uint32_t GMM_STDCALL GmmResIsMappedCompressible(GMM_RESOURCE_INFO *pGmmResource); // Remove when client moves to new interface uint32_t GMM_STDCALL GmmResGetRenderSize(GMM_RESOURCE_INFO *pResourceInfo); uint8_t GMM_STDCALL GmmGetCompressionFormat(GMM_RESOURCE_FORMAT Format, GMM_LIB_CONTEXT *pGmmLibContext); //===================================================================================================== //forward declarations struct GMM_TEXTURE_INFO_REC; // Hack to define and undefine typedef name to avoid redefinition of the // typedef. Part 1. // typedef struct GMM_TEXTURE_INFO_REC GMM_TEXTURE_INFO; #define GMM_TEXTURE_INFO struct GMM_TEXTURE_INFO_REC // TODO: Allows UMD to override some parameters. Remove these functions once GMM comprehends UMD usage model and // can support them properly. void GMM_STDCALL GmmResOverrideAllocationSize(GMM_RESOURCE_INFO *pGmmResource, GMM_GFX_SIZE_T Size); void GMM_STDCALL GmmResOverrideAllocationPitch(GMM_RESOURCE_INFO *pGmmResource, GMM_GFX_SIZE_T Pitch); void GMM_STDCALL GmmResOverrideAuxAllocationPitch(GMM_RESOURCE_INFO *pGmmResource, GMM_GFX_SIZE_T Pitch); void GMM_STDCALL GmmResOverrideAllocationFlags(GMM_RESOURCE_INFO *pGmmResource, GMM_RESOURCE_FLAG *pFlags); void GMM_STDCALL GmmResOverrideAllocationHAlign(GMM_RESOURCE_INFO *pGmmResource, uint32_t HAlign); void GMM_STDCALL GmmResOverrideAllocationBaseAlignment(GMM_RESOURCE_INFO *pGmmResource, uint32_t Alignment); void GMM_STDCALL GmmResOverrideAllocationBaseWidth(GMM_RESOURCE_INFO *pGmmResource, GMM_GFX_SIZE_T BaseWidth); void GMM_STDCALL GmmResOverrideAllocationBaseHeight(GMM_RESOURCE_INFO *pGmmResource, uint32_t BaseHeight); void GMM_STDCALL GmmResOverrideAllocationDepth(GMM_RESOURCE_INFO *pGmmResource, uint32_t Depth); void GMM_STDCALL GmmResOverrideResourceTiling(GMM_RESOURCE_INFO *pGmmResource, uint32_t TileMode); void GMM_STDCALL GmmResOverrideAuxResourceTiling(GMM_RESOURCE_INFO *pGmmResource, uint32_t TileMode); void GMM_STDCALL GmmResOverrideAllocationTextureInfo(GMM_RESOURCE_INFO *pGmmResource, GMM_CLIENT Client, const GMM_TEXTURE_INFO *pTexInfo); void GMM_STDCALL GmmResOverrideAllocationFormat(GMM_RESOURCE_INFO *pGmmResource, GMM_RESOURCE_FORMAT Format); void GMM_STDCALL GmmResOverrideSurfaceType(GMM_RESOURCE_INFO *pGmmResource, GMM_RESOURCE_TYPE ResourceType); void GMM_STDCALL GmmResOverrideSvmGfxAddress(GMM_RESOURCE_INFO *pGmmResource, GMM_GFX_ADDRESS SvmGfxAddress); void GMM_STDCALL GmmResOverrideAllocationArraySize(GMM_RESOURCE_INFO *pGmmResource, uint32_t ArraySize); void GMM_STDCALL GmmResOverrideAllocationMaxLod(GMM_RESOURCE_INFO *pGmmResource, uint32_t MaxLod); ////////////////////////////////////////////////////////////////////////////////////// // GmmCachePolicy.c ////////////////////////////////////////////////////////////////////////////////////// MEMORY_OBJECT_CONTROL_STATE GMM_STDCALL GmmCachePolicyGetMemoryObject(void *pLibContext, GMM_RESOURCE_INFO *pResInfo, GMM_RESOURCE_USAGE_TYPE Usage); GMM_PTE_CACHE_CONTROL_BITS GMM_STDCALL GmmCachePolicyGetPteType(void *pLibContext, GMM_RESOURCE_USAGE_TYPE Usage); GMM_RESOURCE_USAGE_TYPE GMM_STDCALL GmmCachePolicyGetResourceUsage(GMM_RESOURCE_INFO *pResInfo ); MEMORY_OBJECT_CONTROL_STATE GMM_STDCALL GmmCachePolicyGetOriginalMemoryObject(void *pLibContext, GMM_RESOURCE_INFO *pResInfo); uint8_t GMM_STDCALL GmmCachePolicyIsUsagePTECached(void *pLibContext, GMM_RESOURCE_USAGE_TYPE Usage); uint8_t GMM_STDCALL GmmGetSurfaceStateL1CachePolicy(void *pLibContext, GMM_RESOURCE_USAGE_TYPE Usage); void GMM_STDCALL GmmCachePolicyOverrideResourceUsage(GMM_RESOURCE_INFO *pResInfo, GMM_RESOURCE_USAGE_TYPE Usage); uint32_t GMM_STDCALL GmmCachePolicyGetMaxMocsIndex(void *pLibContext); uint32_t GMM_STDCALL GmmCachePolicyGetMaxL1HdcMocsIndex(void *pLibContext); uint32_t GMM_STDCALL GmmCachePolicyGetMaxSpecialMocsIndex(void *pLibContext); void GMM_STDCALL GmmResSetPrivateData(GMM_RESOURCE_INFO *pGmmResource, void *pPrivateData); uint32_t GMM_STDCALL GmmCachePolicyGetPATIndex(void *pLibContext, GMM_RESOURCE_USAGE_TYPE Usage, bool *pCompressionEnable, bool IsCpuCacheable); uint8_t GMM_STDCALL GmmGetSurfaceStateL2CachePolicy(void *pLibContext, GMM_RESOURCE_USAGE_TYPE Usage); #if (!defined(__GMM_KMD__) && !defined(GMM_UNIFIED_LIB)) ///////////////////////////////////////////////////////////////////////////////////// /// C wrapper functions for UMD clients Translation layer from OLD GMM APIs to New /// unified GMM Lib APIs ///////////////////////////////////////////////////////////////////////////////////// GMM_STATUS GmmCreateGlobalClientContext(GMM_CLIENT ClientType); void GmmDestroyGlobalClientContext(); GMM_RESOURCE_INFO* GmmResCreateThroughClientCtxt(GMM_RESCREATE_PARAMS *pCreateParams); void GmmResFreeThroughClientCtxt(GMM_RESOURCE_INFO *pRes); GMM_RESOURCE_INFO* GmmResCopyThroughClientCtxt(GMM_RESOURCE_INFO* pSrcRes); void GmmResMemcpyThroughClientCtxt(void *pDst, void *pSrc); #endif // Hack to define and undefine typedef name to avoid redefinition of the // typedef. Part 2. #undef GMM_TEXTURE_INFO // Reset packing alignment to project default #pragma pack(pop) #ifdef __cplusplus } #endif /*__cplusplus*/ gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/inc/External/Common/GmmTextureExt.h000066400000000000000000000222061466655022700265730ustar00rootroot00000000000000/*============================================================================== Copyright(c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ============================================================================*/ #pragma once #ifdef __cplusplus extern "C" { #endif /*__cplusplus*/ // Set packing alignment #pragma pack(push, 8) #define GMM_MAX_MIPMAP 15 #define GMM_MAX_MMC_INDEX 64 //=========================================================================== // typedef: // GMM_PLANAR_OFFSET_INFO // // Description: // This structure stores the offset address of each level //--------------------------------------------------------------------------- typedef struct GMM_PLANAR_OFFSET_INFO_REC { GMM_GFX_SIZE_T ArrayQPitch; GMM_GFX_SIZE_T X[GMM_MAX_PLANE]; GMM_GFX_SIZE_T Y[GMM_MAX_PLANE]; struct { GMM_GFX_SIZE_T Height[GMM_MAX_PLANE]; } UnAligned, Aligned; uint32_t NoOfPlanes; bool IsTileAlignedPlanes; }GMM_PLANAR_OFFSET_INFO; //=========================================================================== // typedef: // GMM_PLANAR_OFFSET_INFO // // Description: // This structure stores the offset address of each level //--------------------------------------------------------------------------- typedef struct GMM_PLANAR_OFFSET_INFO_V2_REC { GMM_GFX_SIZE_T ArrayQPitch; GMM_GFX_SIZE_T X[GMM_MAX_PLANE]; GMM_GFX_SIZE_T Y[GMM_MAX_PLANE]; struct { uint32_t Height[GMM_MAX_PLANE]; } UnAligned, Aligned, Physical; uint32_t NoOfPlanes; bool IsTileAlignedPlanes; bool Is1MBAuxTAlignedPlanes; GMM_GFX_SIZE_T PhysicalPitch; } GMM_PLANAR_OFFSET_INFO_V2; //=========================================================================== // typedef: // GMM_2D_TEXTURE_OFFSET_INFO // // Description: // This structure stores the offset address of each level //--------------------------------------------------------------------------- typedef struct GMM_2D_TEXTURE_OFFSET_INFO_REC { GMM_GFX_SIZE_T ArrayQPitchLock; GMM_GFX_SIZE_T ArrayQPitchRender; GMM_GFX_SIZE_T Offset[GMM_MAX_MIPMAP]; }GMM_2D_TEXTURE_OFFSET_INFO_T; //=========================================================================== // typedef: // GMM_3D_TEXTURE_OFFSET_INFO // // Description: // This structure stores the offset address of each level //--------------------------------------------------------------------------- typedef struct GMM_3D_TEXTURE_OFFSET_INFO_REC { GMM_GFX_SIZE_T Mip0SlicePitch; GMM_GFX_SIZE_T Offset[GMM_MAX_MIPMAP]; }GMM_3D_TEXTURE_OFFSET_INFO_T; //=========================================================================== // typedef: // GMM_OFFSET_INFO // // Description: // This structure stores the offset address of each level //--------------------------------------------------------------------------- typedef struct GMM_OFFSET_INFO_REC { union { GMM_3D_TEXTURE_OFFSET_INFO_T Texture3DOffsetInfo; GMM_2D_TEXTURE_OFFSET_INFO_T Texture2DOffsetInfo; GMM_PLANAR_OFFSET_INFO Plane; GMM_PLANAR_OFFSET_INFO_V2 PlaneXe_LPG; }; }GMM_OFFSET_INFO, GMM_OFFSET_INFO_T; //=========================================================================== // typedef: // GMM_TEXTURE_CALC // // Description: // This struct is used to texture calculator. // Forward Declaration: Defined in GmmGenXXTextureCalc*.h //--------------------------------------------------------------------------- #ifdef __cplusplus namespace GmmLib { class GmmTextureCalc; } typedef GmmLib::GmmTextureCalc GMM_TEXTURE_CALC; #else struct GmmTextureCalc; typedef struct GmmTextureCalc GMM_TEXTURE_CALC; #endif //=========================================================================== // typedef: // GMM_TEXTURE_INFO_REC // // Description: // This structure used to request mipmap offset information //--------------------------------------------------------------------------- typedef struct GMM_TEXTURE_INFO_REC { // Input ---------------------------------- GMM_RESOURCE_TYPE Type; GMM_RESOURCE_FORMAT Format; uint32_t BitsPerPixel; GMM_RESOURCE_FLAG Flags; uint64_t BaseWidth; uint32_t BaseHeight; uint32_t Depth; uint32_t MaxLod; uint32_t ArraySize; uint32_t CpTag; struct{ GMM_RESOURCE_USAGE_TYPE Usage; } CachePolicy; GMM_RESOURCE_MSAA_INFO MSAA; // Output --------------------------------- GMM_RESOURCE_ALIGNMENT Alignment; uint8_t MmcMode[GMM_MAX_MMC_INDEX]; uint8_t MmcHint[GMM_MAX_MMC_INDEX]; GMM_GFX_SIZE_T Pitch; GMM_GFX_SIZE_T OverridePitch; // VirtualPadding GMM_GFX_SIZE_T Size; // For AuxSurf Size = CCS + CC + Padding GMM_GFX_SIZE_T CCSize; // 4kb => 128 bit Float + 32bit Native RT + Padding. Usage : Gpu.IndirectClearColor GMM_GFX_SIZE_T UnpaddedSize; // Unpadded CCS Size for Flags.Gpu.UnifiedAuxSurface only GMM_GFX_SIZE_T SizeReportToOS; // For Non-aligned ESM GMM_OFFSET_INFO OffsetInfo; // (X,Y) offsets to each mipmap/plane GMM_TILE_MODE TileMode; uint32_t CCSModeAlign; // For AUX_CCS, TexAlign.CCSEx index derived from main surface tiling uint32_t LegacyFlags; GMM_S3D_INFO S3d; #if(LHDM) D3DDDIFORMAT MsFormat; #endif struct{ uint32_t Seg1 : 8; uint32_t Evict : 8; } SegmentOverride; // Used for tuning the Vista driver uint32_t MaximumRenamingListLength; #if(_DEBUG || _RELEASE_INTERNAL) PLATFORM Platform; #else PLATFORM __Platform; // Do not use--For size preservation only. #endif struct{ uint8_t IsGmmAllocated; uint8_t IsPageAligned; } ExistingSysMem; }GMM_TEXTURE_INFO; //*************************************************************************** // // GMM_TEXTURE API // //*************************************************************************** #if(defined(__GMM_KMD__)) GMM_STATUS GmmTexAlloc(GMM_LIB_CONTEXT *pGmmLibContext, GMM_TEXTURE_INFO* pTexInfo); GMM_STATUS GmmTexLinearCCS(GMM_LIB_CONTEXT *pGmmLibContext, GMM_TEXTURE_INFO* pTexInfo, GMM_TEXTURE_INFO *pAuxTexInfo); #endif GMM_STATUS GmmTexGetMipMapOffset(GMM_TEXTURE_INFO* pTexInfo, GMM_REQ_OFFSET_INFO* pReqInfo , GMM_LIB_CONTEXT* pGmmLibContext); #define GMM_ISNOT_TILED(TileInfo) ((TileInfo).LogicalSize == 0) #define GMM_IS_TILED(TileInfo) ((TileInfo).LogicalSize > 0) #define GMM_CLEAR_TILEINFO(TileInfo) \ { \ (TileInfo).LogicalSize = 0; \ (TileInfo).LogicalTileHeight = 0; \ (TileInfo).LogicalTileWidth = 0; \ (TileInfo).MaxPitch = 0; \ } #define GMM_IS_4KB_TILE(Flags) ((Flags).Info.TiledY || (Flags).Info.Tile4) #define GMM_IS_64KB_TILE(Flags) (Flags.Info.TiledYs || Flags.Info.Tile64) #define GMM_IS_SUPPORTED_BPP_ON_TILE_64_YF_YS(bpp) ((bpp == 8) || (bpp == 16) || (bpp == 32) || (bpp == 64) || (bpp == 128)) #define GMM_SET_4KB_TILE(Flags, Value,pGmmLibContext) if (pGmmLibContext->GetSkuTable().FtrTileY) ((Flags).Info.TiledY = (Value)); else ((Flags).Info.Tile4 = (Value)) #define GMM_SET_64KB_TILE(Flags, Value,pGmmLibContext) if (pGmmLibContext->GetSkuTable().FtrTileY) ((Flags).Info.TiledYs = (Value)); else ((Flags).Info.Tile64 = (Value)) #define GMM_SET_4KB_TILE_MODE(TileMode,pGmmLibContext) if (pGmmLibContext->GetSkuTable().FtrTileY) (TileMode = LEGACY_TILE_Y); else (TileMode = TILE4) #define GMM_IS_TILEY(pGmmLibContext) (((GmmClientContext*)pClientContext)->GetSkuTable().FtrTileY) // Reset packing alignment to project default #pragma pack(pop) #ifdef __cplusplus } #endif /*__cplusplus*/ gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/inc/External/Common/GmmUtil.h000066400000000000000000000137621466655022700253760ustar00rootroot00000000000000/*============================================================================== Copyright(c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ============================================================================*/ #pragma once //------------------------------------------------------------------------ // Size macros //------------------------------------------------------------------------ #define GMM_BITS(a) (a) #define GMM_BYTES(a) (a) #define GMM_KBYTE(a) ((a) * 1024) #define GMM_MBYTE(a) ((a) * 1024 * 1024) #define GMM_GBYTE(a) (((uint64_t) 1024) * 1024 * 1024 * (a)) #define GMM_TBYTE(a) (((uint64_t) 1024) * 1024 * 1024 * 1024 * (a)) #define GMM_SCANLINES(a) (a) #define GMM_DEPTH(a) (a) #define GMM_PIXELS(a) (a) #define GMM_BYTES_TO_MBYTES(a) ((a) / (1024*1024)) #define GMM_BYTES_TO_KBYTES(a) ((a) / 1024) //------------------------------------------------------------------------ // Bit manipulation macros //------------------------------------------------------------------------ #define __GMM_IS_ALIGN(A, B) (((A) % (B)) == 0) #define __BIT(x) (1UL << (x)) #define __MASKED_BIT(x) (__BIT(x) | (__BIT(x) << 16)) #define __BIT64(x) ((uint64_t)1 << (x)) #define __GMM_SET_BIT(A, b) (A |= __BIT(b)) #define __GMM_CLEAR_BIT(A, b) (A &= ~__BIT(b)) #define __GMM_SET_BIT64(A, b) (A |= __BIT64(b)) #define __GMM_CLEAR_BIT64(A, b) (A &= ~__BIT64(b)) #define __GMM_IS_BIT_SET(A, b) (A & __BIT(b)) #define __GMM_IS_BIT_CLEAR(A, b) ((A & __BIT(b)) == 0) #define __SET_VALUE(editDst, editMask, editShift, editValue) \ (editDst) = (((editDst) & ~(editMask)) |\ (((editValue) << (editShift)) & (editMask))) #define GMM_UNREFERENCED_PARAMETER(param) ((void)(param)) #define GMM_UNREFERENCED_LOCAL_VARIABLE(debug_var) ((void)(debug_var)) //------------------------------------------------------------------------ // Escape macros //------------------------------------------------------------------------ #define GMM_ESCAPE_D3D_SET_DEV_CTX(Escape, AdapterHandle, DeviceHandle) \ { \ Escape.hContext = NULL; \ Escape.hDevice = DeviceHandle; \ } #define GMM_CALL_D3D_ESCAPE(pfnEscape, hAdapter, Escape) (pfnEscape(hAdapter, &Escape)) #define GMM_ESCAPE_OGL_SET_DEV_CTX(Escape, AdapterHandle, DeviceHandle) \ { \ Escape.hAdapter = (D3DKMT_HANDLE)(uintptr_t)AdapterHandle; \ Escape.hContext = (D3DKMT_HANDLE)(uintptr_t)NULL; \ Escape.hDevice = (D3DKMT_HANDLE)(uintptr_t)DeviceHandle; \ Escape.Type = D3DKMT_ESCAPE_DRIVERPRIVATE; \ } #define GMM_CALL_OGL_ESCAPE(pfnEscape, hAdapter, Escape) (pfnEscape(&Escape)) #define __GMM_RANGE_IN_GMADR(RangeBase, RangeSize,pGmmLibContext) \ (((RangeBase) >= GmmGetGttContext(pGmmLibContext)->GfxAddrRange.Global.Base) && \ (((RangeBase) + (RangeSize)) <= \ (GmmGetGttContext(pGmmLibContext)->GfxAddrRange.Global.Base + \ GmmGetGttContext(pGmmLibContext)->GlobalGfxApertureSize))) #define __GMM_RANGE_IN_GLOBAL_GTT_SPACE(RangeBase, RangeSize,pGmmLibContext) \ (((RangeBase) >= GmmGetGttContext(pGmmLibContext)->GfxAddrRange.Global.Base) && \ (((RangeBase) + (RangeSize)) <= \ (GmmGetGttContext(pGmmLibContext)->GfxAddrRange.Global.Base + \ GmmGetGttContext(pGmmLibContext)->GfxAddrRange.Global.Size))) #define __GMM_RANGE_IN_PPGTT_SPACE(RangeBase, RangeSize,pGmmLibContext) \ (((RangeBase) >= GmmGetGttContext(pGmmLibContext)->GfxAddrRange.PP.Base) && \ (((RangeBase) + (RangeSize)) <= \ (GmmGetGttContext(pGmmLibContext)->GfxAddrRange.PP.Base + \ GmmGetGttContext(pGmmLibContext)->GfxAddrRange.PP.Size))) #define GMM_INLINE __inline #if(defined(__GMM_KMD__)) #define GMM_OVERRIDE_SIZE_64KB_ALLOC(pGmmLibContext) if(GmmGetSkuTable(pGmmLibContext)->FtrPpgtt64KBWalkOptimization){ return (this->GetSizeAllocation());} #else #define GMM_OVERRIDE_SIZE_64KB_ALLOC(pGmmLibContext) if(((GmmClientContext*)pClientContext)->GetSkuTable().FtrPpgtt64KBWalkOptimization){ return (this->GetSizeAllocation());} #endif gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/inc/External/Linux/000077500000000000000000000000001466655022700235055ustar00rootroot00000000000000gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/inc/External/Linux/GmmResourceInfoLin.h000066400000000000000000000043301466655022700273650ustar00rootroot00000000000000/*============================================================================== Copyright(c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ============================================================================*/ #pragma once #ifdef __cplusplus #include "../Common/GmmResourceInfoCommon.h" ///////////////////////////////////////////////////////////////////////////////////// /// @file GmmResourceInfoLin.h /// @brief This file contains the functions and members of GmmResourceInfo that is /// Linux specific. /// ///////////////////////////////////////////////////////////////////////////////////// namespace GmmLib { class GMM_LIB_API NON_PAGED_SECTION GmmResourceInfoLin: public GmmResourceInfoCommon { public: /* Constructors */ GmmResourceInfoLin() { } #ifndef __GMM_KMD__ GmmResourceInfoLin(GmmClientContext *pClientContextIn) : GmmResourceInfoCommon(pClientContextIn) { } #endif virtual ~GmmResourceInfoLin() { } }; typedef GmmResourceInfoLin GmmResourceInfo; } // namespace GmmLib #else typedef struct GmmResourceInfo GmmResourceInfo; #endif // #ifdef __cplusplus gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/inc/External/Linux/GmmResourceInfoLinExt.h000066400000000000000000000067551466655022700300630ustar00rootroot00000000000000/*============================================================================== Copyright(c) 2019 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ============================================================================*/ #pragma once #ifdef __linux__ #ifdef __cplusplus extern "C" { #endif /*__cplusplus*/ typedef struct { int(*pfnAllocate)(void *bufMgr, size_t size, size_t alignment, void **bo, void **cpuAddr, uint64_t *gpuAddr); void(*pfnDeallocate)(void *bo); void(*pfnWaitFromCpu)(void *bo);; } GMM_DEVICE_CB_PTRS; typedef struct _GMM_DEVICE_CALLBACKS_INT { void *pBufMgr; GMM_DEVICE_CB_PTRS DevCbPtrs_; } GMM_DEVICE_CALLBACKS_INT; // Add the definition to compatible. typedef struct GMM_TRANSLATIONTABLE_CALLBACKS_REC { int (*pfPrologTranslationTable)(void *pDeviceHandle); int (*pfWriteL1Entries)(void *pDeviceHandle, const uint32_t NumEntries, GMM_GFX_ADDRESS GfxAddress, uint32_t *Data); int (*pfWriteL2L3Entry)(void *pDeviceHandle, GMM_GFX_ADDRESS GfxAddress, uint64_t Data); int (*pfWriteFenceID)(void *pDeviceHandle, GMM_GFX_ADDRESS GfxAddress, uint64_t Data); int (*pfEpilogTranslationTable)(void *pDeviceHandle, uint8_t ForceFlush); int (*pfCopyL1Entry)(void *pDeviceHandle, GMM_GFX_ADDRESS DstGfxAddress, GMM_GFX_ADDRESS SrcGfxAddress); int (*pfWriteL3Adr)(void *pDeviceHandle, GMM_GFX_ADDRESS L3GfxAddress, uint64_t RegOffset); } GMM_TRANSLATIONTABLE_CALLBACKS; typedef struct _GMM_DEVICE_CALLBACKS { void *pBufferMgr; int FuncDevice; int(*pfnAllocate)(void *bufMgr, size_t size, size_t alignment, void **bo, void **cpuAddr, uint64_t *gpuAddr); void(*pfnDeallocate)(void *bo); void(*pfnWaitFromCpu)(void *bo);; } GMM_DEVICE_CALLBACKS; // This definition is only for code sharing. typedef struct GMM_UMD_SYNCCONTEXT_REC { void *pCommandQueueHandle; // pointer to command queue handle void *pUpdateGpuVaInfo; HANDLE BBFenceObj; // BatchBuffer Last Fence, for CPU to wait on before destroying TT pages uint64_t BBLastFence; // BatchBuffer Last Fence for TT } GMM_UMD_SYNCCONTEXT; #ifdef __cplusplus } #endif /*__cplusplus*/ #endif /*__linux__*/ gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/inc/GmmLib.h000066400000000000000000000045521466655022700221520ustar00rootroot00000000000000/*============================================================================== Copyright(c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ============================================================================*/ #pragma once #ifdef __cplusplus extern "C" { #endif /*__cplusplus*/ #ifndef _WIN32 #include #endif #if defined(LHDM) && !defined(__GMM_KMD__) && defined(_WIN32) #include #include #include #include #else // Since we are compiled not for WinOS, we don't want to include later any Visual Studio specific files. #define VER_H #endif // LHDM #include "../../inc/umKmInc/sharedata.h" // GMM Lib Client Exports #include "External/Common/GmmCommonExt.h" #include "External/Common/GmmUtil.h" #include "External/Common/GmmResourceFlags.h" #include "External/Common/GmmCachePolicy.h" #include "External/Common/GmmCachePolicyExt.h" #include "External/Common/GmmResourceInfoExt.h" #include "External/Common/GmmPlatformExt.h" #include "External/Common/GmmTextureExt.h" #include "External/Common/GmmInfoExt.h" #include "External/Common/GmmResourceInfo.h" #include "External/Common/GmmInfo.h" #include "External/Common/GmmClientContext.h" #include "External/Common/GmmPageTableMgr.h" #include "External/Common/GmmLibDll.h" #include "External/Common/GmmLibDllName.h" #ifdef __cplusplus } #endif /*__cplusplus*/ gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/inc/Internal/000077500000000000000000000000001466655022700224005ustar00rootroot00000000000000gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/inc/Internal/Common/000077500000000000000000000000001466655022700236305ustar00rootroot00000000000000gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/inc/Internal/Common/GmmCommonInt.h000066400000000000000000000035571466655022700263570ustar00rootroot00000000000000/*============================================================================== Copyright(c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ============================================================================*/ #pragma once // Helper Macros for CoherentPATIndex Value handling. #define CONCATENATE_COHERENT_PATINDEX(a, b) (((a & __BIT(0)) << 5) | b) // 'a' ->higher order bits 6th bit [5] MSB, 'b' -> Lower order 5 bits [4:0] #define GET_COHERENT_PATINDEX_VALUE(pGmmLibContext, usage) (CONCATENATE_COHERENT_PATINDEX(pGmmLibContext->GetCachePolicyElement(usage).CoherentPATIndexHigherBit, \ pGmmLibContext->GetCachePolicyElement(usage).CoherentPATIndex)) #define GET_COHERENT_PATINDEX_LOWER_BITS(value) (value & (~(~0 << 5))) #define GET_COHERENT_PATINDEX_HIGHER_BIT(value) ((value >> 5) & __BIT(0)) gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/inc/Internal/Common/GmmLibInc.h000066400000000000000000000063411466655022700256060ustar00rootroot00000000000000/*============================================================================== Copyright(c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ============================================================================*/ #pragma once #ifndef _WIN32 #include #endif #include "External/Common/GmmInternal.h" #include "External/Common/GmmConst.h" #include "External/Common/GmmUtil.h" #include "External/Common/GmmHw.h" #include "External/Common/GmmCommonExt.h" #include "External/Common/GmmPlatformExt.h" #include "External/Common/GmmCachePolicy.h" #include "External/Common/CachePolicy/GmmCachePolicyGen8.h" #include "External/Common/CachePolicy/GmmCachePolicyGen9.h" #include "External/Common/CachePolicy/GmmCachePolicyGen10.h" #include "External/Common/CachePolicy/GmmCachePolicyGen11.h" #include "External/Common/CachePolicy/GmmCachePolicyGen12.h" #include "External/Common/CachePolicy/GmmCachePolicyXe_LPG.h" #include "External/Common/CachePolicy/GmmCachePolicyXe2_LPG.h" #include "External/Common/CachePolicy/GmmCachePolicyGen12dGPU.h" #include "External/Common/GmmResourceInfoExt.h" #include "../Platform/GmmPlatforms.h" #include "Platform/GmmGen8Platform.h" #include "Platform/GmmGen9Platform.h" #include "Platform/GmmGen10Platform.h" #include "Platform/GmmGen11Platform.h" #include "Platform/GmmGen12Platform.h" #include "External/Common/GmmTextureExt.h" #include "../Texture/GmmTexture.h" #include "Texture/GmmTextureCalc.h" #include "Texture/GmmGen7TextureCalc.h" #include "Texture/GmmGen8TextureCalc.h" #include "Texture/GmmGen9TextureCalc.h" #include "Texture/GmmGen10TextureCalc.h" #include "Texture/GmmGen11TextureCalc.h" #include "Texture/GmmGen12TextureCalc.h" #include "Texture/GmmXe_LPGTextureCalc.h" #include "External/Common/GmmResourceInfo.h" #include "External/Common/GmmInfoExt.h" #include "External/Common/GmmInfo.h" #include "../Utility/GmmUtility.h" #include "External/Common/GmmPageTableMgr.h" #include "Internal/Common/GmmCommonInt.h" #include "External/Common/GmmDebug.h" // Unified Definitions of GMM_ASSERT and GMM_DEBUG Macros #ifndef DXGKDDI_INTERFACE_VERSION_WDDM1_3 //WinBlue DDK definitions #define D3DKMT_CROSS_ADAPTER_RESOURCE_PITCH_ALIGNMENT 128 #define D3DKMT_CROSS_ADAPTER_RESOURCE_HEIGHT_ALIGNMENT 4 #endif gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/inc/Internal/Common/GmmLogger.h000066400000000000000000000064311466655022700256650ustar00rootroot00000000000000/*============================================================================== Copyright(c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ============================================================================*/ #pragma once #ifdef __cplusplus #if GMM_LOG_AVAILABLE #include "spdlog/spdlog.h" ///////////////////////////////////////////////////////////////////////////////////// /// @file Logger.h /// @brief This file contains the functions that are useful for logging in GmmLib ///////////////////////////////////////////////////////////////////////////////////// namespace GmmLib { class Logger { private: /// This enum determines where the log goes enum GmmLogMethod { ToOSLog, ///< Log is sent to OS logging infrastructure (Debugger on Windows) ToFile, ///< Log is written to file } LogMethod; ///< Indicates which Logging method is preferred spdlog::level::level_enum LogLevel; ///< Indicates the max log level to print private: Logger(); ~Logger(); bool GmmLogInit(); public: std::shared_ptr SpdLogger; ///< spdlog instance ///////////////////////////////////////////////////////////////////////////////////// /// Creates a Logger singlton per process /// /// @remark /// If there are multiple modules loaded in one process, this singleton will be /// per module. For example: D3D10 and D3D12 are all used in process A. Both D3D10 /// and D3D12 are built with GmmLib.lib. They are considered to be two modules and /// each has a Logger instance (singleton). /// /// @return Logger instance ///////////////////////////////////////////////////////////////////////////////////// static Logger& CreateGmmLogSingleton() { static Logger GmmLoggerPerProc; return GmmLoggerPerProc; } }; } // namespace GmmLib // Macros extern GmmLib::Logger& GmmLoggerPerProc; #endif #endifgmmlib-intel-gmmlib-22.5.2/Source/GmmLib/inc/Internal/Common/GmmTextureCalc.h000066400000000000000000000143231466655022700266700ustar00rootroot00000000000000/*============================================================================== Copyright(c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ============================================================================*/ #pragma once #ifdef __cplusplus #include "GmmMemAllocator.hpp" #include "GmmLibInc.h" ///////////////////////////////////////////////////////////////////////////////////// /// @file GmmTextureCalc.h /// @brief This file contains the common functions and members for texture calculations /// on all GENs/Platforms ///////////////////////////////////////////////////////////////////////////////////// namespace GmmLib { ///////////////////////////////////////////////////////////////////////// /// Contains texture calc functions and members that are common across all platform /// implementation. This class is inherited by gen specific class so /// so clients shouldn't have to ever interact with this class directly. ///////////////////////////////////////////////////////////////////////// class NON_PAGED_SECTION GmmTextureCalc : public GmmMemAllocator { // GMMLIB2_TODO: // 1) Change it to protected when all functions are part of the class // 2) Mode Gen specific implementation in derived class later. private: protected: /* Function prototypes */ public: /* Constructors */ // "Creates GmmTextureCalc object based on platform ID" static GmmTextureCalc* Create(PLATFORM Platform) { return new GmmTextureCalc(); } GmmTextureCalc() { } ~GmmTextureCalc() { } /* Function prototypes */ //GmmTextureAlloc.cpp GMM_STATUS AllocateTexture(GMM_TEXTURE_INFO *pTexInfo); GMM_STATUS __GmmTexFillBlockMem( GMM_TEXTURE_INFO *pTexInfo, __GMM_BUFFER_TYPE *pRestrictions); GMM_STATUS GmmTexFillPitchAndSize(GMM_TEXTURE_INFO *pTexInfo, GMM_GFX_SIZE_T WidthBytesPhysical, uint32_t Height, __GMM_BUFFER_TYPE *pBufferType); void GmmTexGetRestrictions( GMM_TEXTURE_INFO* pTexInfo, __GMM_BUFFER_TYPE* pBuff); GMM_STATUS GMM_STDCALL __GmmTexFillPlanar( GMM_TEXTURE_INFO *pTexInfo, __GMM_BUFFER_TYPE *pRestrictions); void __GmmTexFillPlanar_SetTilingBasedOnRequiredAlignment( GMM_TEXTURE_INFO *pTexInfo, uint32_t YHeight, bool YHeightAlignmentNeeded, uint32_t VHeight, bool VHeightAlignmentNeeded); bool __GmmTexValidateTexInfo( GMM_TEXTURE_INFO *pTexInfo, __GMM_BUFFER_TYPE *pRestrictions); void __GmmSetTileMode( GMM_TEXTURE_INFO* pTexInfo); GMM_STATUS __GmmTexSpecialCasePreProcessing( GMM_TEXTURE_INFO* pTexInfo); //GmmTexture.cpp uint32_t __GmmExpandHeight( uint32_t Height, uint32_t UnitAlignment, uint32_t NumSamples); uint32_t __GmmExpandWidth( uint32_t Width, uint32_t UnitAlignment, uint32_t NumSamples); void __GmmGetElementDimensions( GMM_RESOURCE_FORMAT Format, uint32_t *pWidth, uint32_t *pHeight, uint32_t *pDepth); void __GmmFillPlanarOffsetAddress( GMM_TEXTURE_INFO *pTexInfo); void __GmmFindMipTailStartLod( GMM_TEXTURE_INFO *pTexInfo); // Virtual functions // TODO GmmLib2.0 Create derived class of TextureCalc and add virtual functions. /*virtual GMM_STATUS GMM_STDCALL __GmmTexFill1D( GMM_TEXTURE_INFO *pTexInfo, __GMM_BUFFER_TYPE *pRestrictions) = 0; virtual GMM_STATUS GMM_STDCALL __GmmTexFill2D( GMM_TEXTURE_INFO *pTexInfo, __GMM_BUFFER_TYPE *pRestrictions) = 0; virtual GMM_STATUS GMM_STDCALL __GmmTexFill3D( GMM_TEXTURE_INFO *pTexInfo, __GMM_BUFFER_TYPE *pRestrictions) = 0; virtual GMM_STATUS GMM_STDCALL __GmmTexFillCube( GMM_TEXTURE_INFO *pTexInfo, __GMM_BUFFER_TYPE *pRestrictions) = 0;*/ /* inline functions */ }; } #endif // #ifdef __cplusplusgmmlib-intel-gmmlib-22.5.2/Source/GmmLib/inc/Internal/Common/Platform/000077500000000000000000000000001466655022700254145ustar00rootroot00000000000000gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/inc/Internal/Common/Platform/GmmGen10Platform.h000066400000000000000000000027111466655022700306060ustar00rootroot00000000000000/*============================================================================== Copyright(c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ============================================================================*/ #pragma once #ifdef __cplusplus namespace GmmLib { class NON_PAGED_SECTION PlatformInfoGen10 : public PlatformInfo { public: PlatformInfoGen10(PLATFORM &Platform, Context *pGmmLibContext); ~PlatformInfoGen10(){}; }; } #endif gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/inc/Internal/Common/Platform/GmmGen11Platform.h000077500000000000000000000040261466655022700306130ustar00rootroot00000000000000/*============================================================================== Copyright(c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ============================================================================*/ #pragma once #include "GmmGen10Platform.h" #ifdef __cplusplus namespace GmmLib { class NON_PAGED_SECTION PlatformInfoGen11 : public PlatformInfoGen10 { public: PlatformInfoGen11(PLATFORM &Platform, Context *pGmmLibContext); ~PlatformInfoGen11() {}; virtual uint8_t ValidateMMC(GMM_TEXTURE_INFO &Surf); virtual uint8_t ValidateUnifiedAuxSurface(GMM_TEXTURE_INFO &Surf); virtual uint8_t CheckFmtDisplayDecompressible(GMM_TEXTURE_INFO &Surf, bool IsSupportedRGB64_16_16_16_16, bool IsSupportedRGB32_8_8_8_8, bool IsSupportedRGB32_2_10_10_10, bool IsSupportedMediaFormats); }; } #endif gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/inc/Internal/Common/Platform/GmmGen12Platform.h000066400000000000000000000113531466655022700306120ustar00rootroot00000000000000/*============================================================================== Copyright(c) 2019 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ============================================================================*/ #pragma once #include "GmmGen11Platform.h" typedef struct __CCS_UNIT { ALIGNMENT Align; struct { //represents downscale factor if msb = 0, // upscale factor if msb = 1, //factor value is absolute (+ve) int32_t Width; int32_t Height; uint32_t Depth; //Depth slices or Samples sharing CCS$line } Downscale; } CCS_UNIT; //Gen12 CCS supported on Yf/Ys 2D/MSAA/3D tiling #define CCS_MODES (GMM_TILE_MODES - TILE_YF_2D_8bpe) #define CCS_MODE(x) (x >= TILE_YF_2D_8bpe) ? (x - TILE_YF_2D_8bpe) : CCS_MODES typedef enum _FC_TileType { FC_TILE_Y, FC_TILE_YF, FC_TILE_YS, FC_TILE_4, FC_TILE_64, FC_TILE_64_3D, //max equals last supported plus one FC_TILE_MAX } FC_TILE_TYPE; #define FCTilingType(x) (((x) == LEGACY_TILE_Y) ? (FC_TILE_Y) : \ (((x) == TILE4) ? (FC_TILE_4) : \ (((x) >= TILE_YF_2D_8bpe && (x) <= TILE_YF_2D_128bpe) ? (FC_TILE_YF) : \ (((x) >= TILE_YS_2D_8bpe && (x) <= TILE_YS_2D_128bpe) ? (FC_TILE_YS) : \ (((x) >= TILE__64_2D_8bpe && (x) <= TILE__64_2D_128bpe) ? (FC_TILE_64) : \ (((x) >= TILE__64_3D_8bpe && (x) <= TILE__64_3D_128bpe) ? (FC_TILE_64_3D) : \ (FC_TILE_MAX))))))) #define FCMaxBppModes 5 #define FCMaxModes FC_TILE_MAX *FCMaxBppModes #define FCBppMode(bpp) __GmmLog2(bpp) - 3 #define FCMode(TileMode, bpp) (FCTilingType(TileMode) < FC_TILE_MAX) ? (FCTilingType(TileMode) * FCMaxBppModes + FCBppMode(bpp)) : FCMaxModes //=========================================================================== // typedef: // GMM_TEXTURE_ALIGN_EX // // Description: // The following struct extends the texture mip map unit alignment // required for each map format. The alignment values are platform // dependent. // //--------------------------------------------------------------------------- typedef struct GMM_TEXTURE_ALIGN_EX_REC { CCS_UNIT CCSEx[CCS_MODES]; }GMM_TEXTURE_ALIGN_EX; #ifdef __cplusplus namespace GmmLib { class NON_PAGED_SECTION PlatformInfoGen12 : public PlatformInfoGen11 { protected: GMM_TEXTURE_ALIGN_EX TexAlignEx; CCS_UNIT FCTileMode[FCMaxModes]; public: PlatformInfoGen12(PLATFORM &Platform, Context *pGmmLibContext); ~PlatformInfoGen12(){}; virtual GMM_TEXTURE_ALIGN_EX GetExTextureAlign() { return TexAlignEx; } virtual void ApplyExtendedTexAlign(uint32_t CCSMode, ALIGNMENT& UnitAlign); virtual CCS_UNIT* GetFCRectAlign() { return FCTileMode; } virtual void SetCCSFlag(GMM_RESOURCE_FLAG &Flags); virtual uint8_t ValidateMMC(GMM_TEXTURE_INFO &Surf); virtual uint8_t ValidateCCS(GMM_TEXTURE_INFO &Surf); virtual uint8_t ValidateUnifiedAuxSurface(GMM_TEXTURE_INFO &Surf); virtual uint8_t CheckFmtDisplayDecompressible(GMM_TEXTURE_INFO &Surf, bool IsSupportedRGB64_16_16_16_16, bool IsSupportedRGB32_8_8_8_8, bool IsSupportedRGB32_2_10_10_10, bool IsSupportedMediaFormats); virtual uint8_t OverrideCompressionFormat(GMM_RESOURCE_FORMAT Format, uint8_t IsMC); }; } #endif gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/inc/Internal/Common/Platform/GmmGen8Platform.h000066400000000000000000000026771466655022700305500ustar00rootroot00000000000000/*============================================================================== Copyright(c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ============================================================================*/ #pragma once #ifdef __cplusplus namespace GmmLib { class NON_PAGED_SECTION PlatformInfoGen8 : public PlatformInfo { public: PlatformInfoGen8(PLATFORM &Platform, Context *pGmmLibContext); ~PlatformInfoGen8(){}; }; } #endif gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/inc/Internal/Common/Platform/GmmGen9Platform.h000066400000000000000000000027061466655022700305420ustar00rootroot00000000000000/*============================================================================== Copyright(c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ============================================================================*/ #pragma once #ifdef __cplusplus namespace GmmLib { class NON_PAGED_SECTION PlatformInfoGen9 : public PlatformInfo { public: PlatformInfoGen9(PLATFORM &Platform, Context *pGmmLibContext); ~PlatformInfoGen9(){}; }; } #endif gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/inc/Internal/Common/Texture/000077500000000000000000000000001466655022700252705ustar00rootroot00000000000000gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/inc/Internal/Common/Texture/GmmGen10TextureCalc.h000066400000000000000000000071031466655022700311210ustar00rootroot00000000000000/*============================================================================== Copyright(c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ============================================================================*/ #pragma once #ifdef __cplusplus #include "GmmGen9TextureCalc.h" ///////////////////////////////////////////////////////////////////////////////////// /// @file GmmGen10TextureCalc.h /// @brief This file contains the functions and members definations for texture alloc- /// ation on all Gen10 platforms. ///////////////////////////////////////////////////////////////////////////////////// namespace GmmLib { ///////////////////////////////////////////////////////////////////////// /// Contains texture calc functions and members for Gen10 platforms. /// This class is derived from the base GmmTextureCalc class so clients /// shouldn't have to ever interact with this class directly. ///////////////////////////////////////////////////////////////////////// class NON_PAGED_SECTION GmmGen10TextureCalc : public GmmGen9TextureCalc { private: protected: /* Function prototypes */ virtual uint32_t GetMipTailByteOffset( GMM_TEXTURE_INFO *pTexInfo, uint32_t MipLevel); virtual void GetMipTailGeometryOffset( GMM_TEXTURE_INFO *pTexInfo, uint32_t MipLevel, uint32_t* OffsetX, uint32_t* OffsetY, uint32_t* OffsetZ); virtual uint32_t GetAligned3DBlockHeight( GMM_TEXTURE_INFO* pTexInfo, uint32_t BlockHeight, uint32_t ExpandedArraySize); public: /* Constructors */ GmmGen10TextureCalc(Context *pGmmLibContext) : GmmGen9TextureCalc(pGmmLibContext) { } ~GmmGen10TextureCalc() { } /* Function prototypes */ virtual GMM_STATUS GMM_STDCALL FillTex2D( GMM_TEXTURE_INFO *pTexInfo, __GMM_BUFFER_TYPE *pRestrictions); virtual GMM_STATUS GMM_STDCALL FillTexPlanar( GMM_TEXTURE_INFO *pTexInfo, __GMM_BUFFER_TYPE *pRestrictions); /* inline functions */ }; } #endif // #ifdef __cplusplus gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/inc/Internal/Common/Texture/GmmGen11TextureCalc.h000077500000000000000000000154201466655022700311260ustar00rootroot00000000000000/*============================================================================== Copyright(c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ============================================================================*/ #pragma once #ifdef __cplusplus #include "GmmGen9TextureCalc.h" ///////////////////////////////////////////////////////////////////////////////////// /// @file GmmGen11TextureCalc.h /// @brief This file contains the functions and members definations for texture alloc- /// ation on all Gen11 platforms. ///////////////////////////////////////////////////////////////////////////////////// namespace GmmLib { ///////////////////////////////////////////////////////////////////////// /// Contains texture calc functions and members for Gen11 platforms. /// This class is derived from the base GmmTextureCalc class so clients /// shouldn't have to ever interact with this class directly. ///////////////////////////////////////////////////////////////////////// class NON_PAGED_SECTION GmmGen11TextureCalc : public GmmGen10TextureCalc { private: protected: /* Function prototypes */ virtual uint32_t GetMipTailByteOffset( GMM_TEXTURE_INFO *pTexInfo, uint32_t MipLevel); virtual void GetMipTailGeometryOffset( GMM_TEXTURE_INFO *pTexInfo, uint32_t MipLevel, uint32_t* OffsetX, uint32_t* OffsetY, uint32_t* OffsetZ); virtual GMM_STATUS GMM_STDCALL FillTexPlanar( GMM_TEXTURE_INFO *pTexInfo, __GMM_BUFFER_TYPE *pRestrictions); GMM_STATUS FillLinearCCS( GMM_TEXTURE_INFO *pTexInfo, __GMM_BUFFER_TYPE *pRestrictions); virtual void FillPlanarOffsetAddress(GMM_TEXTURE_INFO *pTexInfo); public: /* Constructors */ GmmGen11TextureCalc(Context *pGmmLibContext) : GmmGen10TextureCalc(pGmmLibContext) { } ~GmmGen11TextureCalc() { } /* Virtual Functions */ ///////////////////////////////////////////////////////////////////////// // Returns unaligned/unpadded width of a given LOD // Default : WL = ((width >> L) > 0 ? width >> L : 1) // CornerTexelMode : WL = MAX(1,(width-1) >> L) + 1 or WL = MAX(1,(WLminus1-1) >> 1) + 1 ///////////////////////////////////////////////////////////////////////// virtual GMM_GFX_SIZE_T GmmTexGetMipWidth(GMM_TEXTURE_INFO *pTexInfo, uint32_t MipLevel) { __GMM_ASSERTPTR(pTexInfo, 0); if (!pTexInfo->Flags.Info.CornerTexelMode) { return(GFX_MAX(1, pTexInfo->BaseWidth >> MipLevel)); } else { if (pTexInfo->BaseWidth == 1) { return pTexInfo->BaseWidth; } else { return(GFX_MAX(1, (pTexInfo->BaseWidth - 1) >> MipLevel) + 1); } } } ///////////////////////////////////////////////////////////////////////// // Returns unaligned/unpadded height of a given LOD // Default : HL = ((height >> L) > 0 ? height >> L : 1) // CornerTexelMode : HL = MAX(1,(height-1) >> L) + 1 or HL = MAX(1,(HLminus1-1) >> 1) + 1 ///////////////////////////////////////////////////////////////////////// virtual uint32_t GmmTexGetMipHeight(GMM_TEXTURE_INFO *pTexInfo, uint32_t MipLevel) { __GMM_ASSERTPTR(pTexInfo, 0); if (!pTexInfo->Flags.Info.CornerTexelMode) { return(GFX_MAX(1, pTexInfo->BaseHeight >> MipLevel)); } else { if (pTexInfo->BaseHeight == 1) { return pTexInfo->BaseHeight; } else { return(GFX_MAX(1, (pTexInfo->BaseHeight - 1) >> MipLevel) + 1); } } } ///////////////////////////////////////////////////////////////////////// // Returns unaligned/unpadded depth of a given LOD // Default : DL = ((depth >> L) > 0 ? depth >> L : 1) // CornerTexelMode : DL = MAX(1,(depth-1) >> L) + 1 or DL = MAX(1,(DLminus1-1) >> 1) + 1 ///////////////////////////////////////////////////////////////////////// virtual uint32_t GmmTexGetMipDepth(GMM_TEXTURE_INFO *pTexInfo, uint32_t MipLevel) { __GMM_ASSERTPTR(pTexInfo, 0); if (!pTexInfo->Flags.Info.CornerTexelMode) { return(GFX_MAX(1, pTexInfo->Depth >> MipLevel)); } else { if (pTexInfo->Depth == 1) { return pTexInfo->Depth; } else { return(GFX_MAX(1, (pTexInfo->Depth - 1) >> MipLevel) + 1); } } } /* Function prototypes */ /* inline functions */ }; } #endif // #ifdef __cplusplus gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/inc/Internal/Common/Texture/GmmGen12TextureCalc.h000066400000000000000000000130341466655022700311230ustar00rootroot00000000000000/*============================================================================== Copyright(c) 2019 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ============================================================================*/ #pragma once #ifdef __cplusplus #include "GmmGen11TextureCalc.h" #include "../Platform/GmmGen12Platform.h" ///////////////////////////////////////////////////////////////////////////////////// /// @file GmmGen12TextureCalc.h /// @brief This file contains the functions and members definations for texture alloc- /// ation on all Gen12 platforms. ///////////////////////////////////////////////////////////////////////////////////// namespace GmmLib { ///////////////////////////////////////////////////////////////////////// /// Contains texture calc functions and members for Gen12 platforms. /// This class is derived from the base GmmTextureCalc class so clients /// shouldn't have to ever interact with this class directly. ///////////////////////////////////////////////////////////////////////// class NON_PAGED_SECTION GmmGen12TextureCalc : public GmmGen11TextureCalc { private: protected: virtual uint32_t GetMipTailByteOffset( GMM_TEXTURE_INFO *pTexInfo, uint32_t MipLevel); virtual void GetMipTailGeometryOffset( GMM_TEXTURE_INFO *pTexInfo, uint32_t MipLevel, uint32_t * OffsetX, uint32_t * OffsetY, uint32_t * OffsetZ); virtual uint32_t Get2DMipMapHeight( GMM_TEXTURE_INFO *pTexInfo); virtual GMM_STATUS FillTexCCS( GMM_TEXTURE_INFO *pSurf, GMM_TEXTURE_INFO *pAuxTexInfo); public: /* Constructors */ GmmGen12TextureCalc(Context *pGmmLibContext) : GmmGen11TextureCalc(pGmmLibContext) { } ~GmmGen12TextureCalc() { } /* Function prototypes */ virtual GMM_STATUS GMM_STDCALL FillTex2D(GMM_TEXTURE_INFO *pTexInfo, __GMM_BUFFER_TYPE *pRestrictions); virtual GMM_STATUS GMM_STDCALL FillTexPlanar(GMM_TEXTURE_INFO *pTexInfo, __GMM_BUFFER_TYPE *pRestrictions); virtual GMM_STATUS GMM_STDCALL GetCCSScaleFactor(GMM_TEXTURE_INFO * pTexInfo, CCS_UNIT& ScaleFactor); GMM_STATUS GMM_STDCALL GetCCSExMode(GMM_TEXTURE_INFO * AuxSurf); virtual uint32_t GMM_STDCALL ScaleTextureHeight(GMM_TEXTURE_INFO * pTexInfo, uint32_t Height); virtual uint32_t GMM_STDCALL ScaleTextureWidth (GMM_TEXTURE_INFO* pTexInfo, uint32_t Width); virtual uint32_t GMM_STDCALL ScaleFCRectHeight(GMM_TEXTURE_INFO * pTexInfo, uint32_t Height); virtual uint64_t GMM_STDCALL ScaleFCRectWidth(GMM_TEXTURE_INFO* pTexInfo, uint64_t Width); virtual GMM_STATUS GMM_STDCALL MSAACCSUsage(GMM_TEXTURE_INFO *pTexInfo); virtual void GMM_STDCALL AllocateOneTileThanRequied(GMM_TEXTURE_INFO *pTexInfo, GMM_GFX_SIZE_T &WidthBytesRender, GMM_GFX_SIZE_T &WidthBytesPhysical, GMM_GFX_SIZE_T &WidthBytesLock) { GMM_UNREFERENCED_PARAMETER(pTexInfo); GMM_UNREFERENCED_PARAMETER(WidthBytesRender); GMM_UNREFERENCED_PARAMETER(WidthBytesPhysical); GMM_UNREFERENCED_PARAMETER(WidthBytesLock); } virtual uint64_t GMM_STDCALL Get2DFCSurfaceWidthFor3DSurface(GMM_TEXTURE_INFO *pTexInfo, uint64_t Width); virtual uint64_t GMM_STDCALL Get2DFCSurfaceHeightFor3DSurface(GMM_TEXTURE_INFO *pTexInfo, uint32_t Height, uint32_t Depth); /* inline functions */ }; } #endif // #ifdef __cplusplus gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/inc/Internal/Common/Texture/GmmGen7TextureCalc.h000066400000000000000000000075731466655022700310620ustar00rootroot00000000000000/*============================================================================== Copyright(c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ============================================================================*/ #pragma once #ifdef __cplusplus #include "GmmTextureCalc.h" ///////////////////////////////////////////////////////////////////////////////////// /// @file GmmGen7TextureCalc.h /// @brief This file contains the common functions and members for texture calculations /// on all GENs/Platforms ///////////////////////////////////////////////////////////////////////////////////// namespace GmmLib { ///////////////////////////////////////////////////////////////////////// /// Contains texture calc functions and members for Gen7 platforms. /// This class is derived from the base GmmTextureCalc class so clients /// shouldn't have to ever interact with this class directly. ///////////////////////////////////////////////////////////////////////// class NON_PAGED_SECTION GmmGen7TextureCalc : public GmmTextureCalc { private: uint32_t GetTotal3DHeight( GMM_TEXTURE_INFO* pTexInfo); void Fill3DTexOffsetAddress( GMM_TEXTURE_INFO *pTexInfo); protected: /* Function prototypes */ virtual uint32_t Get2DMipMapHeight( GMM_TEXTURE_INFO *pTexInfo); virtual void Fill2DTexOffsetAddress( GMM_TEXTURE_INFO *pTexInfo); virtual GMM_GFX_SIZE_T Get2DTexOffsetAddressPerMip( GMM_TEXTURE_INFO *pTexInfo, uint32_t MipLevel); public: /* Constructors */ GmmGen7TextureCalc(Context *pGmmLibContext) : GmmTextureCalc(pGmmLibContext) { } ~GmmGen7TextureCalc() { } /* Function prototypes */ virtual GMM_STATUS GMM_STDCALL FillTex1D(GMM_TEXTURE_INFO *pTexInfo, __GMM_BUFFER_TYPE *pRestrictions); virtual GMM_STATUS GMM_STDCALL FillTex2D(GMM_TEXTURE_INFO *pTexInfo, __GMM_BUFFER_TYPE *pRestrictions); virtual GMM_STATUS GMM_STDCALL FillTex3D(GMM_TEXTURE_INFO *pTexInfo, __GMM_BUFFER_TYPE *pRestrictions); virtual GMM_STATUS GMM_STDCALL FillTexCube(GMM_TEXTURE_INFO *pTexInfo, __GMM_BUFFER_TYPE *pRestrictions); /* inline functions */ }; } #endif // #ifdef __cplusplus gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/inc/Internal/Common/Texture/GmmGen8TextureCalc.h000066400000000000000000000063421466655022700310540ustar00rootroot00000000000000/*============================================================================== Copyright(c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ============================================================================*/ #pragma once #ifdef __cplusplus #include "GmmGen7TextureCalc.h" ///////////////////////////////////////////////////////////////////////////////////// /// @file GmmGen8TextureCalc.h /// @brief This file contains the functions and members definations for texture alloc- /// ation on all Gen8 platforms. ///////////////////////////////////////////////////////////////////////////////////// namespace GmmLib { ///////////////////////////////////////////////////////////////////////// /// Contains texture calc functions and members for Gen8 platforms. /// This class is derived from the base GmmGen7TextureCalc class so clients /// shouldn't have to ever interact with this class directly. ///////////////////////////////////////////////////////////////////////// class NON_PAGED_SECTION GmmGen8TextureCalc : public GmmGen7TextureCalc { private: protected: /* Function prototypes */ virtual void Fill2DTexOffsetAddress( GMM_TEXTURE_INFO *pTexInfo); public: /* Constructors */ GmmGen8TextureCalc(Context *pGmmLibContext) : GmmGen7TextureCalc(pGmmLibContext) { } ~GmmGen8TextureCalc() { } /* Function prototypes */ virtual GMM_STATUS GMM_STDCALL FillTex1D(GMM_TEXTURE_INFO *pTexInfo, __GMM_BUFFER_TYPE *pRestrictions); virtual GMM_STATUS GMM_STDCALL FillTex2D(GMM_TEXTURE_INFO *pTexInfo, __GMM_BUFFER_TYPE *pRestrictions); virtual GMM_STATUS GMM_STDCALL FillTexCube(GMM_TEXTURE_INFO *pTexInfo, __GMM_BUFFER_TYPE *pRestrictions); virtual GMM_STATUS GMM_STDCALL MSAACCSUsage(GMM_TEXTURE_INFO *pTexInfo); /* inline functions */ }; } #endif // #ifdef __cplusplus gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/inc/Internal/Common/Texture/GmmGen9TextureCalc.h000066400000000000000000000134031466655022700310510ustar00rootroot00000000000000/*============================================================================== Copyright(c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ============================================================================*/ #pragma once #ifdef __cplusplus #include "GmmTextureCalc.h" ///////////////////////////////////////////////////////////////////////////////////// /// @file GmmGen9TextureCalc.h /// @brief This file contains the functions and members definations for texture alloc- /// ation on all Gen9 platforms. ///////////////////////////////////////////////////////////////////////////////////// namespace GmmLib { ///////////////////////////////////////////////////////////////////////// /// Contains texture calc functions and members for Gen9 platforms. /// This class is derived from the base GmmTextureCalc class so clients /// shouldn't have to ever interact with this class directly. ///////////////////////////////////////////////////////////////////////// class NON_PAGED_SECTION GmmGen9TextureCalc : public GmmTextureCalc { private: void Fill1DTexOffsetAddress( GMM_TEXTURE_INFO *pTexInfo); GMM_GFX_SIZE_T Get1DTexOffsetAddressPerMip( GMM_TEXTURE_INFO *pTexInfo, uint32_t MipLevel); protected: /* Function prototypes */ virtual void Fill2DTexOffsetAddress( GMM_TEXTURE_INFO *pTexInfo); virtual GMM_GFX_SIZE_T Get2DTexOffsetAddressPerMip( GMM_TEXTURE_INFO *pTexInfo, uint32_t MipLevel); virtual uint32_t Get2DMipMapHeight( GMM_TEXTURE_INFO *pTexInfo); uint32_t Get2DMipMapTotalHeight( GMM_TEXTURE_INFO *pTexInfo); virtual uint32_t GetMipTailByteOffset( GMM_TEXTURE_INFO *pTexInfo, uint32_t MipLevel); virtual void GetMipTailGeometryOffset( GMM_TEXTURE_INFO *pTexInfo, uint32_t MipLevel, uint32_t* OffsetX, uint32_t* OffsetY, uint32_t* OffsetZ); virtual uint32_t GetAligned3DBlockHeight( GMM_TEXTURE_INFO* pTexInfo, uint32_t BlockHeight, uint32_t ExpandedArraySize); public: /* Constructors */ GmmGen9TextureCalc(Context *pGmmLibContext) : GmmTextureCalc(pGmmLibContext) { } ~GmmGen9TextureCalc() { } /* Function prototypes */ virtual GMM_STATUS GMM_STDCALL FillTex1D(GMM_TEXTURE_INFO *pTexInfo, __GMM_BUFFER_TYPE *pRestrictions); virtual GMM_STATUS GMM_STDCALL FillTex2D(GMM_TEXTURE_INFO *pTexInfo, __GMM_BUFFER_TYPE *pRestrictions); virtual GMM_STATUS GMM_STDCALL FillTex3D(GMM_TEXTURE_INFO *pTexInfo, __GMM_BUFFER_TYPE *pRestrictions); virtual GMM_STATUS GMM_STDCALL FillTexCube(GMM_TEXTURE_INFO *pTexInfo, __GMM_BUFFER_TYPE *pRestrictions); virtual GMM_STATUS GMM_STDCALL MSAACCSUsage(GMM_TEXTURE_INFO *pTexInfo); virtual uint32_t GMM_STDCALL ScaleFCRectHeight(GMM_TEXTURE_INFO * pTexInfo, uint32_t Height) { __GMM_ASSERTPTR(pTexInfo, 0); uint32_t ScaledHeight = Height; if (pTexInfo->TileMode == LEGACY_TILE_Y) { const uint16_t FastClearRccTileYAlignHeight = 64; // lines - RCC ( Render Color Cache ) Alignment Sizes const uint16_t TileYClearHeightScale = 32; // lines - Clear & Resolve Rect Scaling Sizes ScaledHeight = GFX_ALIGN(ScaledHeight, FastClearRccTileYAlignHeight); ScaledHeight /= TileYClearHeightScale; } return ScaledHeight; } /* inline functions */ }; } #endif // #ifdef __cplusplus gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/inc/Internal/Common/Texture/GmmTextureCalc.h000066400000000000000000000445641466655022700303420ustar00rootroot00000000000000/*============================================================================== Copyright(c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ============================================================================*/ #pragma once #ifdef __cplusplus #include "External/Common/GmmMemAllocator.hpp" #include "Internal/Common/GmmLibInc.h" ///////////////////////////////////////////////////////////////////////////////////// /// @file GmmTextureCalc.h /// @brief This file contains the common functions and members for texture calculations /// on all GENs/Platforms ///////////////////////////////////////////////////////////////////////////////////// namespace GmmLib { ///////////////////////////////////////////////////////////////////////// /// Contains texture calc functions and members that are common across all /// platform implementation. This is an abstract class and provides a /// uniform interface to all the texture clients and provides gen specific /// texture allocation through derived concrete GmmGenXTextureCalc class. ///////////////////////////////////////////////////////////////////////// class Context; class NON_PAGED_SECTION GmmTextureCalc : public GmmMemAllocator { private: GMM_STATUS FillTexBlockMem( GMM_TEXTURE_INFO *pTexInfo, __GMM_BUFFER_TYPE *pRestrictions); void ResetRestrictions(__GMM_BUFFER_TYPE *pRestriction); void GetTexRestrictions( GMM_TEXTURE_INFO* pTexInfo, __GMM_BUFFER_TYPE* pBuff); bool ValidateTexInfo( GMM_TEXTURE_INFO *pTexInfo, __GMM_BUFFER_TYPE *pRestrictions); protected: Context *pGmmLibContext; /* Function prototypes */ virtual GMM_STATUS GMM_STDCALL FillTexPlanar( GMM_TEXTURE_INFO *pTexInfo, __GMM_BUFFER_TYPE *pRestrictions); GMM_STATUS FillTexPitchAndSize(GMM_TEXTURE_INFO *pTexInfo, GMM_GFX_SIZE_T WidthBytesPhysical, uint32_t Height, __GMM_BUFFER_TYPE *pBufferType); void FillPlanarOffsetAddress( GMM_TEXTURE_INFO *pTexInfo); void FindMipTailStartLod(GMM_TEXTURE_INFO *pTexInfo); GMM_VIRTUAL void GetGenericRestrictions(GMM_TEXTURE_INFO* pTexInfo, __GMM_BUFFER_TYPE *pBuff); GMM_VIRTUAL __GMM_BUFFER_TYPE* GetBestRestrictions(__GMM_BUFFER_TYPE *pFirstBuffer, const __GMM_BUFFER_TYPE *pSecondBuffer); /* Inline functions */ ///////////////////////////////////////////////////////////////////////////////////// /// Checks where the restrictions are invalid or not /// @param[in] pRestriction Restrictions to check /// @return true if restriction is invalid. false otherwise. ///////////////////////////////////////////////////////////////////////////////////// GMM_INLINE_VIRTUAL GMM_INLINE bool IsRestrictionInvalid(__GMM_BUFFER_TYPE *pRestriction) { return ((pRestriction->MinDepth == 0xffffffff) ? true : false); } ///////////////////////////////////////////////////////////////////////////////////// /// Returns restrictions for a linear buffer. /// @param[out] pBuff Restrictions are returned in this buffer ///////////////////////////////////////////////////////////////////////////////////// GMM_INLINE_VIRTUAL GMM_INLINE void GetLinearRestrictions(GMM_TEXTURE_INFO* pTexInfo, __GMM_BUFFER_TYPE* pBuff) { *pBuff = GMM_OVERRIDE_PLATFORM_INFO(pTexInfo,pGmmLibContext)->Linear; } ///////////////////////////////////////////////////////////////////////////////////// /// Returns restrictions for the primary buffer. /// @param[out] pBuff Restrictions are returned in this buffer ///////////////////////////////////////////////////////////////////////////////////// GMM_INLINE_VIRTUAL GMM_INLINE void GetPrimaryRestrictions(GMM_TEXTURE_INFO* pTexInfo, __GMM_BUFFER_TYPE* pBuff) { *pBuff = GMM_OVERRIDE_PLATFORM_INFO(pTexInfo,pGmmLibContext)->ASyncFlipSurface; } virtual uint32_t Get2DMipMapHeight(GMM_TEXTURE_INFO *pTexInfo) = 0; virtual void Fill2DTexOffsetAddress(GMM_TEXTURE_INFO *pTexInfo) = 0; virtual GMM_GFX_SIZE_T Get2DTexOffsetAddressPerMip( GMM_TEXTURE_INFO *pTexInfo, uint32_t MipLevel) = 0; virtual uint32_t GetMipTailByteOffset( GMM_TEXTURE_INFO *pTexInfo, uint32_t MipLevel) { GMM_UNREFERENCED_PARAMETER(pTexInfo); GMM_UNREFERENCED_PARAMETER(MipLevel); // Left empty return 0; } virtual void GetMipTailGeometryOffset( GMM_TEXTURE_INFO *pTexInfo, uint32_t MipLevel, uint32_t* OffsetX, uint32_t* OffsetY, uint32_t* OffsetZ) { GMM_UNREFERENCED_PARAMETER(pTexInfo); GMM_UNREFERENCED_PARAMETER(MipLevel); GMM_UNREFERENCED_PARAMETER(OffsetX); GMM_UNREFERENCED_PARAMETER(OffsetY); GMM_UNREFERENCED_PARAMETER(OffsetZ); // Left empty } GMM_GFX_SIZE_T Get3DMipByteAddress( GMM_TEXTURE_INFO* pTexInfo, GMM_REQ_OFFSET_INFO *pReqInfo); virtual uint32_t GetAligned3DBlockHeight( GMM_TEXTURE_INFO* pTexInfo, uint32_t BlockHeight, uint32_t ExpandedArraySize) { GMM_UNREFERENCED_PARAMETER(pTexInfo); GMM_UNREFERENCED_PARAMETER(BlockHeight); GMM_UNREFERENCED_PARAMETER(ExpandedArraySize); // Left empty return 0; } public: /* Constructors */ // "Creates GmmTextureCalc object based on platform ID" void SetTileMode(GMM_TEXTURE_INFO* pTexInfo); GmmTextureCalc(Context *pGmmLibContext) { this->pGmmLibContext = pGmmLibContext; } virtual ~GmmTextureCalc() { } /* Function prototypes */ GMM_STATUS AllocateTexture(GMM_TEXTURE_INFO *pTexInfo); virtual GMM_STATUS FillTexCCS(GMM_TEXTURE_INFO *pBaseSurf, GMM_TEXTURE_INFO *pTexInfo); uint8_t SurfaceRequires64KBTileOptimization( GMM_TEXTURE_INFO *pTexInfo); GMM_STATUS PreProcessTexSpecialCases( GMM_TEXTURE_INFO* pTexInfo); uint32_t ExpandHeight( uint32_t Height, uint32_t UnitAlignment, uint32_t NumSamples); uint32_t ExpandWidth( uint32_t Width, uint32_t UnitAlignment, uint32_t NumSamples); void GetCompressionBlockDimensions( GMM_RESOURCE_FORMAT Format, uint32_t *pWidth, uint32_t *pHeight, uint32_t *pDepth); GMM_STATUS GetTexRenderOffset( GMM_TEXTURE_INFO* pTexInfo, GMM_REQ_OFFSET_INFO* pReqInfo); virtual GMM_STATUS GetTexLockOffset( GMM_TEXTURE_INFO* pTexInfo, GMM_REQ_OFFSET_INFO *pReqInfo); GMM_STATUS GetTexStdLayoutOffset( GMM_TEXTURE_INFO* pTexInfo, GMM_REQ_OFFSET_INFO *pReqInfo); virtual GMM_GFX_SIZE_T GetMipMapByteAddress( GMM_TEXTURE_INFO* pTexInfo, GMM_REQ_OFFSET_INFO *pReqInfo); void AlignTexHeightWidth( GMM_TEXTURE_INFO* pTexInfo, uint32_t* pHeight, uint32_t* pWidth); bool GmmGetD3DToHwTileConversion( GMM_TEXTURE_INFO *pTexInfo, uint32_t *pColFactor, uint32_t *pRowFactor); void GetResRestrictions( GMM_TEXTURE_INFO* pTexInfo, __GMM_BUFFER_TYPE& pBuff); bool RedescribeTexturePlanes(GMM_TEXTURE_INFO *pTexInfo, uint32_t *pWidthBytesPhysical); bool GetRedescribedPlaneParams(GMM_TEXTURE_INFO *pTexInfo, GMM_YUV_PLANE PlaneType, GMM_TEXTURE_INFO *pRedescribedTexInfo); // Virtual functions virtual GMM_STATUS GMM_STDCALL FillTex1D( GMM_TEXTURE_INFO *pTexInfo, __GMM_BUFFER_TYPE *pRestrictions) = 0; virtual GMM_STATUS GMM_STDCALL FillTex2D( GMM_TEXTURE_INFO *pTexInfo, __GMM_BUFFER_TYPE *pRestrictions) = 0; virtual GMM_STATUS GMM_STDCALL FillTex3D( GMM_TEXTURE_INFO *pTexInfo, __GMM_BUFFER_TYPE *pRestrictions) = 0; virtual GMM_STATUS GMM_STDCALL FillTexCube( GMM_TEXTURE_INFO *pTexInfo, __GMM_BUFFER_TYPE *pRestrictions) = 0; virtual GMM_STATUS GMM_STDCALL GetCCSExMode(GMM_TEXTURE_INFO * AuxSurf) { GMM_UNREFERENCED_PARAMETER(AuxSurf); return GMM_SUCCESS; } virtual uint32_t GMM_STDCALL ScaleTextureWidth(GMM_TEXTURE_INFO* pTexInfo, uint32_t Width) { __GMM_ASSERT(pTexInfo != NULL); switch (pTexInfo->BitsPerPixel) { case 32: Width /= 8; break; case 64: Width /= 4; break; case 128: Width /= 2; break; default: __GMM_ASSERT(0); } return Width; } virtual uint32_t GMM_STDCALL ScaleTextureHeight(GMM_TEXTURE_INFO* pTexInfo, uint32_t Height) { GMM_UNREFERENCED_PARAMETER(pTexInfo); return Height /= 16; } virtual GMM_GFX_SIZE_T GmmTexGetMipWidth(GMM_TEXTURE_INFO *pTexInfo, uint32_t MipLevel) { __GMM_ASSERTPTR(pTexInfo, 0); return(GFX_MAX(1, pTexInfo->BaseWidth >> MipLevel)); } virtual uint32_t GmmTexGetMipHeight(GMM_TEXTURE_INFO *pTexInfo, uint32_t MipLevel) { __GMM_ASSERTPTR(pTexInfo, 0); return(GFX_MAX(1, pTexInfo->BaseHeight >> MipLevel)); } virtual uint32_t GmmTexGetMipDepth(GMM_TEXTURE_INFO *pTexInfo, uint32_t MipLevel) { __GMM_ASSERTPTR(pTexInfo, 0); return(GFX_MAX(1, pTexInfo->Depth >> MipLevel)); } virtual uint32_t GMM_STDCALL ScaleFCRectHeight(GMM_TEXTURE_INFO * pTexInfo, uint32_t Height) { __GMM_ASSERTPTR(pTexInfo, 0); uint32_t ScaledHeight = Height; if (pTexInfo->TileMode == LEGACY_TILE_X) { const uint16_t FastClearRccTileXAlignHeight = 64; // lines - RCC ( Render Color Cache ) Alignment Sizes const uint16_t TileXClearHeightScale = 32; // lines - Clear & Resolve Rect Scaling Sizes ScaledHeight = GFX_ALIGN(ScaledHeight, FastClearRccTileXAlignHeight); ScaledHeight /= TileXClearHeightScale; } else if (pTexInfo->TileMode == LEGACY_TILE_Y) { const uint16_t FastClearRccTileYAlignHeight = 128; // bits const uint16_t TileYClearHeightScale = 64; // bits ScaledHeight = GFX_ALIGN(ScaledHeight, FastClearRccTileYAlignHeight); ScaledHeight /= TileYClearHeightScale; } return ScaledHeight; } virtual uint64_t GMM_STDCALL ScaleFCRectWidth(GMM_TEXTURE_INFO * pTexInfo, uint64_t Width) { __GMM_ASSERTPTR(pTexInfo, 0); uint64_t ScaledWidth = Width; if (pTexInfo->TileMode == LEGACY_TILE_X) { const uint32_t FastClearRccTileXAlignWidth = 8192; // bits - RCC ( Render Color Cache ) Alignment Sizes const uint32_t TileXClearWidthScale = 4096; // bits - Clear & Resolve Rect Scaling Sizes ScaledWidth = GFX_ALIGN(ScaledWidth, FastClearRccTileXAlignWidth / pTexInfo->BitsPerPixel); ScaledWidth /= TileXClearWidthScale; } else if (pTexInfo->TileMode == LEGACY_TILE_Y) { const uint32_t FastClearRccTileYAlignWidth = 4096; // bits const uint32_t TileYClearWidthScale = 2048; // bits ScaledWidth = GFX_ALIGN(ScaledWidth, FastClearRccTileYAlignWidth / pTexInfo->BitsPerPixel); ScaledWidth /= TileYClearWidthScale; } return ScaledWidth; } virtual GMM_STATUS GMM_STDCALL MSAACCSUsage(GMM_TEXTURE_INFO *pTexInfo); virtual void GMM_STDCALL AllocateOneTileThanRequied(GMM_TEXTURE_INFO *pTexInfo, GMM_GFX_SIZE_T &WidthBytesRender, GMM_GFX_SIZE_T &WidthBytesPhysical, GMM_GFX_SIZE_T &WidthBytesLock); GMM_STATUS MSAACompression(GMM_TEXTURE_INFO *pTexInfo); virtual uint64_t GMM_STDCALL Get2DFCSurfaceWidthFor3DSurface(GMM_TEXTURE_INFO *pTexInfo, uint64_t Width) { GMM_UNREFERENCED_PARAMETER(pTexInfo); return Width; } virtual uint64_t GMM_STDCALL Get2DFCSurfaceHeightFor3DSurface(GMM_TEXTURE_INFO *pTexInfo, uint32_t Height, uint32_t Depth) { GMM_UNREFERENCED_PARAMETER(pTexInfo); GMM_UNREFERENCED_PARAMETER(Depth); return Height; } uint32_t GMM_STDCALL GetDisplayFrameOffset(GMM_TEXTURE_INFO *pTexInfo, GMM_REQ_OFFSET_INFO *pReqInfo); virtual uint32_t GMM_STDCALL IsTileAlignedPlanes(GMM_TEXTURE_INFO *pTexInfo); virtual uint32_t GMM_STDCALL GetNumberOfPlanes(GMM_TEXTURE_INFO *pTexInfo); virtual void GMM_STDCALL SetPlanarOffsetInfo(GMM_TEXTURE_INFO *pTexInfo, GMM_RESCREATE_CUSTOM_PARAMS &CreateParams); #ifndef __GMM_KMD__ virtual void GMM_STDCALL SetPlanarOffsetInfo_2(GMM_TEXTURE_INFO *pTexInfo, GMM_RESCREATE_CUSTOM_PARAMS_2 &CreateParams); #endif virtual void GMM_STDCALL SetPlaneUnAlignedTexOffsetInfo(GMM_TEXTURE_INFO *pTexInfo, uint32_t YHeight, uint32_t VHeight); virtual void GMM_STDCALL GetPlaneIdForCpuBlt(GMM_TEXTURE_INFO *pTexInfo, GMM_RES_COPY_BLT *pBlt, uint32_t *PlaneId); virtual void GMM_STDCALL GetBltInfoPerPlane(GMM_TEXTURE_INFO *pTexInfo, GMM_RES_COPY_BLT *pBlt, uint32_t PlaneId); /* inline functions */ }; } #endif // #ifdef __cplusplus gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/inc/Internal/Common/Texture/GmmXe_LPGTextureCalc.h000066400000000000000000000107611466655022700313310ustar00rootroot00000000000000/*============================================================================== Copyright(c) 2022 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ============================================================================*/ #pragma once #ifdef __cplusplus #include "GmmGen12TextureCalc.h" #include "../Platform/GmmGen12Platform.h" ///////////////////////////////////////////////////////////////////////////////////// /// @file GmmGen12TextureCalc.h /// @brief This file contains the functions and members definations for texture alloc- /// ation on all Gen12 platforms. ///////////////////////////////////////////////////////////////////////////////////// namespace GmmLib { ///////////////////////////////////////////////////////////////////////// /// Contains texture calc functions and members for Gen12 platforms. /// This class is derived from the base GmmTextureCalc class so clients /// shouldn't have to ever interact with this class directly. ///////////////////////////////////////////////////////////////////////// class NON_PAGED_SECTION GmmXe_LPGTextureCalc : public GmmGen12TextureCalc { public: /* Constructors */ GmmXe_LPGTextureCalc(Context *pGmmLibContext) : GmmGen12TextureCalc(pGmmLibContext) { } ~GmmXe_LPGTextureCalc() { } /* Function prototypes */ virtual GMM_STATUS GMM_STDCALL FillTexPlanar(GMM_TEXTURE_INFO *pTexInfo, __GMM_BUFFER_TYPE *pRestrictions); virtual void FillPlanarOffsetAddress(GMM_TEXTURE_INFO *pTexInfo); virtual GMM_STATUS GetTexLockOffset(GMM_TEXTURE_INFO *pTexInfo, GMM_REQ_OFFSET_INFO *pReqInfo); virtual GMM_GFX_SIZE_T GetMipMapByteAddress(GMM_TEXTURE_INFO *pTexInfo, GMM_REQ_OFFSET_INFO *pReqInfo); virtual uint32_t GMM_STDCALL IsTileAlignedPlanes(GMM_TEXTURE_INFO *pTexInfo); virtual uint32_t GMM_STDCALL GetNumberOfPlanes(GMM_TEXTURE_INFO *pTexInfo); virtual void GMM_STDCALL SetPlanarOffsetInfo(GMM_TEXTURE_INFO *pTexInfo, GMM_RESCREATE_CUSTOM_PARAMS &CreateParams); #ifndef __GMM_KMD__ virtual void GMM_STDCALL SetPlanarOffsetInfo_2(GMM_TEXTURE_INFO *pTexInfo, GMM_RESCREATE_CUSTOM_PARAMS_2 &CreateParams); #endif virtual void GMM_STDCALL SetPlaneUnAlignedTexOffsetInfo(GMM_TEXTURE_INFO *pTexInfo, uint32_t YHeight, uint32_t VHeight); virtual void GMM_STDCALL GetPlaneIdForCpuBlt(GMM_TEXTURE_INFO *pTexInfo, GMM_RES_COPY_BLT *pBlt, uint32_t *PlaneId); virtual void GMM_STDCALL GetBltInfoPerPlane(GMM_TEXTURE_INFO *pTexInfo, GMM_RES_COPY_BLT *pBlt, uint32_t PlaneId); /* inline functions */ }; } #endif // #ifdef __cplusplus gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/inc/Internal/Linux/000077500000000000000000000000001466655022700234775ustar00rootroot00000000000000gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/inc/Internal/Linux/GmmResourceInfoLinInt.h000066400000000000000000000053021466655022700300320ustar00rootroot00000000000000/*============================================================================== Copyright(c) 2019 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ============================================================================*/ #pragma once #if defined(__linux__) && !LHDM // GMM Lib Client Exports #include "External/Common/GmmCommonExt.h" #include "External/Common/GmmUtil.h" #include "External/Common/GmmResourceFlags.h" #include "External/Common/GmmCachePolicy.h" #include "External/Common/GmmCachePolicyExt.h" #include "External/Common/GmmResourceInfoExt.h" #include "External/Common/GmmPlatformExt.h" #include "External/Common/GmmTextureExt.h" #include "External/Common/GmmInfoExt.h" #include "External/Common/GmmResourceInfo.h" #include "External/Common/GmmInfo.h" typedef struct { size_t size; size_t alignment; void *bo; void *cpuAddr; uint64_t gfxAddr; } GMM_DDI_ALLOCATE; typedef struct { void *bo; } GMM_DDI_DEALLOCATE; typedef struct { void *bo; }GMM_DDI_WAITFORSYNCHRONIZATIONOBJECTFROMCPU; typedef enum GMM_DEVICE_CALLBACKS_TYPE_REC { GMM_DEV_CB_ALLOC = 0, GMM_DEV_CB_DEALLOC, GMM_DEV_CB_WAIT_FROM_CPU, } GMM_DEVICE_CALLBACKS_TYPE; int GmmDeviceCallback(GMM_CLIENT ClientType, GMM_DEVICE_CALLBACKS_INT *pDeviceCb, GMM_DDI_ALLOCATE *pAllocate); int GmmDeviceCallback(GMM_CLIENT ClientType, GMM_DEVICE_CALLBACKS_INT *pDeviceCb, GMM_DDI_DEALLOCATE *pDeallocate); int GmmDeviceCallback(GMM_CLIENT ClientType, GMM_DEVICE_CALLBACKS_INT *pDeviceCb, GMM_DDI_WAITFORSYNCHRONIZATIONOBJECTFROMCPU *pWait); int GmmCheckForNullDevCbPfn(GMM_CLIENT ClientType, GMM_DEVICE_CALLBACKS_INT *pDeviceCb, GMM_DEVICE_CALLBACKS_TYPE CallBackType); extern GMM_TRANSLATIONTABLE_CALLBACKS DummyTTCB; #endif /*__linux__*/ gmmlib-intel-gmmlib-22.5.2/Source/GmmLib/os_release_info.cmake000077500000000000000000000145001466655022700242140ustar00rootroot00000000000000# Copyright (c) 2018, Intel Corporation # # Permission is hereby granted, free of charge, to any person obtaining a # copy of this software and associated documentation files (the "Software"), # to deal in the Software without restriction, including without limitation # the rights to use, copy, modify, merge, publish, distribute, sublicense, # and/or sell copies of the Software, and to permit persons to whom the # Software is furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included # in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL # THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR # OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, # ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR # OTHER DEALINGS IN THE SOFTWARE. # os_release_info.cmake - Function to dump OS name and version # This file has no dependencies on other files (e.g., functions or definitions) # of the local cmake environment. if(NOT DEFINED _os_release_info) set(_os_release_info TRUE) # Set cmake policies for at least this level: cmake_minimum_required(VERSION 2.8.12) if(POLICY CMP0054) cmake_policy(SET CMP0054 NEW) endif() # Function get_os_release_info - Determine and return OS name and version # # Args: # 1. the name of a variable to receive os_name # 2. the name of a variable to receive os_version # # Return values: (Quotation marks are always stripped). # Upon failure, return values are null strings. # # Examples: # os_name os_version # -------------- ------- # clear-linux-os 21180 (Changes twice daily) # ubuntu 12.04 16.04 17.10 18.04 # fedora 27 # centos 6.9 7.4.1708 # # Potential sources are tried (in order of preference) until a # suitable one is found. # Implementation documentation: # # The potential sources, in order, are as follows. # - /etc/centos-release # Centos 7 also has /etc/os-release. File /etc/os-release is less # precise about the Centos version (e.g., "7" instead of "7.4.1708"). # For that reason, this file is checked first. # Examples: # CentOS release 6.9 (Final) # CentOS Linux release 7.4.1708 (Core) # - /usr/lib/os-release # Present for Clear Linux, modern Fedora, and Ubuntu since some time # between 14.04 and 16.04. The ID and VERSION_ID values are used. # Examples: # ID=clear-linux-os VERSION_ID=21180 # ID=fedora VERSION_ID=27 # ID=ubuntu VERSION_ID="14.04" # ID=ubuntu VERSION_ID="16.04" # ID="ubuntu" VERSION_ID="17.10" # - /etc/os-release - Same form as (sometimes a link to) /usr/lib/os-release # ID="Ubuntu" VERSION_ID="12.04" # ID="Ubuntu" VERSION_ID="14.04" # with a symbolic link: /etc/os-release -> ../usr/lib/os-release # ID="CentOS Linux" VERSION_ID="7" Also: ID_LIKE="rhel fedora" # - /etc/lsb-release # For Centos, not too meaningful. # Other "OS"s are more reasonable: # DISTRIB_ID=Ubuntu DISTRIB_RELEASE=12.04 # DISTRIB_ID=Ubuntu DISTRIB_RELEASE=14.04 # DISTRIB_ID=Ubuntu DISTRIB_RELEASE=17.10 function(get_os_release_info _vn_id _vn_version_id) set(_var_id "") set(_var_version_id "") if("${_var_id}" STREQUAL "") set(file_path "/etc/centos-release") if(EXISTS "${file_path}") # Example: CentOS release 6.9 (Final) file(STRINGS "${file_path}" file_list LIMIT_COUNT 1) list(GET file_list 0 file_line) # Remove all parenthesized items. string(REGEX REPLACE "\\([^)]+\\)" "" file_line "${file_line}") # Extract start and end, discard optional "version" or "release" string(REGEX MATCH "^([A-Za-z0-9_]+)( +(version|release))? +(.*)$" _dummy "${file_line}") # 1 2 3 4 set(_var_id "${CMAKE_MATCH_1}") set(_var_version_id "${CMAKE_MATCH_4}") endif() endif() if("${_var_id}" STREQUAL "") if(EXISTS "/usr/lib/os-release") set(file_path "/usr/lib/os-release") elseif(EXISTS "/etc/os-release") set(file_path "/etc/os-release") else() set(file_path "") endif() if(NOT "${file_path}" STREQUAL "") file(STRINGS "${file_path}" data_list REGEX "^(ID|VERSION_ID)=") # Look for lines like "ID="..." and VERSION_ID="..." foreach(_var ${data_list}) if("${_var}" MATCHES "^(ID)=(.*)$") set(_var_id "${CMAKE_MATCH_2}") elseif("${_var}" MATCHES "^(VERSION_ID)=(.*)$") set(_var_version_id "${CMAKE_MATCH_2}") endif() endforeach() endif() endif() if("${_var_id}" STREQUAL "") set(file_path "/etc/lsb-release") if(EXISTS "${file_path}") file(STRINGS "${file_path}" data_list REGEX "^(DISTRIB_ID|DISTRIB_RELEASE)=") # Look for lines like "DISTRIB_ID="..." and DISTRIB_RELEASE="..." foreach(_var ${data_list}) if("${_var}" MATCHES "^(DISTRIB_ID)=(.*)$") set(_var_id "${CMAKE_MATCH_2}") elseif("${_var}" MATCHES "^(DISTRIB_RELEASE)=(.*)$") set(_var_version_id "${CMAKE_MATCH_2}") endif() endforeach() endif() endif() string(TOLOWER "${_var_id}" "_var_id") string(STRIP "${_var_id}" _var_id) string(STRIP "${_var_version_id}" _var_version_id) # Remove any enclosing quotation marks string(REGEX REPLACE "^\"(.*)\"$" "\\1" _var_id "${_var_id}") string(REGEX REPLACE "^\"(.*)\"$" "\\1" _var_version_id "${_var_version_id}") if(NOT "${_vn_id}" STREQUAL "") set(${_vn_id} "${_var_id}" PARENT_SCOPE) endif() if(NOT "${_vn_version_id}" STREQUAL "") set(${_vn_version_id} "${_var_version_id}" PARENT_SCOPE) endif() endfunction() endif(NOT DEFINED _os_release_info) gmmlib-intel-gmmlib-22.5.2/Source/inc/000077500000000000000000000000001466655022700174555ustar00rootroot00000000000000gmmlib-intel-gmmlib-22.5.2/Source/inc/common/000077500000000000000000000000001466655022700207455ustar00rootroot00000000000000gmmlib-intel-gmmlib-22.5.2/Source/inc/common/gfxmacro.h000066400000000000000000000361001466655022700227240ustar00rootroot00000000000000/*============================================================================== Copyright(c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ============================================================================*/ #ifndef __GFXMACRO_H__ #define __GFXMACRO_H__ #include #include // for memcpy #include // ### __GFXMACRO_ASSERT ###################################################### // Since an "always-callable" GFX_ASSERT/etc. is no longer really in-place, // this file will define its own assert statement... #if DBG #define __GFXMACRO_ASSERT(Expression) \ { \ if(!(Expression)) \ { \ __debugbreak(); \ } \ } // __GFXMACRO_ASSERT ################## #else // Release Build #define __GFXMACRO_ASSERT(Expression) #endif //------------------------------------------------------------------------ // Useful constants. #define GFX_ZERO (0.0f) #define GFX_HALF (0.5f) #define GFX_PI ((float) 3.14159265358979323846) #define GFX_SQR_ROOT_OF_TWO ((float) 1.41421356237309504880) #define GFX_E ((float) 2.7182818284590452354) //------------------------------------------------------------------------ // !!! Many of these are macros (instead of functions) so 64-bit friendly (even on 32-bit builds)!!! #define GFX_IS_ALIGNED(A, B) (((B) > 0) && (((A) % (B)) == 0)) #define GFX_ALIGN(x, a) (((x) + ((a) - 1)) - (((x) + ((a) - 1)) & ((a) - 1))) // Alt implementation with bitwise not (~) has issue with uint32 align used with 64-bit value, since ~'ed value will remain 32-bit. #define GFX_ALIGN_FLOOR(x, a) ((x) - ((x) & ((a) - 1))) #define GFX_ALIGN_NP2(x, a) (((a) > 0) ? ((x) + (((a) - 1) - (((x) + ((a) - 1)) % (a)))) : (x)) #define GFX_ALIGN_FLOOR_NP2(x, a) (((a) > 0) ? ((x) - ((x) % (a))) : (x)) #define GFX_MASK(lo,hi) ((1UL << (hi)) | \ ((1UL << (hi)) - \ (1UL << (lo)))) #define GFX_MASK_LARGE(lo,hi) (((uint64_t)1 << (hi)) | \ (((uint64_t)1 << (hi)) - \ ((uint64_t)1 << (lo)))) #define GFX_IS_POWER_OF_2(a) (((a) > 0) && !((a) & ((a) - 1))) #define GFX_SWAP_VAR(a,b,t) (t=a, a=b, b=t) #define GFX_SWAP_VAR3(a,b,c,t) (t=a, a=b, b=c, c=t) #define GFX_UF_ROUND(a) ((uint32_t) ((a) + 0.5F)) #define GFX_F_ROUND(a) ((int32_t) ((a) + ((a) < 0 ? -0.5F : 0.5F))) #define GFX_ABS(a) (((a) < 0) ? -(a) : (a)) #define GFX_MIN(a,b) (((a) < (b)) ? (a) : (b)) #define GFX_MAX(a,b) (((a) > (b)) ? (a) : (b)) #define GFX_MIN3(a,b,c) (((a) < (b)) ? GFX_MIN((a), (c)) : GFX_MIN((b), (c))) #define GFX_MAX3(a,b,c) (((a) > (b)) ? GFX_MAX((a), (c)) : GFX_MAX((b), (c))) #define GFX_CEIL_DIV(a,b) (((b) > 0) ? (((a) + ((b) - 1)) / (b)) : (a)) #define GFX_SQ(a) ((a) * (a)) #define GFX_CLAMP_MIN_MAX(a,min,max) ((a) < (min) ? (min) : GFX_MIN ((a), (max))) #define GFX_KB(k) ((k) * 1024) #define GFX_MB(m) ((m) * 1024 * 1024) //------------ Macros for setting and removing bits. #define GFX_BIT(n) (1UL << (n)) #define GFX_BIT_ON(a,bit) ((a) |= (bit)) #define GFX_BIT_OFF(a,bit) ((a) &= ~(bit)) #define GFX_IS_BIT_SET(a,bit) ((a) & (bit)) //***************************************************************************** // MACRO: GFX_BIT_RANGE // PURPOSE: Calculates the number of bits between the startbit and the endbit // and count is inclusive of both bits. The bits are 0 based. //***************************************************************************** #define GFX_BIT_RANGE(endbit, startbit) ((endbit)-(startbit)+1) //------------ Macros for dealing with void pointers #define GFX_VOID_PTR_INC(p,n) ((void *) ((char *)(p) + (n))) #define GFX_VOID_PTR_DEC(p,n) ((void *) ((char *)(p) - (n))) // While the difference of two pointers on a 64-bit machine can exceed // 32-bits, it is mostly limited to 32-bits for the graphics driver. In // order to avoid compilation warnings arising from assigning a 64-bit // quantity to a 32-bit lvalue, we have two separate macros for obtaining // pointer difference of two pointers. #define GFX_VOID_PTR_DIFF(a,b) (int32_t) ((char *) (a) - (char *) (b)) #define GFX_VOID_PTR_DIFF_LARGE(a,b) ((char *) (a) - (char *) (b)) //------------ Bytes to page conversion #define GFX_BYTES_TO_PAGES(b) (((b) + PAGE_SIZE - 1) / PAGE_SIZE) #define GFX_PAGES_TO_BYTES(p) ((p) * PAGE_SIZE) #define GFX_MEMSET(p,d,s) (memset(p, d, s)) #if DBG #define GFX_ULONG_CAST(x) \ ( \ ((x) <= 0xffffffff) ? \ 1 : __debugbreak(), \ (uint32_t)(x) \ ) #else // Release Build #define GFX_ULONG_CAST(x) ((uint32_t)(x)) #endif // Since hardware addresses are still 32 bits, we need a safe way // to convert 64 bit pointers into 32 bit hardware addresses. // ASSERT that the upper 32 bits are 0 before truncating address. #define GFX_VOID_PTR_TO_ULONG(ptr) ((uint32_t)(ptr)) //------------------------------------------------------------------------ // FAST FLOAT-TO_LONG CONVERSION // // We can convert floats to integers quickly by adding a floating-point // constant to an IEEE float so that the integer value of the IEEE float is // found in the least significant bits of the sum. We add 2^23 + 2^22, and // thus the number is represented in IEEE single-precision as // 2^23*(1.1xxxxxxx), where the first 1 is the implied one, the second is 1 . // // This technique has several limitations: // 1. It only works on values in the range [0,2^22-1]. // 2. It is subject to the processor rounding mode, which we assume to be // "round to nearest (even)". In this rounding mode, the conversion // yields round(x), not floor(x) as called for in C. // // It can be made to work on negative values with a little fixed point // trickery by: // result = ((LONG) (result ^ 0x00800000) << 8) >> 8, // // However, when the result is masked to a byte or a short and directly // assigned to the right type, no sign extension is required. // // The macros for -ve numbers since we use a constant of "1100" in binary // representation. The msb 1 is force it to be the implicit bit. The next // 1 is used for -ve numbers which will force other bits to be FFF.. // // which flips and then smears the sign bit into the rest of the number. The // intermediate values must be signed, so we do an arithmetic (fill with sign // bit) instead of logical shift. // // We approximate the floor operation by subtracting off 0.5 before doing the // round. This would work perfectly except that the processor breaks ties in // rounding be selecting the even value. Thus, we compute floor(1.0) as // round(0.5) = 0! Not good -- the caller must be careful to use // __GL_FLOAT_TO_LONG_TRUNC only in cases where he can live with this // behavior. #define GFX_FLOAT_TO_LONG_ROUND(ux,x,mask) \ { \ float fx; \ \ fx = x; \ fx += 0x00C00000; \ ux = mask & *(uint32_t *) &fx; \ } #define GFX_FLOAT_TO_LONG_TRUNC(ux,x,mask) \ { \ float fx; \ \ fx = x - GFX_HALF; \ fx += 0x00C00000; \ ux = mask & *(uint32_t *) &fx; \ } // Note: Double has 1 sign bit, 11 exponent and 52 mantissa bits. // We need to add the following constant for fast conversion // // fx += (__LONG64) 0x18000000000000; // // This is done in a portable/decipherable manner through // multiplications which are collapsed by the compiler at compile time. #define GFX_DOUBLE_TO_LONG_ROUND(ux,x,mask) \ { \ double fx; \ \ fx = x; \ fx += 24.0 * 1024.0 * 1024.0 * 1024.0 * 1024.0 * 256; \ ux = mask & *(uint32_t *) &fx; \ } #define GFX_DOUBLE_TO_LONG_TRUNC(ux,x,mask) \ { \ double fx; \ \ fx = x - GFX_HALF; \ fx += 24.0 * 1024.0 * 1024.0 * 1024.0 * 1024.0 * 256; \ ux = mask & *(uint32_t *) &fx; \ } #if __DEFINE_PROTO || defined __GFX_MACRO_C__ extern uint32_t GFX_LOG2 (uint32_t a); extern uint32_t GFX_REAL_TO_UBYTE (float a); extern int64_t GFX_POW2_SIZE (int64_t x); extern uint32_t GFX_2_TO_POWER_OF (uint32_t w); extern uint32_t GFX_MEMCPY_S(void *d, int dn, const void *s, int n); extern void* GFX_MEMCPY_S_INC(void *d, int dn, const void *s, int n); #endif // __DEFINE_PROTO #ifndef __S_INLINE #define __S_INLINE __inline #endif #if __DEFINE_MACRO || defined __GFX_MACRO_C__ //------------------------------------------------------------------------ __S_INLINE uint32_t GFX_LOG2 (uint32_t a) { long i = 1; while ((a >> i) > 0) { i++; } return (i - 1); } // Round-up to next power-of-2 __S_INLINE int64_t GFX_POW2_SIZE (int64_t x) { //-- Signed instead of unsigned since 64-bit is large enough that we don't need unsigned's range extension. int64_t Pow2Size; /* Algorithm: If there are no bits lit beneath the highest bit lit (HBL), the value is already a power-of-2 and needs no further rounding but if there are additional bits lit beneath the highest, the next higher power-of-2 is (1 << (HBL + 1)). To determine if there are bits lit beneath the HBL, we will subtract 1 from the given value before scanning for the HBL, and only if there are no lower bits lit will the subtraction reduce the HBL but in both cases, (1 << (HBL + 1)) will then produce the appropriately rounded-up (or not) power-of-2. */ if(x > 1) // <-- Since we bit-scan for (x - 1) and can't bit-scan zero. { #define MSB (sizeof(x) * CHAR_BIT - 1) uint32_t HighBit; { // HighBit = HighestBitLit(x - 1)... #if defined(__GNUC__) || defined(__clang__) { HighBit = MSB - __builtin_clzll(x - 1); } #else // Windows { #ifdef __CT__ { _BitScanReverse64((DWORD *)&HighBit, x - 1); } #else // Break into separate Upper/Lower scans... { #define UDW_1 ((int64_t) _UI32_MAX + 1) // <-- UpperDW Value of 1 (i.e. 0x00000001`00000000). if(x < UDW_1) { _BitScanReverse((DWORD *)&HighBit, GFX_ULONG_CAST(x - 1)); } else if(x > UDW_1) { _BitScanReverse((DWORD *)&HighBit, GFX_ULONG_CAST((x - 1) >> 32)); HighBit += 32; } else { HighBit = 31; } #undef UDW_1 } #endif } #endif } if(HighBit < (MSB - 1)) // <-- -1 since operating on signed type. { Pow2Size = (int64_t) 1 << (HighBit + 1); } else { __GFXMACRO_ASSERT(0); // Overflow! Pow2Size = 0; } #undef MSB } else { Pow2Size = 1; } return(Pow2Size); } // GFX_POW2_SIZE // Find 2 to the power of w __S_INLINE uint32_t GFX_2_TO_POWER_OF (uint32_t w) { __GFXMACRO_ASSERT(w < (sizeof(w) * CHAR_BIT)); // Assert no overflow. return(1UL << w); } __S_INLINE uint32_t GFX_REAL_TO_UBYTE (float a) { uint32_t x; GFX_FLOAT_TO_LONG_ROUND(x, a, 0xFF); return x; } __S_INLINE uint32_t GFX_MEMCPY_S(void *d, int dn, const void *s, int n) { uint32_t Error; // Check for the size, overlapping, etc. // Calling code responsibility to avoid overlap regions __GFXMACRO_ASSERT(n >= 0); __GFXMACRO_ASSERT( (((char*) d >= (char*) s) && ((ULONG_PTR)((char*) d - (char*) s) >= (ULONG_PTR) n) ) || (((char*) s >= (char*) d) && ((ULONG_PTR)((char*) s - (char*) d) >= (ULONG_PTR) n) )); #ifndef _WIN32 Error = 0; if(n <= dn) { memcpy(d, s, n); } else { Error = !Error; } #else Error = (uint32_t) memcpy_s(d, dn, s, n); #endif __GFXMACRO_ASSERT(!Error); return(Error); } __S_INLINE void* GFX_MEMCPY_S_INC(void *d, int dn, const void *s, int n) { GFX_MEMCPY_S(d, dn, s, n); return GFX_VOID_PTR_INC(d, n); } __S_INLINE uint32_t GFX_GET_NONZERO_BIT_COUNT(uint32_t bitMask) { uint32_t bitCount = 0; while(bitMask) { bitCount += bitMask & 0x1; bitMask >>= 1; } return bitCount; } #endif //#include // __readmsr should not be called for vGT cases, use __try __except to handle the // exception and assign it with hard coded values // isVGT flag will be set if it's being called from vGT. #define GFX_READ_MSR(pHwDevExt, value, reg, retParam) \ if(!gfx_read_msr((pHwDevExt), &(value), (reg))) return retParam; #define GFX_WRITE_MSR(pHwDevExt, reg, value, retParam)\ if(!gfx_write_msr((pHwDevExt), (value), (reg))) return retParam; #define GFX_READ_MSR_GOTO_LABEL_ON_ERROR(pHwDevExt, value, reg, label) \ if(!gfx_read_msr((pHwDevExt), &(value), (reg))) goto label; #define GFX_WRITE_MSR_GOTO_LABEL_ON_ERROR(pHwDevExt, reg, value, label)\ if(!gfx_write_msr((pHwDevExt), (value), (reg))) goto label; #endif // __GFXMACRO_H__ gmmlib-intel-gmmlib-22.5.2/Source/inc/common/gfxplatform.h000066400000000000000000000056601466655022700234560ustar00rootroot00000000000000/*============================================================================== Copyright(c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ============================================================================*/ #ifndef __GFXPLATFORM_H__ #define __GFXPLATFORM_H__ //////////////////////////////////////////////////////////////////////// // ABSTRACT: // Platform-specific constants, #defines, and // #includes. For the purposes of this header file, // a platform is defined as the combination of: // // - CPU Architecture // - C/C++ Compiler //////////////////////////////////////////////////////////////////////// #if _MSC_VER #pragma inline_depth (255) #endif // _MSC_VER #ifndef __S_INLINE #define __S_INLINE __inline #endif #ifndef __F_INLINE #ifdef _DEBUG #define __F_INLINE static #else #define __F_INLINE static __inline #endif #endif // Component definitions for ASSERT. #define GFX_GMM (uint32_t)0x00000020 #ifdef _DEBUG #define GFX_ASSERT(component,expr) \ {if (!(expr)) {__debugbreak();}} #else #define GFX_ASSERT(component,expr) #endif //======================================================================== // From winnt.h // // C_ASSERT() can be used to perform many COMPILE-TIME assertions: // type sizes, field offsets, etc. // // An assertion failure results in error C2118: negative subscript. // // When this assertion is to be used in the middle of a code block, // use it within {} - e.g. {GFX_C_ASSERT (GFX_NUM == 0);} #ifndef GFX_C_ASSERT #define GFX_C_ASSERT(e) typedef char GFX_C_ASSERT__[(e)?1:-1] #endif //======================================================================== // GFX_MMX_ALIGN: Alignment boundary (in bytes) for optimal use of // the MMX instruction set on IA32. #define GFX_MMX_ALIGN 8 #endif // #ifndef __GFXPLATFORM_H__ gmmlib-intel-gmmlib-22.5.2/Source/inc/common/gtsysinfo.h000066400000000000000000000327021466655022700231470ustar00rootroot00000000000000/*============================================================================== Copyright(c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ============================================================================*/ // This header file describes the GT system info data structure and associated // types and constants. It is for use by both producers and consumers of GT // system info on all OS. #ifndef __GT_SYS_INFO_H__ #define __GT_SYS_INFO_H__ #include #include #pragma pack(push,1) // Maximums which bound all supported GT #define GT_MAX_SLICE (8) #define GT_MAX_SUBSLICE_PER_SLICE (8) #define GT_MAX_SUBSLICE_PER_DSS (2) // Currently max value based on Gen12 #define GT_MAX_DUALSUBSLICE_PER_SLICE (6) // Currently max value based on Gen12LP typedef struct GT_SUBSLICE_INFO { bool Enabled; // determine if this SS is enabled. uint32_t EuEnabledCount; // Total Count of EU enabled on this SubSlice uint32_t EuEnabledMask; // Mask of EUs enabled on this SubSlice } GT_SUBSLICE_INFO; typedef struct GT_DUALSUBSLICE_INFO { bool Enabled; // Bool to determine if this SS is enabled. GT_SUBSLICE_INFO SubSlice[GT_MAX_SUBSLICE_PER_DSS]; // SS details that belong to this DualSubSlice. } GT_DUALSUBSLICE_INFO; typedef struct GT_SLICE_INFO { bool Enabled; // determine if this slice is enabled. GT_SUBSLICE_INFO SubSliceInfo[GT_MAX_SUBSLICE_PER_SLICE]; // SS details that belong to this slice. GT_DUALSUBSLICE_INFO DSSInfo[GT_MAX_DUALSUBSLICE_PER_SLICE]; // DSS details that belong to this slice. uint32_t SubSliceEnabledCount; // No. of SS enabled in this slice uint32_t DualSubSliceEnabledCount; // No. of DSS enabled in this slice } GT_SLICE_INFO; typedef struct GT_VEBOX_INFO { union VEBoxInstances { struct VEBitStruct { uint32_t VEBox0Enabled : 1; // To determine if VEBox0 is enabled uint32_t VEBox1Enabled : 1; // To determine if VEBox1 is enabled uint32_t VEBox2Enabled : 1; // To determine if VEBox2 is enabled uint32_t VEBox3Enabled : 1; // To determine if VEBox3 is enabled uint32_t Reserved : 28; // Reserved bits } Bits; uint32_t VEBoxEnableMask; // Union for all VEBox instances. It can be used to know if any of the VEBOX is enabled. } Instances; union { struct { uint32_t VEBox0 : 1; // Set if VEBox0 supports SFC uint32_t VEBox1 : 1; // Set if VEBox1 supports SFC uint32_t VEBox2 : 1; // Set if VEBox2 supports SFC uint32_t VEBox3 : 1; // Set if VEBox3 supports SFC uint32_t Reserved : 28; // Reserved bits }SfcSupportedBits; uint32_t Value; } SFCSupport; // VEBOX support of Scalar & Format Converter; uint32_t NumberOfVEBoxEnabled; // Number of bits set among bit 0-3 of VEBoxEnableMask; used on CNL bool IsValid; // flag to check if VEBoxInfo is valid. } GT_VEBOX_INFO; typedef struct GT_VDBOX_INFO { union VDBoxInstances { struct VDBitStruct { uint32_t VDBox0Enabled : 1; // To determine if VDBox0 is enabled uint32_t VDBox1Enabled : 1; // To determine if VDBox1 is enabled uint32_t VDBox2Enabled : 1; // To determine if VDBox2 is enabled uint32_t VDBox3Enabled : 1; // To determine if VDBox3 is enabled uint32_t VDBox4Enabled : 1; // To determine if VDBox4 is enabled uint32_t VDBox5Enabled : 1; // To determine if VDBox5 is enabled uint32_t VDBox6Enabled : 1; // To determine if VDBox6 is enabled uint32_t VDBox7Enabled : 1; // To determine if VDBox7 is enabled uint32_t Reserved : 24; // Reserved bits } Bits; uint32_t VDBoxEnableMask; // Union for all VDBox instances. It can be used to know if any of the VDBOX is enabled. } Instances; union { struct { uint32_t VDBox0 : 1; // Set if VDBox0 supports SFC uint32_t VDBox1 : 1; // Set if VDBox1 supports SFC uint32_t VDBox2 : 1; // Set if VDBox2 supports SFC uint32_t VDBox3 : 1; // Set if VDBox3 supports SFC uint32_t VDBox4 : 1; // Set if VDBox4 supports SFC uint32_t VDBox5 : 1; // Set if VDBox5 supports SFC uint32_t VDBox6 : 1; // Set if VDBox6 supports SFC uint32_t VDBox7 : 1; // Set if VDBox7 supports SFC uint32_t Reserved : 24; // Reserved bits }SfcSupportedBits; uint32_t Value; } SFCSupport; // VDBOX support of Scalar & Format Converter; uint32_t NumberOfVDBoxEnabled; // Number of bits set among bit 0-7 of VDBoxEnableMask; bool IsValid; // flag to check if VDBoxInfo is valid. } GT_VDBOX_INFO; typedef struct GT_CCS_INFO { union CCSInstances { struct CCSBitStruct { uint32_t CCS0Enabled : 1; // To determine if CCS0 is enabled uint32_t CCS1Enabled : 1; uint32_t CCS2Enabled : 1; uint32_t CCS3Enabled : 1; uint32_t Reserved : 28; // Reserved bits } Bits; uint32_t CCSEnableMask; // Union for all CCS instances. It can be used to know which CCS is enabled. } Instances; uint32_t NumberOfCCSEnabled; // Number of bits set among bit 0-3 of CCSEnableMask; bool IsValid; // flag to check if CCSInfo is valid. } GT_CCS_INFO; typedef struct GT_MULTI_TILE_ARCH_INFO { // Total Count of Tiles enabled uint8_t TileCount; // Mask of all enabled Tiles union { struct { uint8_t Tile0 : 1; uint8_t Tile1 : 1; uint8_t Tile2 : 1; uint8_t Tile3 : 1; uint8_t Reserved : 4; }; uint8_t TileMask; }; // flag to check if MultiTileArchInfo has valid data or not bool IsValid; } GT_MULTI_TILE_ARCH_INFO; typedef struct GT_SQIDI_INFO { uint32_t NumberofSQIDI; // Total no. of enabled SQIDIs. uint32_t NumberofDoorbellPerSQIDI; // Total no. of doorbells available per SQIDI unit }GT_SQIDI_INFO; typedef union _GT_CACHE_TYPES { struct { uint32_t L3 : 1; uint32_t LLC : 1; uint32_t eDRAM : 1; uint32_t Reserved : 29; }; uint32_t CacheTypeMask; } GT_CACHE_TYPES; typedef struct GT_SYSTEM_INFO { // These fields should always hold valid values uint32_t EUCount; // Total no. of enabled EUs uint32_t ThreadCount; // total no of system threads available uint32_t SliceCount; // Total no. of enabled slices uint32_t SubSliceCount; // Total no. of enabled subslices uint32_t DualSubSliceCount; // Total no. of enabled dualsubslices uint64_t L3CacheSizeInKb; // Total L3 cache size in kilo bytes uint64_t LLCCacheSizeInKb; // Total LLC cache size in kilo bytes uint64_t EdramSizeInKb; // Total EDRAM size in kilo bytes uint32_t L3BankCount; // Total L3 banks across all slices. This is not bank count per slice. uint32_t MaxFillRate; // Fillrate with Alphablend (in Pix/Clk) uint32_t EuCountPerPoolMax; // Max EU count per pool uint32_t EuCountPerPoolMin; // Min EU count per pool uint32_t TotalVsThreads; // Total threads in VS uint32_t TotalHsThreads; // Total threads in HS uint32_t TotalDsThreads; // Total threads in DS uint32_t TotalGsThreads; // Total threads in GS uint32_t TotalPsThreadsWindowerRange; // Total threads in PS Windower Range uint32_t TotalVsThreads_Pocs; // Total threads in VS for POCS // Note: The CSR size requirement is not clear at this moment. Till then the driver will set // the maximum size that should be sufficient for all platform SKUs. uint32_t CsrSizeInMb; // Total size that driver needs to allocate for CSR. /*------------------------------------*/ // Below fields are required for proper allocation of scratch/private space for threads execution. // Threads scratch space has to be allocated based on native die config. So allocation has to be // done even for unfused or non-enabled slices/subslices/EUs. Since H/W doesn't provide us a way to know // about the native die config S/W will allocate based on max EU/S/SS. uint32_t MaxEuPerSubSlice; // Max available EUs per sub-slice. uint32_t MaxSlicesSupported; // Max slices this platfrom can have. uint32_t MaxSubSlicesSupported; // Max total sub-slices this platform can have (not per slice) uint32_t MaxDualSubSlicesSupported; // Max total dual sub-slices this platform can have (not per slice) /*------------------------------------*/ // Flag to determine if hashing is enabled. If enabled then one of the L3 banks will be disabled. // As a result 'L3BankCount' will be reduced by 1 bank during system info derivation routine. // Note: Only expected only in CNL (limited SKUs). bool IsL3HashModeEnabled; // VEBox/VDBox info GT_VDBOX_INFO VDBoxInfo; // VDBoxInfo provides details(enabled/disabled) of all VDBox instances. GT_VEBOX_INFO VEBoxInfo; // VEBoxInfo provides details(enabled/disabled) of all VEBox instances. // SliceInfo provides the detailed breakdown of the Slice/Subslice/EU configuration. It is useful // for various WA that depend on the specific SSEU components enabled or disabled, but it is not // considered critically important to driver function at this time and may not be validly populated // on all platforms. IsDynamicallyPopulated indicates if SliceInfo has been validly populated. // IsDynamicallyPopulated only applies to SliceInfo. // TODO: Rename IsDynamicallyPopulated to something like SliceInfoIsValid to help clarify its // purpose. At the moment we are constrained by USC not to make any changes to the GT System // Info interface which require USC changes. USC currently references IsDynamicallyPopulated. GT_SLICE_INFO SliceInfo[GT_MAX_SLICE]; bool IsDynamicallyPopulated; //SqidiInfo provides the detailed information for number of SQIDIs supported in GT. //It also provides total no. of doorbells available per SQIDI unit. GT_SQIDI_INFO SqidiInfo; uint32_t ReservedCCSWays; // Reserved CCS ways provides value of reserved L3 ways for CCS when CCS is enabled. // This is a hardcoded value as suggested by HW. No MMIO read is needed for same. GT_CCS_INFO CCSInfo; // CCSInfo provides details(enabled/disabled) of all CCS instances. GT_MULTI_TILE_ARCH_INFO MultiTileArchInfo; // MultiTileArchInfo provides details(enabled/disabled) of GT Tiles in case of Multi Tile Architecture SKUs uint32_t NumThreadsPerEu; // Number of threads per EU. GT_CACHE_TYPES CacheTypes; // Types of caches available on system (L3/LLC/eDRAM). uint32_t MaxVECS; // Max VECS instances. uint32_t MemoryType; // GT_MEMORY_TYPES - type of memory supported in current platform uint32_t SLMSizeInKb; // SLM Size } GT_SYSTEM_INFO, *PGT_SYSTEM_INFO; #pragma pack(pop) #endif //__GT_SYS_INFO_H__ gmmlib-intel-gmmlib-22.5.2/Source/inc/common/igfxfmid.h000066400000000000000000003213571466655022700227260ustar00rootroot00000000000000/*============================================================================== Copyright(c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ============================================================================ ** ** File Name : igfxfmid.h ** ** Abastract : Family IDs for device abstraction ** ** Authors : Ken Stevens ** ** Environment : Win9x and WinNT builds. ** ** Items in File : Family IDs for Intel Graphics Controllers ** ** ---------------------------------------------------------------------- */ #ifndef __IGFXFMID_H__ #define __IGFXFMID_H__ typedef enum { IGFX_UNKNOWN = 0, IGFX_GRANTSDALE_G, IGFX_ALVISO_G, IGFX_LAKEPORT_G, IGFX_CALISTOGA_G, IGFX_BROADWATER_G, IGFX_CRESTLINE_G, IGFX_BEARLAKE_G, IGFX_CANTIGA_G, IGFX_CEDARVIEW_G, IGFX_EAGLELAKE_G, IGFX_IRONLAKE_G, IGFX_GT, IGFX_IVYBRIDGE, IGFX_HASWELL, IGFX_VALLEYVIEW, IGFX_BROADWELL, IGFX_CHERRYVIEW, IGFX_SKYLAKE, IGFX_KABYLAKE, IGFX_COFFEELAKE, IGFX_WILLOWVIEW, IGFX_BROXTON, IGFX_GEMINILAKE, IGFX_CANNONLAKE, IGFX_ICELAKE, IGFX_ICELAKE_LP, IGFX_LAKEFIELD, IGFX_JASPERLAKE, IGFX_ELKHARTLAKE =IGFX_JASPERLAKE, IGFX_TIGERLAKE_LP, IGFX_ROCKETLAKE, IGFX_ALDERLAKE_S, IGFX_ALDERLAKE_P, IGFX_ALDERLAKE_N, IGFX_DG1 = 1210, IGFX_XE_HP_SDV = 1250, IGFX_DG2 = 1270, IGFX_PVC = 1271, IGFX_METEORLAKE = 1272, IGFX_ARROWLAKE = 1273, IGFX_BMG = 1274, IGFX_LUNARLAKE = 1275, IGFX_MAX_PRODUCT, IGFX_GENNEXT = 0x7ffffffe, PRODUCT_FAMILY_FORCE_ULONG = 0x7fffffff } PRODUCT_FAMILY; typedef enum { PCH_UNKNOWN = 0, PCH_IBX, // Ibexpeak PCH_CPT, // Cougarpoint, PCH_CPTR, // Cougarpoint Refresh, PCH_PPT, // Panther Point PCH_LPT, // Lynx Point PCH_LPTR, // Lynx Point Refresh PCH_WPT, // Wildcat point PCH_SPT, // PCH_KBP, // Kabylake PCH PCH_CNP_LP, // Cannonlake LP PCH PCH_CNP_H, // Cannonlake Halo PCH PCH_ICP_LP, // ICL LP PCH PCH_ICP_N, // ICL N PCH PCH_LKF, // LKF PCH PCH_TGL_LP, // TGL LP PCH PCH_CMP_LP, // CML LP PCH PCH_CMP_H, // CML Halo PCH PCH_CMP_V, // CML V PCH PCH_JSP_N, // JSL N PCH Device IDs for JSL+ Rev02 PCH_ADL_S, // ADL_S PCH PCH_ADL_P, // ADL_P PCH PCH_TGL_H, // TGL H PCH PCH_ADL_N, // ADL_N PCHDL PCH_MTL, // MTL PCH PCH_ARL, // ARL PCH PCH_PRODUCT_FAMILY_FORCE_ULONG = 0x7fffffff } PCH_PRODUCT_FAMILY; typedef enum { IGFX_UNKNOWN_CORE = 0, IGFX_GEN3_CORE = 1, //Gen3 Family IGFX_GEN3_5_CORE = 2, //Gen3.5 Family IGFX_GEN4_CORE = 3, //Gen4 Family IGFX_GEN4_5_CORE = 4, //Gen4.5 Family IGFX_GEN5_CORE = 5, //Gen5 Family IGFX_GEN5_5_CORE = 6, //Gen5.5 Family IGFX_GEN5_75_CORE = 7, //Gen5.75 Family IGFX_GEN6_CORE = 8, //Gen6 Family IGFX_GEN7_CORE = 9, //Gen7 Family IGFX_GEN7_5_CORE = 10, //Gen7.5 Family IGFX_GEN8_CORE = 11, //Gen8 Family IGFX_GEN9_CORE = 12, //Gen9 Family IGFX_GEN10_CORE = 13, //Gen10 Family IGFX_GEN10LP_CORE = 14, //Gen10 LP Family IGFX_GEN11_CORE = 15, //Gen11 Family IGFX_GEN11LP_CORE = 16, //Gen11 LP Family IGFX_GEN12_CORE = 17, //Gen12 Family IGFX_GEN12LP_CORE = 18, //Gen12 LP Family IGFX_XE_HP_CORE = 0x0c05, //XE_HP family IGFX_XE_HPG_CORE = 0x0c07, // XE_HPG Family IGFX_XE_HPC_CORE = 0x0c08, // XE_HPC Family IGFX_XE2_LPG_CORE = 0x0c09, // XE2_LPG Family IGFX_XE2_HPG_CORE = IGFX_XE2_LPG_CORE, //XE2_HPG Family //Please add new GENs BEFORE THIS ! IGFX_MAX_CORE, IGFX_GENNEXT_CORE = 0x7ffffffe, //GenNext GFXCORE_FAMILY_FORCE_ULONG = 0x7fffffff } GFXCORE_FAMILY; typedef enum { IGFX_SKU_NONE = 0, // IGFX_SKU_UNKNOWN defined in \opengl\source\desktop\ail\ailgl_profiles.h IGFX_SKU_ULX = 1, IGFX_SKU_ULT = 2, IGFX_SKU_T = 3, IGFX_SKU_ALL = 0xff } PLATFORM_SKU; typedef enum __GTTYPE { GTTYPE_GT1 = 0x0, GTTYPE_GT2, GTTYPE_GT2_FUSED_TO_GT1, GTTYPE_GT2_FUSED_TO_GT1_6, //IVB GTTYPE_GTL, // HSW GTTYPE_GTM, // HSW GTTYPE_GTH, // HSW GTTYPE_GT1_5,//HSW GTTYPE_GT1_75,//HSW GTTYPE_GT3,//BDW GTTYPE_GT4,//BDW GTTYPE_GT0,//BDW GTTYPE_GTA,// BXT GTTYPE_GTC,// BXT GTTYPE_GTX, // BXT GTTYPE_GT2_5,//CNL GTTYPE_GT3_5,//SKL GTTYPE_GT0_5,//CNL GTTYPE_UNDEFINED,//Always at the end. }GTTYPE, *PGTTYPE; ///////////////////////////////////////////////////////////////// // // Platform types which are used during Sku/Wa initialization. // #ifndef _COMMON_PPA typedef enum { PLATFORM_NONE = 0x00, PLATFORM_DESKTOP = 0x01, PLATFORM_MOBILE = 0x02, PLATFORM_TABLET = 0X03, PLATFORM_ALL = 0xff, // flag used for applying any feature/WA for All platform types } PLATFORM_TYPE; #endif typedef struct PLATFORM_STR { PRODUCT_FAMILY eProductFamily; PCH_PRODUCT_FAMILY ePCHProductFamily; GFXCORE_FAMILY eDisplayCoreFamily; GFXCORE_FAMILY eRenderCoreFamily; #ifndef _COMMON_PPA PLATFORM_TYPE ePlatformType; #endif unsigned short usDeviceID; unsigned short usRevId; unsigned short usDeviceID_PCH; unsigned short usRevId_PCH; // GT Type // Note: Is valid only till Gen9. From Gen10 SKUs are not identified by any GT flags. 'GT_SYSTEM_INFO' should be used instead. GTTYPE eGTType; } PLATFORM; // add enums at the end typedef enum __SKUIDTYPE { SKU_FULL_TYPE = 0x0, SKU_VALUE_TYPE, SKU_PLUS_FULL_TYPE, SKU_PLUS_VALUE_TYPE, SKU_T_TYPE, SKU_PLUS_T_TYPE, SKU_P_TYPE, SKU_PLUS_P_TYPE, SKU_SMALL_TYPE, SKU_LIGHT_TYPE, SKU_N_TYPE }SKUIDTYPE, *PSKUIDTYPE; typedef enum __CPUTYPE { CPU_UNDEFINED = 0x0, CPU_CORE_I3, CPU_CORE_I5, CPU_CORE_I7, CPU_PENTIUM, CPU_CELERON, CPU_CORE, CPU_VPRO, CPU_SUPER_SKU, CPU_ATOM, CPU_CORE1, CPU_CORE2, CPU_WS, CPU_SERVER, CPU_CORE_I5_I7, CPU_COREX1_4, CPU_ULX_PENTIUM, CPU_MB_WORKSTATION, CPU_DT_WORKSTATION, CPU_M3, CPU_M5, CPU_M7, CPU_MEDIA_SERVER //Added for KBL }CPUTYPE, *PCPUTYPE; // the code below convert platform real revision number to pre-defined revision number, the revision will be set as follow // REVISION_A0 - this will include all incarnations for A stepping in all packages types A = {A0} // REVISION_A1 - this will include all incarnations for A stepping in all packages types A = {A1} // REVISION_A3 - this will include all incarnations for A stepping in all packages types A = {A3,...,A7} // REVISION_B - this will include all incarnations for B stepping in all packages types B = {B0,B1,..,B7} // REVISION_C - this will include all incarnations for C stepping in all packages types C = {C0,C1,..,C7} // REVISION_D - this will include all incarnations for C stepping in all packages types C = {D0,D1} // REVISION_K - this will include all incarnations for K stepping in all packages types K = {K0,K1,..,K7} typedef enum __REVID { REVISION_A0 = 0, REVISION_A1, //1 REVISION_A3,//2 REVISION_B,//3 REVISION_C,//4 REVISION_D,//5 REVISION_K//6 }REVID, *PREVID; typedef enum __NATIVEGTTYPE { NATIVEGTTYPE_HSW_UNDEFINED = 0x00, NATIVEGTTYPE_HSW_GT1 = 0x01, NATIVEGTTYPE_HSW_GT2 = 0x02, NATIVEGTTYPE_HSW_GT3 = 0x03, }NATIVEGTTYPE; // Following macros return true/false depending on the current PCH family #define PCH_IS_PRODUCT(p, r) ( (p).ePCHProductFamily == r ) #define PCH_GET_CURRENT_PRODUCT(p) ( (p).ePCHProductFamily ) // These macros return true/false depending on current product/core family. #define GFX_IS_PRODUCT(p, r) ( (p).eProductFamily == r ) #define GFX_IS_DISPLAYCORE(p, d) ( (p).eDisplayCoreFamily == d ) #define GFX_IS_RENDERCORE(p, r) ( (p).eRenderCoreFamily == r ) // These macros return the current product/core family enum. // Relational compares () should not be done when using GFX_GET_CURRENT_PRODUCT // macro. There are no relationships between the PRODUCT_FAMILY enum values. #define GFX_GET_CURRENT_PRODUCT(p) ( (p).eProductFamily ) #define GFX_GET_CURRENT_DISPLAYCORE(p) ( (p).eDisplayCoreFamily ) #define GFX_GET_CURRENT_RENDERCORE(p) ( (p).eRenderCoreFamily ) // This macro returns true if the product family is discrete #define GFX_IS_DISCRETE_PRODUCT(pf) ( ( pf == IGFX_DG1 ) || \ ( pf == IGFX_DG2 ) || \ ( pf == IGFX_XE_HP_SDV ) || \ ( pf == IGFX_BMG ) ) #define GFX_IS_DISCRETE_FAMILY(p) GFX_IS_DISCRETE_PRODUCT(GFX_GET_CURRENT_PRODUCT(p)) #define GFX_IS_INTEGRATED_PRODUCT(pf) (!GFX_IS_DISCRETE_PRODUCT(pf)) #define GFX_IS_INTEGRATED_FAMILY(p) (!GFX_IS_DISCRETE_FAMILY(p)) // These macros return true/false depending on the current render family. #define GFX_IS_NAPA_RENDER_FAMILY(p) ( ( GFX_GET_CURRENT_RENDERCORE(p) == IGFX_GEN3_CORE ) || \ ( GFX_GET_CURRENT_RENDERCORE(p) == IGFX_GEN3_5_CORE ) ) #define GFX_IS_GEN_RENDER_FAMILY(p) ( ( GFX_GET_CURRENT_RENDERCORE(p) == IGFX_GEN4_CORE ) || \ ( GFX_GET_CURRENT_RENDERCORE(p) == IGFX_GEN4_5_CORE ) || \ ( GFX_GET_CURRENT_RENDERCORE(p) == IGFX_GEN5_CORE ) || \ ( GFX_GET_CURRENT_RENDERCORE(p) == IGFX_GEN5_5_CORE ) || \ ( GFX_GET_CURRENT_RENDERCORE(p) == IGFX_GEN5_75_CORE ) || \ ( GFX_GET_CURRENT_RENDERCORE(p) == IGFX_GEN6_CORE ) || \ ( GFX_GET_CURRENT_RENDERCORE(p) == IGFX_GEN7_CORE ) || \ ( GFX_GET_CURRENT_RENDERCORE(p) == IGFX_GEN7_5_CORE ) || \ ( GFX_GET_CURRENT_RENDERCORE(p) == IGFX_GEN8_CORE ) || \ ( GFX_GET_CURRENT_RENDERCORE(p) == IGFX_GEN9_CORE ) || \ ( GFX_GET_CURRENT_RENDERCORE(p) == IGFX_GEN10_CORE ) || \ ( GFX_GET_CURRENT_RENDERCORE(p) == IGFX_GEN11_CORE ) || \ ( GFX_GET_CURRENT_RENDERCORE(p) == IGFX_GEN12_CORE ) || \ ( GFX_GET_CURRENT_RENDERCORE(p) == IGFX_XE_HP_CORE ) || \ ( GFX_GET_CURRENT_RENDERCORE(p) == IGFX_XE_HPG_CORE ) || \ ( GFX_GET_CURRENT_RENDERCORE(p) == IGFX_XE_HPC_CORE ) || \ ( GFX_GET_CURRENT_RENDERCORE(p) == IGFX_XE2_HPG_CORE ) || \ ( GFX_GET_CURRENT_RENDERCORE(p) == IGFX_GENNEXT_CORE ) ) #define GFX_IS_GEN_5_OR_LATER(p) ( ( GFX_GET_CURRENT_RENDERCORE(p) == IGFX_GEN5_CORE ) || \ ( GFX_GET_CURRENT_RENDERCORE(p) == IGFX_GEN5_5_CORE ) || \ ( GFX_GET_CURRENT_RENDERCORE(p) == IGFX_GEN5_75_CORE ) || \ ( GFX_GET_CURRENT_RENDERCORE(p) == IGFX_GEN6_CORE ) || \ ( GFX_GET_CURRENT_RENDERCORE(p) == IGFX_GEN7_CORE ) || \ ( GFX_GET_CURRENT_RENDERCORE(p) == IGFX_GEN7_5_CORE ) || \ ( GFX_GET_CURRENT_RENDERCORE(p) == IGFX_GEN8_CORE ) || \ ( GFX_GET_CURRENT_RENDERCORE(p) == IGFX_GEN9_CORE ) || \ ( GFX_GET_CURRENT_RENDERCORE(p) == IGFX_GEN10_CORE ) || \ ( GFX_GET_CURRENT_RENDERCORE(p) == IGFX_GEN11_CORE ) || \ ( GFX_GET_CURRENT_RENDERCORE(p) == IGFX_GEN12_CORE ) || \ ( GFX_GET_CURRENT_RENDERCORE(p) == IGFX_XE_HP_CORE ) || \ ( GFX_GET_CURRENT_RENDERCORE(p) == IGFX_XE_HPG_CORE ) || \ ( GFX_GET_CURRENT_RENDERCORE(p) == IGFX_XE_HPC_CORE ) || \ ( GFX_GET_CURRENT_RENDERCORE(p) == IGFX_XE2_HPG_CORE ) || \ ( GFX_GET_CURRENT_RENDERCORE(p) == IGFX_GENNEXT_CORE ) ) #define GFX_IS_GEN_5_75_OR_LATER(p) ( ( GFX_GET_CURRENT_RENDERCORE(p) == IGFX_GEN5_75_CORE ) || \ ( GFX_GET_CURRENT_RENDERCORE(p) == IGFX_GEN6_CORE ) || \ ( GFX_GET_CURRENT_RENDERCORE(p) == IGFX_GEN7_CORE ) || \ ( GFX_GET_CURRENT_RENDERCORE(p) == IGFX_GEN7_5_CORE ) || \ ( GFX_GET_CURRENT_RENDERCORE(p) == IGFX_GEN8_CORE ) || \ ( GFX_GET_CURRENT_RENDERCORE(p) == IGFX_GEN9_CORE ) || \ ( GFX_GET_CURRENT_RENDERCORE(p) == IGFX_GEN10_CORE ) || \ ( GFX_GET_CURRENT_RENDERCORE(p) == IGFX_GEN11_CORE ) || \ ( GFX_GET_CURRENT_RENDERCORE(p) == IGFX_GEN12_CORE ) || \ ( GFX_GET_CURRENT_RENDERCORE(p) == IGFX_XE_HP_CORE ) || \ ( GFX_GET_CURRENT_RENDERCORE(p) == IGFX_XE_HPG_CORE ) || \ ( GFX_GET_CURRENT_RENDERCORE(p) == IGFX_XE_HPC_CORE ) || \ ( GFX_GET_CURRENT_RENDERCORE(p) == IGFX_XE2_HPG_CORE ) || \ ( GFX_GET_CURRENT_RENDERCORE(p) == IGFX_GENNEXT_CORE ) ) #define GFX_IS_GEN_6_OR_LATER(p) ( ( GFX_GET_CURRENT_RENDERCORE(p) == IGFX_GEN6_CORE ) || \ ( GFX_GET_CURRENT_RENDERCORE(p) == IGFX_GEN7_CORE ) || \ ( GFX_GET_CURRENT_RENDERCORE(p) == IGFX_GEN7_5_CORE ) || \ ( GFX_GET_CURRENT_RENDERCORE(p) == IGFX_GEN8_CORE ) || \ ( GFX_GET_CURRENT_RENDERCORE(p) == IGFX_GEN9_CORE ) || \ ( GFX_GET_CURRENT_RENDERCORE(p) == IGFX_GEN10_CORE ) || \ ( GFX_GET_CURRENT_RENDERCORE(p) == IGFX_GEN11_CORE ) || \ ( GFX_GET_CURRENT_RENDERCORE(p) == IGFX_XE_HP_CORE ) || \ ( GFX_GET_CURRENT_RENDERCORE(p) == IGFX_XE_HPG_CORE ) || \ ( GFX_GET_CURRENT_RENDERCORE(p) == IGFX_XE_HPC_CORE ) || \ ( GFX_GET_CURRENT_RENDERCORE(p) == IGFX_XE2_HPG_CORE ) || \ ( GFX_GET_CURRENT_RENDERCORE(p) == IGFX_GENNEXT_CORE ) ) #define GFX_IS_GEN_7_OR_LATER(p) ( ( GFX_GET_CURRENT_RENDERCORE(p) == IGFX_GEN7_CORE ) || \ ( GFX_GET_CURRENT_RENDERCORE(p) == IGFX_GEN7_5_CORE ) || \ ( GFX_GET_CURRENT_RENDERCORE(p) == IGFX_GEN8_CORE ) || \ ( GFX_GET_CURRENT_RENDERCORE(p) == IGFX_GEN9_CORE ) || \ ( GFX_GET_CURRENT_RENDERCORE(p) == IGFX_GEN10_CORE ) || \ ( GFX_GET_CURRENT_RENDERCORE(p) == IGFX_GEN11_CORE ) || \ ( GFX_GET_CURRENT_RENDERCORE(p) == IGFX_GEN12_CORE ) || \ ( GFX_GET_CURRENT_RENDERCORE(p) == IGFX_XE_HP_CORE ) || \ ( GFX_GET_CURRENT_RENDERCORE(p) == IGFX_XE_HPG_CORE ) || \ ( GFX_GET_CURRENT_RENDERCORE(p) == IGFX_XE_HPC_CORE ) || \ ( GFX_GET_CURRENT_RENDERCORE(p) == IGFX_XE2_HPG_CORE ) || \ ( GFX_GET_CURRENT_RENDERCORE(p) == IGFX_GENNEXT_CORE ) ) #define GFX_IS_GEN_7_5_OR_LATER(p) ( ( GFX_GET_CURRENT_RENDERCORE(p) == IGFX_GEN7_5_CORE ) || \ ( GFX_GET_CURRENT_RENDERCORE(p) == IGFX_GEN8_CORE ) || \ ( GFX_GET_CURRENT_RENDERCORE(p) == IGFX_GEN9_CORE ) || \ ( GFX_GET_CURRENT_RENDERCORE(p) == IGFX_GEN10_CORE ) || \ ( GFX_GET_CURRENT_RENDERCORE(p) == IGFX_GEN11_CORE ) || \ ( GFX_GET_CURRENT_RENDERCORE(p) == IGFX_GEN12_CORE ) || \ ( GFX_GET_CURRENT_RENDERCORE(p) == IGFX_XE_HP_CORE ) || \ ( GFX_GET_CURRENT_RENDERCORE(p) == IGFX_XE_HPG_CORE ) || \ ( GFX_GET_CURRENT_RENDERCORE(p) == IGFX_XE_HPC_CORE ) || \ ( GFX_GET_CURRENT_RENDERCORE(p) == IGFX_GENNEXT_CORE ) ) #define GFX_IS_GEN_8_OR_LATER(p) ( ( GFX_GET_CURRENT_RENDERCORE(p) == IGFX_GEN8_CORE ) || \ ( GFX_GET_CURRENT_RENDERCORE(p) == IGFX_GEN9_CORE ) || \ ( GFX_GET_CURRENT_RENDERCORE(p) == IGFX_GEN10_CORE ) || \ ( GFX_GET_CURRENT_RENDERCORE(p) == IGFX_GEN11_CORE ) || \ ( GFX_GET_CURRENT_RENDERCORE(p) == IGFX_GEN12_CORE ) || \ ( GFX_GET_CURRENT_RENDERCORE(p) == IGFX_XE_HP_CORE ) || \ ( GFX_GET_CURRENT_RENDERCORE(p) == IGFX_XE_HPG_CORE ) || \ ( GFX_GET_CURRENT_RENDERCORE(p) == IGFX_XE_HPC_CORE ) || \ ( GFX_GET_CURRENT_RENDERCORE(p) == IGFX_GENNEXT_CORE ) ) #define GFX_IS_GEN_8_CHV_OR_LATER(p) ( ( GFX_GET_CURRENT_PRODUCT(p) == IGFX_CHERRYVIEW ) || \ ( GFX_GET_CURRENT_RENDERCORE(p) == IGFX_GEN9_CORE ) || \ ( GFX_GET_CURRENT_RENDERCORE(p) == IGFX_GEN10_CORE ) || \ ( GFX_GET_CURRENT_RENDERCORE(p) == IGFX_GEN11_CORE ) || \ ( GFX_GET_CURRENT_RENDERCORE(p) == IGFX_GEN12_CORE ) || \ ( GFX_GET_CURRENT_RENDERCORE(p) == IGFX_XE_HP_CORE ) || \ ( GFX_GET_CURRENT_RENDERCORE(p) == IGFX_XE_HPG_CORE ) || \ ( GFX_GET_CURRENT_RENDERCORE(p) == IGFX_XE_HPC_CORE ) || \ ( GFX_GET_CURRENT_RENDERCORE(p) == IGFX_GENNEXT_CORE ) ) #define GFX_IS_GEN_9_OR_LATER(p) ( ( GFX_GET_CURRENT_RENDERCORE(p) == IGFX_GEN9_CORE ) || \ ( GFX_GET_CURRENT_RENDERCORE(p) == IGFX_GEN10_CORE ) || \ ( GFX_GET_CURRENT_RENDERCORE(p) == IGFX_GEN11_CORE ) || \ ( GFX_GET_CURRENT_RENDERCORE(p) == IGFX_GEN12_CORE ) || \ ( GFX_GET_CURRENT_RENDERCORE(p) == IGFX_XE_HPG_CORE ) || \ ( GFX_GET_CURRENT_RENDERCORE(p) == IGFX_XE_HP_CORE ) || \ ( GFX_GET_CURRENT_RENDERCORE(p) == IGFX_XE_HPC_CORE ) || \ ( GFX_GET_CURRENT_RENDERCORE(p) == IGFX_GENNEXT_CORE ) ) #define GFX_IS_GEN_10_OR_LATER(p) (( GFX_GET_CURRENT_RENDERCORE(p) == IGFX_GEN10_CORE ) || \ ( GFX_GET_CURRENT_RENDERCORE(p) == IGFX_GEN11_CORE ) || \ ( GFX_GET_CURRENT_RENDERCORE(p) == IGFX_GEN12_CORE ) || \ ( GFX_GET_CURRENT_RENDERCORE(p) == IGFX_XE_HP_CORE ) || \ ( GFX_GET_CURRENT_RENDERCORE(p) == IGFX_XE_HPG_CORE ) || \ ( GFX_GET_CURRENT_RENDERCORE(p) == IGFX_XE_HPC_CORE ) || \ ( GFX_GET_CURRENT_RENDERCORE(p) == IGFX_GENNEXT_CORE ) ) #define GFX_IS_GEN_11_OR_LATER(p) (( GFX_GET_CURRENT_RENDERCORE(p) == IGFX_GEN11_CORE ) || \ ( GFX_GET_CURRENT_RENDERCORE(p) == IGFX_GEN12_CORE ) || \ ( GFX_GET_CURRENT_RENDERCORE(p) == IGFX_XE_HP_CORE ) || \ ( GFX_GET_CURRENT_RENDERCORE(p) == IGFX_XE_HPG_CORE ) || \ ( GFX_GET_CURRENT_RENDERCORE(p) == IGFX_XE_HPC_CORE ) || \ ( GFX_GET_CURRENT_RENDERCORE(p) == IGFX_GENNEXT_CORE ) ) #define GFX_IS_GEN_12_OR_LATER(p) (( GFX_GET_CURRENT_RENDERCORE(p) >= IGFX_GEN12_CORE )) #define GFX_IS_ATOM_PRODUCT_FAMILY(p) ( GFX_IS_PRODUCT(p, IGFX_VALLEYVIEW) || \ GFX_IS_PRODUCT(p, IGFX_CHERRYVIEW) || \ GFX_IS_PRODUCT(p, IGFX_BROXTON) ) /////////////////////////////////////////////////////////////////// // // macros for comparing Graphics family and products // /////////////////////////////////////////////////////////////////// #define GFX_IS_FAMILY_EQUAL_OR_ABOVE(family1, family2) ((family1)>=(family2) ? true : false) #define GFX_IS_FAMILY_EQUAL_OR_BELOW(family1, family2) ((family1)<=(family2) ? true : false) #define GFX_IS_FAMILY_BELOW(family1, family2) ((family1)<(family2) ? true : false) #define GFX_IS_PRODUCT_EQUAL_OR_ABOVE(product1, product2) ((product1)>=(product2) ? true : false) #define GFX_IS_PRODUCT_EQUAL_OR_BELOW(product1, product2) ((product1)<=(product2) ? true : false) #define GFX_IS_PRODUCT_BELOW(product1, product2) ((product1) <(product2) ? true : false) //Feature ID: Graphics PRD PC11.0 - Brookdale-G Support //Description: Move device and vendor ID's to igfxfmid.h. // Add #include "igfxfmid.h". //Other Files Modified: dispconf.c, kcconfig.c, kchmisc.c, kchsys.c, // driver.h, igfxfmid.h, imdefs.h, kchialm.h, kchname.h, softbios.h, // swbios.h, vddcomm.h, vidmini.h #define INTEL_VENDOR_ID 0x8086 // Intel Corporation //Device IDs #define UNKNOWN_DEVICE_ID 0xFFFF // Unknown device #define IALM_DEVICE0_ID_M 0x3575 #define IALM_DEVICE0_ID_MG 0x3578 #define IALM_DEVICE1_ID 0x3576 #define IALM_DEVICE_ID 0x3577 // Almador Base #define BROOKDALE_G_DEVICE_ID 0x2562 // Brookdale_G #define IMGM_DEVICE_ID 0x3582 // MontaraGM Base #define IMGM_DEVICE0_ID 0x3580 #define ISDG_DEVICE0_ID 0x2570 // Springdale-G Device 0 ID #define ISDG_DEVICE1_ID 0x2571 // Springdale-G Device 1 ID #define ISDG_DEVICE2_ID 0x2572 // Springdale-G Device 2 ID #define ISDG_DEVICE_ID ISDG_DEVICE2_ID // Springdale-G Graphics Controller Device ID #define IGDG_DEVICE_F0_ID 0x2582 // Grantsdale-G graphics function 0 ID #define IGDG_DEVICE_F1_ID 0x2782 // Grantsdale-G graphics function 1 ID #define IALG_DEVICE_F0_ID 0x2592 // Alviso-G , function 0 #define IALG_DEVICE_F1_ID 0x2792 // Alviso-G , function 1 #define ILPG_DEVICE_F0_ID 0x2772 // Lakeport-G graphics function 0 ID #define ILPG_DEVICE_F1_ID 0x2776 // Lakeport-G graphics function 1 ID #define ICLG_DEVICE_F0_ID 0x27A2 // Calistoga-G graphics function 0 ID #define ICLG_DEVICE_F1_ID 0x27A6 // Calistoga-G graphics function 1 ID #define ICLG_GME_DEVICE_F0_ID 0x27AE // Calistoga-G graphics function 0 ID for GME SKU #define IBWG_DEVICE_F0_ID 0x2982 // Broadwater-G graphics function 0 ID #define IBWG_DEVICE_F1_ID 0x2983 // Broadwater-G graphics function 1 ID #define IBWG_GQ_DEVICE_F0_ID 0x2992 // Broadwater-GQ graphics function 0 ID #define IBWG_GQ_DEVICE_F1_ID 0x2993 // Broadwater-GQ graphics function 1 ID #define IBWG_GC_DEVICE_F0_ID 0x29A2 // Broadwater-GC graphics function 0 ID #define IBWG_GC_DEVICE_F1_ID 0x29A3 // Broadwater-GC graphics function 1 ID #define IBWG_GV_DEVICE_F0_ID 0x2972 // Broadwater-GL/GZ graphics function 0 ID #define IBWG_GV_DEVICE_F1_ID 0x2973 // Broadwater-GL/GZ graphics function 1 ID #define ICRL_DEVICE_F0_ID 0x2A02 // Crestline-G graphics function 0 ID #define ICRL_DEVICE_F1_ID 0x2A03 // Crestline-G graphics function 1 ID #define ICRL_GME_DEVICE_F0_ID 0x2A12 // Crestline-G graphics function 0 ID for GME SKU #define ICRL_GME_DEVICE_F1_ID 0x2A13 // Crestline-G graphics function 1 ID for GME SKU #define IBLK_GBA_DEVICE_F0_ID 0x29C2 // BearLake-GBA graphics function 0 ID #define IBLK_GBA_DEVICE_F1_ID 0x29C3 // BearLake-GBA graphics function 1 ID #define IBLK_GBB_DEVICE_F0_ID 0x29B2 // BearLake-GBB Corporate skew graphics function 0 ID #define IBLK_GBB_DEVICE_F1_ID 0x29B3 // BearLake-GBB Corporate skew graphics function 1 ID #define IBLK_GBC_DEVICE_F0_ID 0x29D2 // BearLake-GBC graphics function 0 ID #define IBLK_GBC_DEVICE_F1_ID 0x29D3 // BearLake-GBC graphics function 1 ID #define ICTG_DEVICE_F0_ID 0x2A42 // Cantiga-G graphics function 0 ID #define ICTG_DEVICE_F1_ID 0x2A43 // Cantiga-G graphics function 1 ID #define ICDV_DEVICE_F0_ID 0x0BE0 // CDV graphics function 0 ID #define ICDV_DEVICE_F0_ID_MASK 0xFFF0 // Mask of Penwell_D graphics function 0 ID. Bits [3:0] // are used to identify SKU from B1 QS #define IELK_DEVICE_SUPER_SKU_F0_ID 0x2E02 // EagleLake-G graphics function 0 ID for Super SKU #define IELK_DEVICE_SUPER_SKU_F1_ID 0x2E03 // EagleLake-G graphics function 1 ID for Super SKU #define IELK_DEVICE_Q45_Q43_SKU_F0_ID 0x2E12 // EagleLake-G graphics function 0 ID for Q45 and Q43 SKUs #define IELK_DEVICE_Q45_Q43_SKU_F1_ID 0x2E13 // EagleLake-G graphics function 1 ID for Q45 and Q43 SKUs #define IELK_DEVICE_G45_G43_P45_SKU_F0_ID 0x2E22 // EagleLake-G graphics function 0 ID for G45, G43 and P45 SKUs #define IELK_DEVICE_G45_G43_P45_SKU_F1_ID 0x2E23 // EagleLake-G graphics function 1 ID for G45, G43 and P45 SKUs #define IELK_DEVICE_G41_SKU_F0_ID 0x2E32 // EagleLake-G graphics function 0 ID for G41 SKU #define IELK_DEVICE_G41_SKU_F1_ID 0x2E33 // EagleLake-G graphics function 1 ID for G41 SKU #define IELK_DEVICE_F0_ID 0x2E02 // EagleLake-G graphics function 0 ID #define IELK_DEVICE_F1_ID 0x2E03 // EagleLake-G graphics function 1 ID #define IELK_DEVICE_Q45_F0_ID 0x2E12 // EagleLake-G graphics Corporate function 0 ID #define IELK_DEVICE_Q45_F1_ID 0x2E13 // EagleLake-G graphics Corporate function 1 ID #define IELK_DEVICE_Q43_F0_ID 0x2E22 // EagleLake-G graphics Corporate function 0 ID #define IELK_DEVICE_Q43_F1_ID 0x2E23 // EagleLake-G graphics Corporate function 1 ID #define IELK_DEVICE_G45_F0_ID 0x2E32 // EagleLake-G graphics function 0 ID #define IELK_DEVICE_G45_F1_ID 0x2E33 // EagleLake-G graphics function 1 ID #define IELK_DEVICE_G43_F0_ID 0x2E42 // EagleLake-G graphics function 0 ID #define IELK_DEVICE_G43_F1_ID 0x2E43 // EagleLake-G graphics function 1 ID #define IELK_DEVICE_B43_SKU_F0_ID 0x2E42 // EagleLake-G graphics function 0 ID #define IELK_DEVICE_B43_SKU_F1_ID 0x2E43 // EagleLake-G graphics function 1 ID #define IELK_DEVICE_G41_F0_ID 0x2E52 // EagleLake-G graphics function 0 ID #define IELK_DEVICE_G41_F1_ID 0x2E53 // EagleLake-G graphics function 1 ID #define IELK_DEVICE_P45_F0_ID 0x2E62 // EagleLake-G graphics function 0 ID #define IELK_DEVICE_P45_F1_ID 0x2E63 // EagleLake-G graphics function 1 ID #define IELK_DEVICE_P43_F0_ID 0x2E72 // EagleLake-G graphics function 0 ID #define IELK_DEVICE_P43_F1_ID 0x2E73 // EagleLake-G graphics function 1 ID #define IELK_DEVICE_B43_UPGRD_F0_ID 0x2E92 // EagleLake-G graphics function 0 ID #define IELK_DEVICE_B43_UPGRD_F1_ID 0x2E93 // EagleLake-G graphics function 0 ID #define IILK_DESK_DEVICE_F0_ID 0x0042 // IronLake-G Desktop graphics function 0 ID #define IILK_MOBL_DEVICE_F0_ID 0x0046 // IronLake-G Mobile graphics function 0 ID #define IGT_DESK_DEVICE_GT1_ID 0x0102 // GT / SandyBridge Desktop GT1 ID #define IGT_MOBL_DEVICE_GT1_ID 0x0106 // GT / SandyBridge Mobile GT1 ID #define IGT_DESK_SERVER_DEVICE_ID 0x010A // GT / SandyBridge Server ID #define IGT_DESK_DEVICE_GT2_ID 0x0112 // GT / SandyBridge Desktop GT2 ID #define IGT_MOBL_DEVICE_GT2_ID 0x0116 // GT / SandyBridge Mobile GT2 ID #define IGT_DESK_DEVICE_GT_PLUS_ID 0x0122 // GT / SandyBridge Desktop GT2+ ID #define IGT_MOBL_DEVICE_GT_PLUS_ID 0x0126 // GT / SandyBridge Mobile GT2+ ID #define IGT_DESK_VERSATILE_ACCELERATION_MODE_ID 0x010B //GT / SandyBridge Versatile Acceleration Mode. Desk/Mobl?? //ivb issue366162 #define IIVB_DESK_DEVICE_F0_ID 0x0162 // IVB Desktop graphics function 0 ID #define IIVB_DESK_SERVER_DEVICE_ID 0x016A // IVB Server graphics function 0 ID #define IIVB_MOBL_DEVICE_F0_ID 0x0166 // IVB Mobile graphics function 0 ID #define IIVB_GT1_DESK_DEVICE_F0_ID 0x0152 // IVB Desktop graphics function 0 ID #define IIVB_GT1_DESK_SERVER_DEVICE_ID 0x015A // IVB Server graphics function 0 ID #define IIVB_GT1_MOBL_DEVICE_F0_ID 0x0156 // IVB Mobile graphics function 0 ID //ivb placeholder #define IIVB_GT2p_DESK_DEVICE_F0_ID 0x0172 #define IIVB_GT2p_MOBL_DEVICE_F0_ID 0x0176 #define IIVB_GT16_DESK_DEVICE_F0_ID 0x0182 #define IIVB_GT16_MOBL_DEVICE_F0_ID 0x0186 #define IIVB_GT2_XEON_DEVICE_F0_ID 0x016A //HSW TEMP #define IHSW_GTH_DESK_DEVICE_F0_ID 0x0090 // HSW Desktop graphics function 0 ID #define IHSW_GTM_DESK_DEVICE_F0_ID 0x0091 #define IHSW_GTL_DESK_DEVICE_F0_ID 0x0092 #define IHSW_DESK_DEV_F0_ID 0x0C02 // HSW Desktop Device ID #define IHSW_MOBL_DEV_F0_ID 0x0C06 // HSW Mobile Device ID #define IHSW_DESK_DEV_F0_M_ID 0x0C12 // HSW Desktop Device ID GT - M SKU. #define IHSW_MOBL_DEV_F0_M_ID 0x0C16 // HSW Mobile Device ID GT - M SKU. #define IHSW_DESK_DEV_F0_H_ID 0x0C22 // HSW Desktop Device ID GT - H SKU. #define IHSW_MOBL_DEV_F0_H_ID 0x0C26 // HSW Mobile Device ID GT - H SKU. #define IHSW_VA_DEV_F0_ID 0x0C0B // HSW Mobile Device ID GT - H SKU. #define IHSW_MOBL_DEVICE_F0_ID 0x0094 // Not used currently //HSW - client #define IHSW_CL_DESK_GT1_DEV_ID 0x402 //CLIENT Desktop - GT1 #define IHSW_CL_MOBL_GT1_DEV_ID 0x406 //CLIENT Mobile - GT1 #define IHSW_CL_SERV_GT1_DEV_ID 0x40A //CLIENT Server - GT1 #define IHSW_CL_DESK_GT2_DEV_ID 0x412 #define IHSW_CL_MOBL_GT2_DEV_ID 0x416 #define IHSW_CL_WS_GT2_DEV_ID 0x41B // Use for WS GT2 SKU, not confirmed #define IHSW_CL_SERV_GT2_DEV_ID 0x41A #define IHSW_CL_MRKT_GT1_5_DEV_ID 0x41E // Use for GT1.5w/12EUs AKA GT2.12 //HSW - ULT #define IHSW_ULT_MOBL_GT1_DEV_ID 0xA06 #define IHSW_ULT_MOBL_GT2_DEV_ID 0xA16 //Mob ULT GT1.5 and GT2 #define IHSW_ULT_MOBL_GT3_DEV_ID 0xA26 #define IHSW_ULT_MRKT_GT3_DEV_ID 0xA2E // HSW - ULX #define IHSW_ULX_MOBL_GT1_DEV_ID 0xA0E #define IHSW_ULX_MOBL_GT2_DEV_ID 0xA1E //Mob ULX GT1.5 and GT2 //HSW - CRW #define IHSW_CRW_DESK_GT2_DEV_ID 0xD12 #define IHSW_CRW_MOBL_GT2_DEV_ID 0xD16 #define IHSW_CRW_DESK_GT3_DEV_ID 0xD22 #define IHSW_CRW_MOBL_GT3_DEV_ID 0xD26 #define IHSW_CRW_SERV_GT3_DEV_ID 0xD2A //VLV device ids #define IVLV_DESK_DEVICE_F0_ID 0x0F32 #define IVLV_MOBL_DEVICE_F0_ID 0x0F30 // VLV Mobile graphics function 0 ID //VLV Plus device ids #define IVLV_PLUS_DESK_DEVICE_F0_ID 0x0F33 #define IVLV_PLUS_MOBL_DEVICE_F0_ID 0x0F31 // VLV Plus Mobile graphics function 0 ID //CHV device ids #define ICHV_MOBL_DEVICE_F0_ID 0x22B0 // CHV TABLET i.e CHT #define ICHV_PLUS_MOBL_DEVICE_F0_ID 0x22B1 // Essential i.e Braswell #define ICHV_DESK_DEVICE_F0_ID 0x22B2 // Reserved #define ICHV_PLUS_DESK_DEVICE_F0_ID 0x22B3 // Reserved //BDW device ids #define IBDW_GT1_HALO_MOBL_DEVICE_F0_ID 0x1602 #define IBDW_GT1_ULT_MOBL_DEVICE_F0_ID 0x1606 #define IBDW_GT1_RSVD_DEVICE_F0_ID 0x160B #define IBDW_GT1_SERV_DEVICE_F0_ID 0x160A #define IBDW_GT1_WRK_DEVICE_F0_ID 0x160D #define IBDW_GT1_ULX_DEVICE_F0_ID 0x160E #define IBDW_GT2_HALO_MOBL_DEVICE_F0_ID 0x1612 #define IBDW_GT2_ULT_MOBL_DEVICE_F0_ID 0x1616 #define IBDW_GT2_RSVD_DEVICE_F0_ID 0x161B #define IBDW_GT2_SERV_DEVICE_F0_ID 0x161A #define IBDW_GT2_WRK_DEVICE_F0_ID 0x161D #define IBDW_GT2_ULX_DEVICE_F0_ID 0x161E #define IBDW_GT3_HALO_MOBL_DEVICE_F0_ID 0x1622 #define IBDW_GT3_ULT_MOBL_DEVICE_F0_ID 0x1626 #define IBDW_GT3_ULT25W_MOBL_DEVICE_F0_ID 0x162B //This is actually 28w #define IBDW_GT3_SERV_DEVICE_F0_ID 0x162A #define IBDW_GT3_WRK_DEVICE_F0_ID 0x162D #define IBDW_GT3_ULX_DEVICE_F0_ID 0x162E #define IBDW_RSVD_MRKT_DEVICE_F0_ID 0x1632 #define IBDW_RSVD_ULT_MOBL_DEVICE_F0_ID 0x1636 #define IBDW_RSVD_HALO_MOBL_DEVICE_F0_ID 0x163B #define IBDW_RSVD_SERV_DEVICE_F0_ID 0x163A #define IBDW_RSVD_WRK_DEVICE_F0_ID 0x163D #define IBDW_RSVD_ULX_DEVICE_F0_ID 0x163E //skl placeholder #define ISKL_GT4_DT_DEVICE_F0_ID 0x1932 #define ISKL_GT2_DT_DEVICE_F0_ID 0x1912 // Used on actual Silicon #define ISKL_GT1_DT_DEVICE_F0_ID 0x1902 #define ISKL_GT2_ULT_DEVICE_F0_ID 0x1916 #define ISKL_GT2F_ULT_DEVICE_F0_ID 0x1921 #define ISKL_GT3e_ULT_DEVICE_F0_ID_540 0x1926 #define ISKL_GT3e_ULT_DEVICE_F0_ID_550 0x1927 #define ISKL_GT2_ULX_DEVICE_F0_ID 0x191E #define ISKL_GT1_ULT_DEVICE_F0_ID 0x1906 #define ISKL_GT3_MEDIA_SERV_DEVICE_F0_ID 0x192D #define ISKL_GT1_5_ULT_DEVICE_F0_ID 0x1913 #define ISKL_GT3_ULT_DEVICE_F0_ID 0x1923 #define ISKL_GT2_HALO_MOBL_DEVICE_F0_ID 0x191B #define ISKL_GT4_HALO_MOBL_DEVICE_F0_ID 0x193B #define ISKL_GT4_SERV_DEVICE_F0_ID 0x193A #define ISKL_GT2_WRK_DEVICE_F0_ID 0x191D #define ISKL_GT4_WRK_DEVICE_F0_ID 0x193D #define ISKL_GT0_DESK_DEVICE_F0_ID 0x0900 #define ISKL_GT1_DESK_DEVICE_F0_ID 0x0901 #define ISKL_GT2_DESK_DEVICE_F0_ID 0x0902 #define ISKL_GT3_DESK_DEVICE_F0_ID 0x0903 #define ISKL_GT4_DESK_DEVICE_F0_ID 0x0904 #define ISKL_GT1_ULX_DEVICE_F0_ID 0x190E //SKL strings to be be deleted in future #define ISKL_GT1_HALO_MOBL_DEVICE_F0_ID 0x190B #define ISKL_GT1_SERV_DEVICE_F0_ID 0x190A #define ISKL_GT1_5_ULX_DEVICE_F0_ID 0x1915 #define ISKL_GT1_5_DT_DEVICE_F0_ID 0x1917 #define ISKL_GT2_SERV_DEVICE_F0_ID 0x191A #define ISKL_LP_DEVICE_F0_ID 0x9905 #define ISKL_GT3_HALO_MOBL_DEVICE_F0_ID 0x192B #define ISKL_GT3_SERV_DEVICE_F0_ID 0x192A #define ISKL_GT0_MOBL_DEVICE_F0_ID 0xFFFF // KabyLake Device ids #define IKBL_GT1_ULT_DEVICE_F0_ID 0x5906 #define IKBL_GT1_5_ULT_DEVICE_F0_ID 0x5913 #define IKBL_GT2_ULT_DEVICE_F0_ID 0x5916 #define IKBL_GT2F_ULT_DEVICE_F0_ID 0x5921 #define IKBL_GT2_R_ULX_DEVICE_F0_ID 0x591C #define IKBL_GT3_15W_ULT_DEVICE_F0_ID 0x5926 //#define IKBL_GT3E_ULT_DEVICE_F0_ID 0x5926 #define IKBL_GT1_ULX_DEVICE_F0_ID 0x590E #define IKBL_GT1_5_ULX_DEVICE_F0_ID 0x5915 #define IKBL_GT2_ULX_DEVICE_F0_ID 0x591E #define IKBL_GT1_DT_DEVICE_F0_ID 0x5902 #define IKBL_GT2_R_ULT_DEVICE_F0_ID 0x5917 #define IKBL_GT2_DT_DEVICE_F0_ID 0x5912 #define IKBL_GT1_HALO_DEVICE_F0_ID 0x590B #define IKBL_GT1F_HALO_DEVICE_F0_ID 0x5908 #define IKBL_GT2_HALO_DEVICE_F0_ID 0x591B #define IKBL_GT4_HALO_DEVICE_F0_ID 0x593B #define IKBL_GT1_SERV_DEVICE_F0_ID 0x590A #define IKBL_GT2_SERV_DEVICE_F0_ID 0x591A #define IKBL_GT2_WRK_DEVICE_F0_ID 0x591D #define IKBL_GT3_ULT_DEVICE_F0_ID 0x5923 #define IKBL_GT3_28W_ULT_DEVICE_F0_ID 0x5927 //keeping the below ids as its been used in linux . need to be removed once removed from linux files. #define IKBL_GT4_DT_DEVICE_F0_ID 0x5932 #define IKBL_GT3_HALO_DEVICE_F0_ID 0x592B #define IKBL_GT3_SERV_DEVICE_F0_ID 0x592A #define IKBL_GT4_SERV_DEVICE_F0_ID 0x593A #define IKBL_GT4_WRK_DEVICE_F0_ID 0x593D //GLK Device ids #define IGLK_GT2_ULT_18EU_DEVICE_F0_ID 0x3184 #define IGLK_GT2_ULT_12EU_DEVICE_F0_ID 0x3185 //GWL #define IGWL_GT1_MOB_DEVICE_F0_ID 0xFF0F //For Pre-Si, temp #define IBXT_A_DEVICE_F0_ID 0x9906 #define IBXT_C_DEVICE_F0_ID 0x9907 #define IBXT_X_DEVICE_F0_ID 0x9908 //BXT BIOS programmed Silicon ids #define IBXT_GT_3x6_DEVICE_ID 0x0A84 #define IBXT_PRO_3x6_DEVICE_ID 0x1A84 //18EU #define IBXT_PRO_12EU_3x6_DEVICE_ID 0x1A85 //12 EU #define IBXT_P_3x6_DEVICE_ID 0x5A84 //18EU APL #define IBXT_P_12EU_3x6_DEVICE_ID 0x5A85 //12EU APL #define ICNL_3x8_DESK_DEVICE_F0_ID 0x0A01 #define ICNL_5x8_DESK_DEVICE_F0_ID 0x0A02 #define ICNL_9x8_DESK_DEVICE_F0_ID 0x0A05 #define ICNL_13x8_DESK_DEVICE_F0_ID 0x0A07 // CNL Si device ids #define ICNL_5x8_ULX_DEVICE_F0_ID 0x5A51 //GT2 #define ICNL_5x8_ULT_DEVICE_F0_ID 0x5A52 //GT2 #define ICNL_4x8_ULT_DEVICE_F0_ID 0x5A5A //GT1.5 #define ICNL_3x8_ULT_DEVICE_F0_ID 0x5A42 //GT1 #define ICNL_2x8_ULT_DEVICE_F0_ID 0x5A4A //GT0.5 #define ICNL_9x8_ULT_DEVICE_F0_ID 0x5A62 #define ICNL_9x8_SUPERSKU_DEVICE_F0_ID 0x5A60 #define ICNL_5x8_SUPERSKU_DEVICE_F0_ID 0x5A50 //GT2 #define ICNL_1x6_5x8_SUPERSKU_DEVICE_F0_ID 0x5A40 //GTx #define ICNL_5x8_HALO_DEVICE_F0_ID 0x5A54 //GT2 #define ICNL_3x8_HALO_DEVICE_F0_ID 0x5A44 //GT1 #define ICNL_5x8_DESKTOP_DEVICE_F0_ID 0x5A55 #define ICNL_3x8_DESKTOP_DEVICE_F0_ID 0x5A45 #define ICNL_4x8_ULX_DEVICE_F0_ID 0x5A59 //GT1.5 #define ICNL_3x8_ULX_DEVICE_F0_ID 0x5A41 //GT1 #define ICNL_2x8_ULX_DEVICE_F0_ID 0x5A49 //GT0.5 #define ICNL_4x8_HALO_DEVICE_F0_ID 0x5A5C //GT1.5 #define ICNL_2x8_HALO_DEVICE_F0_ID 0x5A4C //GT0.5 //CFL #define ICFL_GT1_DT_DEVICE_F0_ID 0x3E90 #define ICFL_GT2_DT_DEVICE_F0_ID 0x3E92 #define ICFL_GT1_S61_DT_DEVICE_F0_ID 0x3E90 #define ICFL_GT1_S41_DT_DEVICE_F0_ID 0x3E93 #define ICFL_GT2_S62_DT_DEVICE_F0_ID 0x3E92 #define ICFL_GT2_HALO_DEVICE_F0_ID 0x3E9B #define ICFL_GT2_SERV_DEVICE_F0_ID 0x3E96 #define ICFL_GT2_HALO_WS_DEVICE_F0_ID 0x3E94 #define ICFL_GT2_S42_DT_DEVICE_F0_ID 0x3E91 #define ICFL_GT3_ULT_15W_DEVICE_F0_ID 0x3EA6 #define ICFL_GT3_ULT_15W_42EU_DEVICE_F0_ID 0x3EA7 #define ICFL_GT3_ULT_28W_DEVICE_F0_ID 0x3EA8 #define ICFL_GT3_ULT_DEVICE_F0_ID 0x3EA5 #define ICFL_HALO_DEVICE_F0_ID 0x3E95 #define ICFL_GT2_S8_S2_DT_DEVICE_F0_ID 0x3E98 #define ICFL_GT1_S6_S4_S2_F1F_DT_DEVICE_F0_ID 0x3E99 #define ICFL_GT2_S82_S6F2_DT_DEVICE_F0_ID 0x3E9A #define ICFL_GT2_U42F_U2F2_ULT_DEVICE_F0_ID 0x3EA0 #define ICFL_GT1_U41F_U2F1F_ULT_DEVICE_F0_ID 0x3EA1 #define ICFL_GT3_U43_ULT_DEVICE_F0_ID 0x3EA2 #define ICFL_GT2_U42F_U2F1F_ULT_DEVICE_F0_ID 0x3EA3 #define ICFL_GT1_41F_2F1F_ULT_DEVICE_F0_ID 0x3EA4 #define ICFL_GT2_U42F_U2F2F_ULT_DEVICE_F0_ID 0x3EA9 //CML- continue to follow CFL Macro #define ICFL_GT2_ULT_DEVICE_V0_ID 0x9B41 #define ICFL_GT1_ULT_DEVICE_V0_ID 0x9B21 #define ICFL_GT2_ULT_DEVICE_A0_ID 0x9BCA #define ICFL_GT1_ULT_DEVICE_A0_ID 0x9BAA #define ICFL_GT2_ULT_DEVICE_S0_ID 0x9BCB #define ICFL_GT1_ULT_DEVICE_S0_ID 0x9BAB #define ICFL_GT2_ULT_DEVICE_K0_ID 0x9BCC #define ICFL_GT1_ULT_DEVICE_K0_ID 0x9BAC #define ICFL_GT2_ULX_DEVICE_S0_ID 0x9BC0 #define ICFL_GT1_ULX_DEVICE_S0_ID 0x9BA0 #define ICFL_GT2_DT_DEVICE_P0_ID 0x9BC5 #define ICFL_GT1_DT_DEVICE_P0_ID 0x9BA5 #define ICFL_GT2_DT_DEVICE_G0_ID 0x9BC8 #define ICFL_GT1_DT_DEVICE_G0_ID 0x9BA8 #define ICFL_GT2_WKS_DEVICE_P0_ID 0x9BC6 #define ICFL_GT2_WKS_DEVICE_G0_ID 0x9BE6 #define ICFL_GT2_HALO_DEVICE_15_ID 0x9BC4 #define ICFL_GT1_HALO_DEVICE_16_ID 0x9BA4 #define ICFL_GT2_HALO_DEVICE_17_ID 0x9BC2 #define ICFL_GT1_HALO_DEVICE_18_ID 0x9BA2 // PCH related definitions #define PCH_IBX_DESK_DEVICE_FULL_ID 0x3B00 #define PCH_IBX_DESK_DEVICE_P55_ID 0x3B02 #define PCH_IBX_DESK_DEVICE_H55_ID 0x3B06 #define PCH_IBX_DESK_DEVICE_H57_ID 0x3B08 #define PCH_IBX_DESK_DEVICE_Q57_ID 0x3B0A #define PCH_IBX_MOBL_DEVICE_FULL_ID 0x3B01 #define PCH_IBX_MOBL_DEVICE_PM55_ID 0x3B03 #define PCH_IBX_MOBL_DEVICE_QM57_ID 0x3B07 #define PCH_IBX_MOBL_DEVICE_HM55_ID 0x3B09 #define PCH_IBX_MOBL_DEVICE_HM57_ID 0x3B0B #define PCH_IBX_MOBL_DEVICE_SFF_FULL_ID 0x3B0D #define PCH_IBX_DEVICE_QS57_ID 0x3B0F #define PCH_IBX_DEVICE_3400_ID 0x3B12 #define PCH_IBX_DEVICE_3420_ID 0x3B14 #define PCH_IBX_DEVICE_3450_ID 0x3B16 #define PCH_CPT_UNFUSED_PART_DEV_ID 0x1C40 #define PCH_CPT_DESKTOP_SUPER_SKU_DEV_ID 0x1C42 #define PCH_CPT_MOBL_SUPER_SKU_DEV_ID 0x1C43 #define PCH_CPT_DESKTOP_DH_SKU_DEV_ID 0x1C44 #define PCH_CPT_DESKTOP_DO_SKU_DEV_ID 0x1C46 #define PCH_CPT_MOBL_DO_SKU_DEV_ID 0x1C47 #define PCH_CPT_DESKTOP_R_SKU_DEV_ID 0x1C48 #define PCH_CPT_MOBL_ENHANCED_SKU_DEV_ID 0x1C49 #define PCH_CPT_DESKTOP_BASE_SKU_DEV_ID 0x1C4A #define PCH_CPT_MOBL_BASE_SKU_DEV_ID 0x1C4B #define PCH_CPT_Q65_SKU_DEV_ID 0x1C4C #define PCH_CPT_QS67_SKU_DEV_ID 0x1C4D #define PCH_CPT_Q67_SKU_DEV_ID 0x1C4E #define PCH_CPT_QM67_SKU_DEV_ID 0x1C4F #define PCH_CPT_B65_SKU_DEV_ID 0x1C50 #define PCH_CPT_ESSENTIAL_SKU_DEV_ID 0x1C52 #define PCH_CPT_STANDARD_SKU_DEV_ID 0x1C54 #define PCH_CPT_ADVANCED_SKU_DEV_ID 0x1C56 #define PCH_CPT_B65_SKU_LEVEL_III_DEV_ID 0x1C58 #define PCH_CPT_HM67_SKU_LEVEL_III_DEV_ID 0x1C59 #define PCH_CPT_Q67_SKU_LEVEL_I_DEV_ID 0x1C5A #define PCH_CPT_H61_SKU_LEVEL_I_DEV_ID 0x1C5C // CPT Refresh Device IDs.. #define PCH_CPT_REF_RSVD1_DEV_ID 0x1CC0 //Reserved for future use #define PCH_CPT_REF_MOB_SFF_SUPER_DEV_ID 0x1CC1 #define PCH_CPT_REF_MOB_SUPER_DEV_ID 0x1CC2 #define PCH_CPT_REF_RSVD2_DEV_ID 0x1CC3 //Reserved for future use #define PCH_CPT_REF_QM77_DEV_ID 0x1CC4 #define PCH_CPT_REF_QS77_DEV_ID 0x1CC5 #define PCH_CPT_REF_HM77_DEV_ID 0x1CC6 #define PCH_CPT_REF_UM77_DEV_ID 0x1CC7 #define PCH_CPT_REF_HM75_DEV_ID 0x1CC8 #define PCH_CPT_REF_HM75_RAID_RST_DEV_ID 0x1CC9 #define PCH_CPT_REF_UM77_RAID_RST_DEV_ID 0x1CCA #define PCH_CPT_REF_HM77_MNG_DEV_ID 0x1CCB #define PCH_CPT_REF_RSVD3_DEV_ID 0x1CCC #define PCH_CPT_REF_RSVD4_DEV_ID 0x1CCD #define PCH_CPT_REF_RSVD5_DEV_ID 0x1CCE #define PCH_CPT_REF_RSVD6_DEV_ID 0x1CCF #define PCH_CPT_REF_RSVD7_DEV_ID 0x1CD0 #define PCH_CPT_REF_RSVD8_DEV_ID 0x1CD1 #define PCH_CPT_REF_RSVD9_DEV_ID 0x1CD2 #define PCH_CPT_REF_RSVD10_DEV_ID 0x1CD3 #define PCH_CPT_REF_RSVD11_DEV_ID 0x1CD4 #define PCH_CPT_REF_RSVD12_DEV_ID 0x1CD5 #define PCH_CPT_REF_RSVD13_DEV_ID 0x1CD6 #define PCH_CPT_REF_RSVD14_DEV_ID 0x1CD7 #define PCH_CPT_REF_RSVD15_DEV_ID 0x1CD8 #define PCH_CPT_REF_RSVD16_DEV_ID 0x1CD9 #define PCH_CPT_REF_RSVD17_DEV_ID 0x1CDA #define PCH_CPT_REF_RSVD18_DEV_ID 0x1CDB #define PCH_CPT_REF_RSVD19_DEV_ID 0x1CDC #define PCH_CPT_REF_RSVD20_DEV_ID 0x1CDD #define PCH_CPT_REF_RSVD21_DEV_ID 0x1CDE #define PCH_CPT_REF_RSVD22_DEV_ID 0x1CDF //PPT Device IDs.. #define PCH_PPT_DEV_ID 0x1E40 #define PCH_PPT_DESK_SUPER_DEV_ID 0x1E41 #define PCH_PPT_MOB_SUPER_DEV_ID 0x1E42 #define PCH_PPT_MOB_SFF_SUPER_DEV_ID 0x1E43 #define PCH_PPT_Z7x_DEV_ID 0x1E44 #define PCH_PPT_H71_DEV_ID 0x1E45 #define PCH_PPT_P77_DEV_ID 0x1E46 #define PCH_PPT_Q77_DEV_ID 0x1E47 #define PCH_PPT_Q75_DEV_ID 0x1E48 #define PCH_PPT_B75_DEV_ID 0x1E49 #define PCH_PPT_H77_DEV_ID 0x1E4A #define PCH_PPT_B75_MNG_DEV_ID 0x1E4B #define PCH_PPT_B75_RAID_RST_DEV_ID 0x1E4C #define PCH_PPT_B75_RAID_RST_MNG_DEV_ID 0x1E4D #define PCH_PPT_H77_RST_DEV_ID 0x1E4E #define PCH_PPT_P77_RST_DEV_ID 0x1E4F #define PCH_PPT_Q77_RST_DEV_ID 0x1E50 #define PCH_PPT_H71_RAID_RST_DEV_ID 0x1E51 #define PCH_PPT_Q75_RAID_RST_DEV_ID 0x1E52 #define PCH_PPT_SERVER_DEV_ID 0x1E53 #define PCH_PPT_RSVD1_DEV_ID 0x1E54 #define PCH_PPT_QM78_DEV_ID 0x1E55 #define PCH_PPT_QS78_DEV_ID 0x1E56 #define PCH_PPT_HM78_DEV_ID 0x1E57 #define PCH_PPT_UM78_DEV_ID 0x1E58 #define PCH_PPT_HM76_DEV_ID 0x1E59 #define PCH_PPT_HM76_RAID_RST_DEV_ID 0x1E5A #define PCH_PPT_UM78_RAID_RST_DEV_ID 0x1E5B #define PCH_PPT_HM78_MNG_DEV_ID 0x1E5C #define PCH_PPT_DEV_RSVD2_USB1_ID 0x1E5D #define PCH_PPT_DEV_RSVD3_USB2_ID 0x1E5E #define PCH_PPT_DEV_RSVD4_ID 0x1E5F //define LPT device ids #define PCH_LPT_DEV_ID 0x8C40 #define PCH_LPT_DESK_SUPER_DEV_ID 0x8C41 #define PCH_LPT_MOB_SUPER_DEV_ID 0x8C42 #define PCH_LPT_DEV_RSVD1_ID 0x8C43 #define PCH_LPT_Z87_DEV_ID 0x8C44 #define PCH_LPT_DEV_RSVD2_ID 0x8C45 #define PCH_LPT_Z85_DEV_ID 0x8C46 #define PCH_LPT_DEV_RSVD3_ID 0x8C47 #define PCH_LPT_DEV_RSVD4_ID 0x8C48 #define PCH_LPT_HM86_DEV_ID 0x8C49 #define PCH_LPT_H87DEV_ID 0x8C4A #define PCH_LPT_HM87_DEV_ID 0x8C4B #define PCH_LPT_Q85_DEV_ID 0x8C4C #define PCH_LPT_DEV_RSVD5_ID 0x8C4D #define PCH_LPT_Q87_DEV_ID 0x8C4E #define PCH_LPT_QM87_DEV_ID 0x8C4F #define PCH_LPT_B85_DEV_ID 0x8C50 #define PCH_LPT_DEV_RSVD6_ID 0x8C51 #define PCH_LPT_SERVER_ESS_DEV_ID 0x8C52 #define PCH_LPT_DEV_RSVD7_ID 0x8C53 #define PCH_LPT_SERVER_STD_DEV_ID 0x8C54 #define PCH_LPT_DEV_RSVD8_ID 0x8C55 #define PCH_LPT_SERVER_ADV_DEV_ID 0x8C56 #define PCH_LPT_DEV_RSVD9_ID 0x8C57 #define PCH_LPT_WS_DEV_ID 0x8C58 #define PCH_LPT_DEV_RSVD10_ID 0x8C59 #define PCH_LPT_DEV_RSVD11_ID 0x8C5A #define PCH_LPT_DEV_RSVD12_ID 0x8C5B #define PCH_LPT_H81_DEV_ID 0x8C5C #define PCH_LPT_DEV_RSVD13_ID 0x8C5D #define PCH_LPT_DEV_RSVD14_ID 0x8C5E #define PCH_LPT_DEV_RSVD15_ID 0x8C5F #define PCH_LPT_MOB_FFE_DEV_ID 0x8CC1 // D31:F0 - LPC Controller (Mobile Full Featured Engineering Sample) #define PCH_LPT_DESK_FFE_DEV_ID 0X8CC2 // D31:F0 - LPC Controller (Desktop Full Featured Engineering Sample) #define PCH_LPT_HM97_DEV_ID 0X8CC3 // D31:F0 - LPC Controller (HM97 SKU) #define PCH_LPT_Z97_DEV_ID 0X8CC4 // D31:F0 - LPC Controller (Z97 SKU) #define PCH_LPT_QM97_DEV_ID 0X8CC5 // D31:F0 - LPC Controller (QM97 SKU) #define PCH_LPT_H97_DEV_ID 0X8CC6 // D31:F0 - LPC Controller (H97 SKU) #define PCH_LPT_LP_DEV_UNFUSED_ID 0x9C40 #define PCH_LPT_LP_DEV_SUPER_ID 0x9C41 #define PCH_LPT_LP_DEV_PREMIUM_ID 0x9C43 #define PCH_LPT_LP_DEV_MAINSTREAM_ID 0x9C45 #define PCH_LPT_LP_DEV_VALUE_ID 0x9C47 //define WPT device ids #define PCH_WPT_DEV_SIM_ID 0x99FF #define PCH_WPT_LPC_DEV_UNFUSED_ID 0x9CC0 // for BDW P0, D31:F0 - LPC Controller (Unfused part) #define PCH_WPT_LPC_DEV_SUPER_HSW_ID 0x9CC1 // for BDW P0, D31:F0 - LPC Controller (Super SKU) w/ HSW #define PCH_WPT_LPC_DEV_SUPER_BDW_U_CPU_ID 0x9CC2 // for BDW P0, D31:F0 - LPC Controller (Super SKU) w/ BDW U CPU #define PCH_WPT_LPC_DEV_PREMIUM_BDW_U_CPU_ID 0x9CC3 // for BDW P0, D31:F0 - LPC Controller (Premimum SKU) w/ BDW U CPU #define PCH_WPT_LPC_DEV_BASE_BDW_U_CPU_ID 0x9CC5 // for BDW P0, D31:F0 - LPC Controller (Base SKU) w/ BDW U CPU #define PCH_WPT_LPC_DEV_SUPER_BDW_Y_CPU_ID 0x9CC6 // for BDW P0, D31:F0 - LPC Controller (Super SKU) w/ BDW Y CPU #define PCH_WPT_LPC_DEV_PREMIUM_BDW_Y_CPU_ID 0x9CC7 // for BDW P0, D31:F0 - LPC Controller (Premimum SKU) w/ BDW Y CPU #define PCH_WPT_LPC_DEV_BASE_BDW_Y_CPU_ID 0x9CC9 // for BDW P0, D31:F0 - LPC Controller (Base SKU) w/ BDW Y CPU #define PCH_WPT_LPC_DEV_PERFORMANCE_ID 0x9CCB // for BDW P0, D31:F0 - LPC Controller (Performance SKU) //define SPT LP device ids #define PCH_SPT_DEV_SIM_ID 0x99EF #define PCH_SPT_LPC_DEV_UNFUSED_ID 0x9D40 // (SPT-LP) Unfused #define PCH_SPT_LPC_DEV_SUPER_U_ID 0x9D41 // (SPT-LP) Super SKU(Unlocked) #define PCH_SPT_LPC_DEV_SUPER_L_ID 0x9D42 // (SPT-LP) Super SKU(locked) #define PCH_SPT_LPC_DEV_BASE_SKL_U_ID 0x9D43 // (SPT-LP) Base Consumer/Corp SKL-U #define PCH_SPT_LPC_DEV_P1_ID 0x9D44 // (SPT-LP) Placeholder, yet to be finalized #define PCH_SPT_LPC_DEV_P2_ID 0x9D45 // (SPT-LP) Placeholder, yet to be finalized #define PCH_SPT_LPC_DEV_PREMIUM_SKL_Y_ID 0x9D46 // (SPT-LP) Premium Consumer/Corp SKL-Y #define PCH_SPT_LPC_DEV_P3_ID 0x9D47 // (SPT-LP) Placeholder, yet to be finalized #define PCH_SPT_LPC_DEV_PREMIUM_SKL_U_ID 0x9D48 // (SPT-LP) Premium Consumer/Corp SKL-U, yet to be finalized #define PCH_SPT_DEV_PREMIUM_KBL_Y_ID 0x9D4B // (PCH-SPT) Premium Consumer/Corp KBL-Y #define PCH_SPT_DEV_PREMIUM_KBL_U_ID 0x9D4E // (PCH-SPT) Premium Consumer/Corp KBL-U #define PCH_SPT_LPC_DEV_KBL_SUPERSKU_UNLOCKED_ID 0x9D51 // (SPT-LP) Super SKU Unlocked #define PCH_SPT_LPC_DEV_KBL_SUPERSKU_LOCKED_ID 0x9D52 // (SPT-LP) Super SKU locked #define PCH_SPT_LPC_DEV_PREMIUM_KBL_Y_ID 0x9D56 // (SPT-LP) Premium Consumer/Corp KBL-Y #define PCH_SPT_LPC_DEV_PREMIUM_KBL_U_ID 0x9D58 // (SPT-LP) (SPT-LP) Premium Consumer/Corp KBL-Y #define PCH_SPT_LPC_DEV_KBL_BASE_ID 0x9D53 // (SPT-LP) Base Consumer/Corp KBL-U #define PCH_SPT_LPC_DEV_P4_ID 0x9D49 // (SPT-LP) Placeholder, yet to be finalized #define PCH_SPT_LPC_DEV_P5_ID 0x9D50 // (SPT-LP) Placeholder, yet to be finalized #define PCH_SPT_LPC_DEV_P6_ID 0x9D54 // (SPT-LP) Placeholder, yet to be finalized #define PCH_SPT_LPC_DEV_P7_ID 0x9D55 // (SPT-LP) Placeholder, yet to be finalized #define PCH_SPT_LPC_DEV_P8_ID 0x9D57 // (SPT-LP) Placeholder, yet to be finalized #define PCH_SPT_LPC_DEV_P9_ID 0x9D59 // (SPT-LP) Placeholder, yet to be finalized #define PCH_SPT_LPC_DEV_PA_ID 0x9D5A // (SPT-LP) Placeholder, yet to be finalized #define PCH_SPT_LPC_DEV_PB_ID 0x9D5B // (SPT-LP) Placeholder, yet to be finalized #define PCH_SPT_LPC_DEV_PC_ID 0x9D5C // (SPT-LP) Placeholder, yet to be finalized #define PCH_SPT_LPC_DEV_PD_ID 0x9D5D // (SPT-LP) Placeholder, yet to be finalized #define PCH_SPT_LPC_DEV_PE_ID 0x9D5E // (SPT-LP) Placeholder, yet to be finalized #define PCH_SPT_LPC_DEV_PF_ID 0x9D5F // (SPT-LP) Placeholder, yet to be finalized //define SPT Halo Device ids #define PCH_SPT_HALO_DEV_UNFUSED_ID 0xA140 // (SPT-H) Unfused #define PCH_SPT_CLIENT_UNLOCKED_ID 0xA141 // (SPT-H) SuperSKU Client UnLocked #define PCH_SPT_CLIENT_LOCKED_ID 0xA142 // (SPT-H) SuperSKU Client Locked #define PCH_SPT_HALO_DEV_H110_ID 0xA143 // (SPT-H) H110 SKU #define PCH_SPT_HALO_DEV_H170_ID 0xA144 // (SPT-H) H170 SKU #define PCH_SPT_HALO_DEV_Z170_ID 0xA145 // (SPT-H) Z170 SKU #define PCH_SPT_HALO_DEV_Q170_ID 0xA146 // (SPT-H) Q170 SKU #define PCH_SPT_HALO_DEV_Q150_ID 0xA147 // (SPT-H) Q150 SKU #define PCH_SPT_HALO_DEV_B150_ID 0xA148 // (SPT-H) B150 SKU #define PCH_SPT_HALO_DEV_C236_ID 0xA149 // (SPT-H) C236 SKU #define PCH_SPT_HALO_DEV_C232_ID 0xA14A // (SPT-H) C232 SKU #define PCH_SPT_SERVER_UNLOCKED_ID 0xA14B // (SPT-H) Super SKU Server Unlocked #define PCH_SPT_SERVER_LOCKED_ID 0xA14C // (SPT-H) Super SKU Server locked #define PCH_SPT_HALO_DEV_QM170_ID 0xA14D // (SPT-H) QM170 SKU #define PCH_SPT_HALO_DEV_HM170_ID 0xA14E // (SPT-H) HM170 SKU #define PCH_SPT_HALO_DEV_QMS170_ID 0xA14F // (SPT-H) QMS170 SKU #define PCH_SPT_HALO_DEV_CM236_ID 0xA150 // (SPT-H) CM236 SKU #define PCH_SPT_HALO_DEV_QMS180_ID 0xA151 // SPT-H QMS180 SKU #define PCH_SPT_HALO_DEV_HM172_ID 0xA152 // SPT-H HM172 SKU #define PCH_SPT_HALO_DEV_QM172_ID 0xA153 // SPT-H QM172 SKU #define PCH_SPT_HALO_DEV_CM238_ID 0xA154 // SPT-H CM238 SKU #define PCH_SPT_HALO_DEV_P1_ID 0xA155 // Placeholder, yet to be finalized #define PCH_SPT_HALO_DEV_P2_ID 0xA156 // Placeholder, yet to be finalized #define PCH_SPT_HALO_DEV_P3_ID 0xA157 // Placeholder, yet to be finalized #define PCH_SPT_HALO_DEV_P4_ID 0xA158 // Placeholder, yet to be finalized #define PCH_SPT_HALO_DEV_P5_ID 0xA159 // Placeholder, yet to be finalized #define PCH_SPT_HALO_DEV_P6_ID 0xA15A // Placeholder, yet to be finalized #define PCH_SPT_HALO_DEV_P7_ID 0xA15B // Placeholder, yet to be finalized #define PCH_SPT_HALO_DEV_P8_ID 0xA15C // Placeholder, yet to be finalized #define PCH_SPT_HALO_DEV_P9_ID 0xA15D // Placeholder, yet to be finalized #define PCH_SPT_HALO_DEV_PA_ID 0xA15E // Placeholder, yet to be finalized #define PCH_SPT_HALO_DEV_PB_ID 0xA15F // Placeholder, yet to be finalized //define KBP Halo Device Ids #define PCH_KBP_HALO_DEV_P1_ID 0xA280 #define PCH_KBP_HALO_DEV_P2_ID 0xA281 #define PCH_KBP_HALO_DEV_P3_ID 0xA282 #define PCH_KBP_HALO_DEV_P4_ID 0xA283 #define PCH_KBP_HALO_DEV_P5_ID 0xA284 #define PCH_KBP_HALO_DEV_P6_ID 0xA285 #define PCH_KBP_HALO_DEV_P7_ID 0xA286 #define PCH_KBP_HALO_DEV_P8_ID 0xA287 #define PCH_KBP_HALO_DEV_P9_ID 0xA288 #define PCH_KBP_HALO_DEV_PA_ID 0xA289 #define PCH_KBP_HALO_DEV_PB_ID 0xA28A #define PCH_KBP_HALO_DEV_PC_ID 0xA28B #define PCH_KBP_HALO_DEV_PD_ID 0xA28C #define PCH_KBP_HALO_DEV_PE_ID 0xA28D #define PCH_KBP_HALO_DEV_PF_ID 0xA28E #define PCH_KBP_HALO_DEV_P10_ID 0xA28F #define PCH_KBP_HALO_DEV_P11_ID 0xA290 #define PCH_KBP_HALO_DEV_P12_ID 0xA291 #define PCH_KBP_HALO_DEV_P13_ID 0xA292 #define PCH_KBP_HALO_DEV_P14_ID 0xA293 #define PCH_KBP_HALO_DEV_P15_ID 0xA294 #define PCH_KBP_HALO_DEV_P16_ID 0xA295 #define PCH_KBP_HALO_DEV_P17_ID 0xA296 #define PCH_KBP_HALO_DEV_P18_ID 0xA297 #define PCH_KBP_HALO_DEV_P19_ID 0xA298 #define PCH_KBP_HALO_DEV_P1A_ID 0xA299 #define PCH_KBP_HALO_DEV_P1B_ID 0xA29A #define PCH_KBP_HALO_DEV_P1C_ID 0xA29B #define PCH_KBP_HALO_DEV_P1D_ID 0xA29C #define PCH_KBP_HALO_DEV_P1E_ID 0xA29D #define PCH_KBP_HALO_DEV_P1F_ID 0xA29E #define PCH_KBP_HALO_DEV_P20_ID 0xA29F #define PCH_KBP_HALO_ES_SUPER_SKU_CLIENT 0xA2C0 #define PCH_KBP_HALO_ES_SUPER_SKU_SERVER 0xA2CE #define PCH_KBP_SUPERSKU_CLIENT_ID 0xA2C1 #define PCH_KBP_S_DEV_P0_ID 0xA2C2 #define PCH_KBP_S_DEV_P1_ID 0xA2C3 #define PCH_KBP_S_H270_ID 0xA2C4 #define PCH_KBP_S_Z270_ID 0xA2C5 #define PCH_KBP_S_Q270_ID 0xA2C6 #define PCH_KBP_S_Q250_ID 0xA2C7 #define PCH_KBP_S_B250_ID 0xA2C8 #define PCH_KBP_S_DEV_P2_ID 0xA2C9 #define PCH_KBP_S_DEV_P3_ID 0xA2CA #define PCH_KBP_S_DEV_P4_ID 0xA2CB #define PCH_KBP_S_DEV_P5_ID 0xA2CC #define PCH_KBP_S_DEV_P6_ID 0xA2CD #define PCH_KBP_SUPERSKU_SERVER_ID 0xA2CF //define CNL LP PCH Device Ids #define PCH_CNP_LP_DEV_P1_ID 0x9D80 #define PCH_CNP_LP_DEV_P2_ID 0x9D81 #define PCH_CNP_LP_DEV_P3_ID 0x9D82 #define PCH_CNP_LP_DEV_P4_ID 0x9D83 #define PCH_CNP_LP_DEV_P5_ID 0x9D84 #define PCH_CNP_LP_DEV_P6_ID 0x9D85 #define PCH_CNP_LP_DEV_P7_ID 0x9D86 #define PCH_CNP_LP_DEV_P8_ID 0x9D87 #define PCH_CNP_LP_DEV_P9_ID 0x9D88 #define PCH_CNP_LP_DEV_PA_ID 0x9D89 #define PCH_CNP_LP_DEV_PB_ID 0x9D8A #define PCH_CNP_LP_DEV_PC_ID 0x9D8B #define PCH_CNP_LP_DEV_PD_ID 0x9D8C #define PCH_CNP_LP_DEV_PE_ID 0x9D8D #define PCH_CNP_LP_DEV_PF_ID 0x9D8E #define PCH_CNP_LP_DEV_P10_ID 0x9D8F #define PCH_CNP_LP_DEV_P11_ID 0x9D90 #define PCH_CNP_LP_DEV_P12_ID 0x9D91 #define PCH_CNP_LP_DEV_P13_ID 0x9D92 #define PCH_CNP_LP_DEV_P14_ID 0x9D93 #define PCH_CNP_LP_DEV_P15_ID 0x9D94 #define PCH_CNP_LP_DEV_P16_ID 0x9D95 #define PCH_CNP_LP_DEV_P17_ID 0x9D96 #define PCH_CNP_LP_DEV_P18_ID 0x9D97 #define PCH_CNP_LP_DEV_P19_ID 0x9D98 #define PCH_CNP_LP_DEV_P1A_ID 0x9D99 #define PCH_CNP_LP_DEV_P1B_ID 0x9D9A #define PCH_CNP_LP_DEV_P1C_ID 0x9D9B #define PCH_CNP_LP_DEV_P1D_ID 0x9D9C #define PCH_CNP_LP_DEV_P1E_ID 0x9D9D #define PCH_CNP_LP_DEV_P1F_ID 0x9D9E #define PCH_CNP_LP_DEV_P20_ID 0x9D9F //define CNL Halo PCH Device Ids #define PCH_CNP_HALO_DEV_P1_ID 0xA300 #define PCH_CNP_HALO_DEV_P2_ID 0xA301 #define PCH_CNP_HALO_DEV_P3_ID 0xA302 #define PCH_CNP_HALO_DEV_P4_ID 0xA303 #define PCH_CNP_HALO_DEV_P5_ID 0xA304 #define PCH_CNP_HALO_DEV_P6_ID 0xA305 #define PCH_CNP_HALO_DEV_P7_ID 0xA306 #define PCH_CNP_HALO_DEV_P8_ID 0xA307 #define PCH_CNP_HALO_DEV_P9_ID 0xA308 #define PCH_CNP_HALO_DEV_PA_ID 0xA309 #define PCH_CNP_HALO_DEV_PB_ID 0xA30A #define PCH_CNP_HALO_DEV_PC_ID 0xA30B #define PCH_CNP_HALO_DEV_PD_ID 0xA30C #define PCH_CNP_HALO_DEV_PE_ID 0xA30D #define PCH_CNP_HALO_DEV_PF_ID 0xA30E #define PCH_CNP_HALO_DEV_P10_ID 0xA30F #define PCH_CNP_HALO_DEV_P11_ID 0xA310 #define PCH_CNP_HALO_DEV_P12_ID 0xA311 #define PCH_CNP_HALO_DEV_P13_ID 0xA312 #define PCH_CNP_HALO_DEV_P14_ID 0xA313 #define PCH_CNP_HALO_DEV_P15_ID 0xA314 #define PCH_CNP_HALO_DEV_P16_ID 0xA315 #define PCH_CNP_HALO_DEV_P17_ID 0xA316 #define PCH_CNP_HALO_DEV_P18_ID 0xA317 #define PCH_CNP_HALO_DEV_P19_ID 0xA318 #define PCH_CNP_HALO_DEV_P1A_ID 0xA319 #define PCH_CNP_HALO_DEV_P1B_ID 0xA31A #define PCH_CNP_HALO_DEV_P1C_ID 0xA31B #define PCH_CNP_HALO_DEV_P1D_ID 0xA31C #define PCH_CNP_HALO_DEV_P1E_ID 0xA31D #define PCH_CNP_HALO_DEV_P1F_ID 0xA31E #define PCH_CNP_HALO_DEV_P20_ID 0xA31F //GEN11LP #define IICL_LP_GT1_MOB_DEVICE_F0_ID 0xFF05 #define IICL_LP_1x8x8_SUPERSKU_DEVICE_F0_ID 0x8A50 #define IICL_LP_1x8x8_ULX_DEVICE_F0_ID 0x8A51 #define IICL_LP_1x6x8_ULX_DEVICE_F0_ID 0x8A5C #define IICL_LP_1x4x8_ULX_DEVICE_F0_ID 0x8A5D #define IICL_LP_1x8x8_ULT_DEVICE_F0_ID 0x8A52 #define IICL_LP_1x6x8_ULT_DEVICE_F0_ID 0x8A5A #define IICL_LP_1x4x8_ULT_DEVICE_F0_ID 0x8A5B #define IICL_LP_0x0x0_ULT_DEVICE_A0_ID 0x8A70 #define IICL_LP_1x1x8_ULT_DEVICE_A0_ID 0x8A71 #define IICL_LP_1x4x8_LOW_MEDIA_ULT_DEVICE_F0_ID 0x8A56 #define IICL_LP_1x4x8_LOW_MEDIA_ULX_DEVICE_F0_ID 0x8A58 //TGL LP #define IGEN12LP_GT1_MOB_DEVICE_F0_ID 0xFF20 #define ITGL_LP_1x6x16_UNKNOWN_SKU_F0_ID_5 0x9A49 // Remove this once newer enums are merged in OpenCL. Added this to avoid build failure with Linux/OpenCL. #define ITGL_LP_1x6x16_ULT_15W_DEVICE_F0_ID 0x9A49 // Mobile - U42 - 15W #define ITGL_LP_1x6x16_ULX_5_2W_DEVICE_F0_ID 0x9A40 // Mobile - Y42 - 5.2W #define ITGL_LP_1x6x16_ULT_12W_DEVICE_F0_ID 0x9A59 // Mobile - U42 - 12W #define ITGL_LP_1x2x16_HALO_45W_DEVICE_F0_ID 0x9A60 // Halo - H81 - 45W #define ITGL_LP_1x2x16_DESK_65W_DEVICE_F0_ID 0x9A68 // Desktop - S81 - 35W/65W/95W #define ITGL_LP_1x2x16_HALO_WS_45W_DEVICE_F0_ID 0x9A70 // Mobile WS - H81 - 45W #define ITGL_LP_1x2x16_DESK_WS_65W_DEVICE_F0_ID 0x9A78 // Desktop WS- S81 - 35W/65W/95W #define ITGL_LP_GT0_ULT_DEVICE_F0_ID 0x9A7F // GT0 - No GFX, Display Only #define DEV_ID_0205 0x0205 #define DEV_ID_020A 0x020A //Internal Validation Sku's Only #define DEV_ID_0201 0x0201 #define DEV_ID_0202 0x0202 #define DEV_ID_0203 0x0203 #define DEV_ID_0204 0x0204 #define DEV_ID_0206 0x0206 #define DEV_ID_0207 0x0207 #define DEV_ID_0208 0x0208 #define DEV_ID_0209 0x0209 #define DEV_ID_020B 0x020B #define DEV_ID_020C 0x020C #define DEV_ID_020D 0x020D #define DEV_ID_020E 0x020E #define DEV_ID_020F 0x020F #define DEV_ID_0210 0x0210 #define DEV_ID_FF20 0xFF20 #define DEV_ID_9A49 0x9A49 #define DEV_ID_9A40 0x9A40 #define DEV_ID_9A59 0x9A59 #define DEV_ID_9A60 0x9A60 #define DEV_ID_9A68 0x9A68 #define DEV_ID_9A70 0x9A70 #define DEV_ID_9A78 0x9A78 #define DEV_ID_9A7F 0x9A7F #define DEV_ID_4905 0x4905 #define DEV_ID_4906 0x4906 #define DEV_ID_4907 0x4907 // Rocketlake #define DEV_ID_4C80 0x4C80 #define DEV_ID_4C8A 0x4C8A #define DEV_ID_4C8B 0x4C8B #define DEV_ID_4C8C 0x4C8C #define DEV_ID_4C90 0x4C90 #define DEV_ID_4C9A 0x4C9A //LKF #define ILKF_1x8x8_DESK_DEVICE_F0_ID 0x9840 #define ILKF_GT0_DESK_DEVICE_A0_ID 0x9850 #define ILKF_1x6x8_DESK_DEVICE_F0_ID 0x9841 #define ILKF_1x4x8_DESK_DEVICE_F0_ID 0x9842 //JSL #define IJSL_1x4x8_DEVICE_A0_ID 0x4500 //EHL #define IEHL_1x4x8_SUPERSKU_DEVICE_A0_ID 0x4500 #define IEHL_1x2x4_DEVICE_A0_ID 0x4541 #define IEHL_1x4x4_DEVICE_A0_ID 0x4551 #define IEHL_1x4x8_DEVICE_A0_ID 0x4571 #define DEV_ID_4500 0x4500 #define DEV_ID_4541 0x4541 #define DEV_ID_4551 0x4551 #define DEV_ID_4571 0x4571 #define DEV_ID_4555 0x4555 //JSL+ Rev02 #define IJSL_1x4x4_DEVICE_B0_ID 0x4E51 #define IJSL_1x4x6_DEVICE_B0_ID 0x4E61 #define IJSL_1x4x8_DEVICE_B0_ID 0x4E71 #define DEV_ID_4E51 0x4E51 #define DEV_ID_4E61 0x4E61 #define DEV_ID_4E71 0x4E71 #define DEV_ID_4E55 0x4E55 //ADL-S PCH Device IDs #define DEV_ID_4680 0x4680 #define DEV_ID_4681 0x4681 #define DEV_ID_4682 0x4682 #define DEV_ID_4683 0x4683 #define DEV_ID_4690 0x4690 #define DEV_ID_4691 0x4691 #define DEV_ID_4692 0x4692 #define DEV_ID_4693 0x4693 #define DEV_ID_4698 0x4698 #define DEV_ID_4699 0x4699 // ADL-P #define DEV_ID_46A0 0x46A0 #define DEV_ID_46A1 0x46A1 #define DEV_ID_46A2 0x46A2 #define DEV_ID_46A3 0x46A3 #define DEV_ID_46A6 0x46A6 #define DEV_ID_46A8 0x46A8 #define DEV_ID_46AA 0x46AA #define DEV_ID_4626 0x4626 #define DEV_ID_4628 0x4628 #define DEV_ID_462A 0x462A #define DEV_ID_46B0 0x46B0 #define DEV_ID_46B1 0x46B1 #define DEV_ID_46B2 0x46B2 #define DEV_ID_46B3 0x46B3 #define DEV_ID_46C0 0x46C0 #define DEV_ID_46C1 0x46C1 #define DEV_ID_46C2 0x46C2 #define DEV_ID_46C3 0x46C3 //ICL PCH LP Device IDs #define ICP_LP_RESERVED_FUSE_ID 0x3480 #define ICP_LP_U_SUPER_SKU_ID 0x3481 #define ICP_LP_U_PREMIUM_ID 0x3482 #define ICP_LP_U_MAINSTREAM_ID 0x3483 #define ICL_LP_UNKNOWN_SKU_ID_1 0x3484 #define ICL_LP_UNKNOWN_SKU_ID_2 0x3485 #define ICP_LP_Y_SUPER_SKU_ID 0x3486 #define ICP_LP_Y_PREMIUM_ID 0x3487 #define ICL_LP_UNKNOWN_SKU_ID_3 0x3488 #define ICL_LP_UNKNOWN_SKU_ID_4 0x3489 #define ICL_LP_UNKNOWN_SKU_ID_5 0x348A #define ICL_LP_UNKNOWN_SKU_ID_6 0x348B #define ICL_LP_UNKNOWN_SKU_ID_7 0x348C #define ICL_LP_UNKNOWN_SKU_ID_8 0x348D #define ICL_LP_UNKNOWN_SKU_ID_9 0x348E #define ICL_LP_UNKNOWN_SKU_ID_10 0x348F #define ICL_LP_UNKNOWN_SKU_ID_11 0x3490 #define ICL_LP_UNKNOWN_SKU_ID_12 0x3491 #define ICL_LP_UNKNOWN_SKU_ID_13 0x3492 #define ICL_LP_UNKNOWN_SKU_ID_14 0x3493 #define ICL_LP_UNKNOWN_SKU_ID_15 0x3494 #define ICL_LP_UNKNOWN_SKU_ID_16 0x3495 #define ICL_LP_UNKNOWN_SKU_ID_17 0x3496 #define ICL_LP_UNKNOWN_SKU_ID_18 0x3497 #define ICL_LP_UNKNOWN_SKU_ID_19 0x3498 #define ICL_LP_UNKNOWN_SKU_ID_20 0x3499 #define ICL_LP_UNKNOWN_SKU_ID_21 0x349A #define ICL_LP_UNKNOWN_SKU_ID_22 0x349B #define ICL_LP_UNKNOWN_SKU_ID_23 0x349C #define ICL_LP_UNKNOWN_SKU_ID_24 0x349D #define ICL_LP_UNKNOWN_SKU_ID_25 0x349E #define ICL_LP_UNKNOWN_SKU_ID_26 0x349F // JSL N PCH Device IDs for JSL+ Rev02 #define PCH_JSP_N_UNKNOWN_SKU_ID_1 0x4D80 #define PCH_JSP_N_UNKNOWN_SKU_ID_2 0x4D81 #define PCH_JSP_N_UNKNOWN_SKU_ID_3 0x4D82 #define PCH_JSP_N_UNKNOWN_SKU_ID_4 0x4D83 #define PCH_JSP_N_UNKNOWN_SKU_ID_5 0x4D84 #define PCH_JSP_N_UNKNOWN_SKU_ID_6 0x4D85 #define PCH_JSP_N_UNKNOWN_SKU_ID_7 0x4D86 #define PCH_JSP_N_UNKNOWN_SKU_ID_8 0x4D87 #define PCH_JSP_N_UNKNOWN_SKU_ID_9 0x4D88 #define PCH_JSP_N_UNKNOWN_SKU_ID_10 0x4D89 #define PCH_JSP_N_UNKNOWN_SKU_ID_11 0x4D8A #define PCH_JSP_N_UNKNOWN_SKU_ID_12 0x4D8B #define PCH_JSP_N_UNKNOWN_SKU_ID_13 0x4D8C #define PCH_JSP_N_UNKNOWN_SKU_ID_14 0x4D8D #define PCH_JSP_N_UNKNOWN_SKU_ID_15 0x4D8E #define PCH_JSP_N_UNKNOWN_SKU_ID_16 0x4D8F #define PCH_JSP_N_UNKNOWN_SKU_ID_17 0x4D90 #define PCH_JSP_N_UNKNOWN_SKU_ID_18 0x4D91 #define PCH_JSP_N_UNKNOWN_SKU_ID_19 0x4D92 #define PCH_JSP_N_UNKNOWN_SKU_ID_20 0x4D93 #define PCH_JSP_N_UNKNOWN_SKU_ID_21 0x4D94 #define PCH_JSP_N_UNKNOWN_SKU_ID_22 0x4D95 #define PCH_JSP_N_UNKNOWN_SKU_ID_23 0x4D96 #define PCH_JSP_N_UNKNOWN_SKU_ID_24 0x4D97 #define PCH_JSP_N_UNKNOWN_SKU_ID_25 0x4D98 #define PCH_JSP_N_UNKNOWN_SKU_ID_26 0x4D99 #define PCH_JSP_N_UNKNOWN_SKU_ID_27 0x4D9A #define PCH_JSP_N_UNKNOWN_SKU_ID_28 0x4D9B #define PCH_JSP_N_UNKNOWN_SKU_ID_29 0x4D9C #define PCH_JSP_N_UNKNOWN_SKU_ID_30 0x4D9D #define PCH_JSP_N_UNKNOWN_SKU_ID_31 0x4D9E #define PCH_JSP_N_UNKNOWN_SKU_ID_32 0x4D9F // LKF-PCH Device IDs #define PCH_LKF_UNFUSED_SKU_ID 0x9880 #define PCH_LKF_SUPER_SKU_ID 0x9881 // TGL_LP PCH Device ID range 0xA080-0xA09F #define PCH_TGL_LP_UNKNOWN_SKU_ID_1 0xA080 #define PCH_TGL_LP_UNKNOWN_SKU_ID_2 0xA081 #define PCH_TGL_LP_UNKNOWN_SKU_ID_3 0xA082 #define PCH_TGL_LP_UNKNOWN_SKU_ID_4 0xA083 #define PCH_TGL_LP_UNKNOWN_SKU_ID_5 0xA084 #define PCH_TGL_LP_UNKNOWN_SKU_ID_6 0xA085 #define PCH_TGL_LP_UNKNOWN_SKU_ID_7 0xA086 #define PCH_TGL_LP_UNKNOWN_SKU_ID_8 0xA087 #define PCH_TGL_LP_UNKNOWN_SKU_ID_9 0xA088 #define PCH_TGL_LP_UNKNOWN_SKU_ID_10 0xA089 #define PCH_TGL_LP_UNKNOWN_SKU_ID_11 0xA08A #define PCH_TGL_LP_UNKNOWN_SKU_ID_12 0xA08B #define PCH_TGL_LP_UNKNOWN_SKU_ID_13 0xA08C #define PCH_TGL_LP_UNKNOWN_SKU_ID_14 0xA08D #define PCH_TGL_LP_UNKNOWN_SKU_ID_15 0xA08E #define PCH_TGL_LP_UNKNOWN_SKU_ID_16 0xA08F #define PCH_TGL_LP_UNKNOWN_SKU_ID_17 0xA090 #define PCH_TGL_LP_UNKNOWN_SKU_ID_18 0xA091 #define PCH_TGL_LP_UNKNOWN_SKU_ID_19 0xA092 #define PCH_TGL_LP_UNKNOWN_SKU_ID_20 0xA093 #define PCH_TGL_LP_UNKNOWN_SKU_ID_21 0xA094 #define PCH_TGL_LP_UNKNOWN_SKU_ID_22 0xA095 #define PCH_TGL_LP_UNKNOWN_SKU_ID_23 0xA096 #define PCH_TGL_LP_UNKNOWN_SKU_ID_24 0xA097 #define PCH_TGL_LP_UNKNOWN_SKU_ID_25 0xA098 #define PCH_TGL_LP_UNKNOWN_SKU_ID_26 0xA099 #define PCH_TGL_LP_UNKNOWN_SKU_ID_27 0xA09A #define PCH_TGL_LP_UNKNOWN_SKU_ID_28 0xA09B #define PCH_TGL_LP_UNKNOWN_SKU_ID_29 0xA09C #define PCH_TGL_LP_UNKNOWN_SKU_ID_30 0xA09D #define PCH_TGL_LP_UNKNOWN_SKU_ID_31 0xA09E #define PCH_TGL_LP_UNKNOWN_SKU_ID_32 0xA09F //define CML LP PCH Device Ids #define PCH_CMP_LP_DEV_P1_ID 0x0280 #define PCH_CMP_LP_DEV_P2_ID 0x0281 #define PCH_CMP_LP_DEV_P3_ID 0x0282 #define PCH_CMP_LP_DEV_P4_ID 0x0283 #define PCH_CMP_LP_DEV_P5_ID 0x0284 #define PCH_CMP_LP_DEV_P6_ID 0x0285 #define PCH_CMP_LP_DEV_P7_ID 0x0286 #define PCH_CMP_LP_DEV_P8_ID 0x0287 #define PCH_CMP_LP_DEV_P9_ID 0x0288 #define PCH_CMP_LP_DEV_P10_ID 0x0289 #define PCH_CMP_LP_DEV_P11_ID 0x028A #define PCH_CMP_LP_DEV_P12_ID 0x028B #define PCH_CMP_LP_DEV_P13_ID 0x028C #define PCH_CMP_LP_DEV_P14_ID 0x028D #define PCH_CMP_LP_DEV_P15_ID 0x028E #define PCH_CMP_LP_DEV_P16_ID 0x028F #define PCH_CMP_LP_DEV_P17_ID 0x0290 #define PCH_CMP_LP_DEV_P18_ID 0x0291 #define PCH_CMP_LP_DEV_P19_ID 0x0292 #define PCH_CMP_LP_DEV_P20_ID 0x0293 #define PCH_CMP_LP_DEV_P21_ID 0x0294 #define PCH_CMP_LP_DEV_P22_ID 0x0295 #define PCH_CMP_LP_DEV_P23_ID 0x0296 #define PCH_CMP_LP_DEV_P24_ID 0x0297 #define PCH_CMP_LP_DEV_P25_ID 0x0298 #define PCH_CMP_LP_DEV_P26_ID 0x0299 #define PCH_CMP_LP_DEV_P27_ID 0x029A #define PCH_CMP_LP_DEV_P28_ID 0x029B #define PCH_CMP_LP_DEV_P29_ID 0x029C #define PCH_CMP_LP_DEV_P30_ID 0x029D #define PCH_CMP_LP_DEV_P31_ID 0x029E #define PCH_CMP_LP_DEV_P32_ID 0x029F // TGL_H PCH Device ID range 0x4380-0x439F #define PCH_TGL_H_UNKNOWN_SKU_ID_1 0x4380 #define PCH_TGL_H_UNKNOWN_SKU_ID_2 0x4381 #define PCH_TGL_H_UNKNOWN_SKU_ID_3 0x4382 #define PCH_TGL_H_UNKNOWN_SKU_ID_4 0x4383 #define PCH_TGL_H_UNKNOWN_SKU_ID_5 0x4384 #define PCH_TGL_H_UNKNOWN_SKU_ID_6 0x4385 #define PCH_TGL_H_UNKNOWN_SKU_ID_7 0x4386 #define PCH_TGL_H_UNKNOWN_SKU_ID_8 0x4387 #define PCH_TGL_H_UNKNOWN_SKU_ID_9 0x4388 #define PCH_TGL_H_UNKNOWN_SKU_ID_10 0x4389 #define PCH_TGL_H_UNKNOWN_SKU_ID_11 0x438A #define PCH_TGL_H_UNKNOWN_SKU_ID_12 0x438B #define PCH_TGL_H_UNKNOWN_SKU_ID_13 0x438C #define PCH_TGL_H_UNKNOWN_SKU_ID_14 0x438D #define PCH_TGL_H_UNKNOWN_SKU_ID_15 0x438E #define PCH_TGL_H_UNKNOWN_SKU_ID_16 0x438F #define PCH_TGL_H_UNKNOWN_SKU_ID_17 0x4390 #define PCH_TGL_H_UNKNOWN_SKU_ID_18 0x4391 #define PCH_TGL_H_UNKNOWN_SKU_ID_19 0x4392 #define PCH_TGL_H_UNKNOWN_SKU_ID_20 0x4393 #define PCH_TGL_H_UNKNOWN_SKU_ID_21 0x4394 #define PCH_TGL_H_UNKNOWN_SKU_ID_22 0x4395 #define PCH_TGL_H_UNKNOWN_SKU_ID_23 0x4396 #define PCH_TGL_H_UNKNOWN_SKU_ID_24 0x4397 #define PCH_TGL_H_UNKNOWN_SKU_ID_25 0x4398 #define PCH_TGL_H_UNKNOWN_SKU_ID_26 0x4399 #define PCH_TGL_H_UNKNOWN_SKU_ID_27 0x439A #define PCH_TGL_H_UNKNOWN_SKU_ID_28 0x439B #define PCH_TGL_H_UNKNOWN_SKU_ID_29 0x439C #define PCH_TGL_H_UNKNOWN_SKU_ID_30 0x439D #define PCH_TGL_H_UNKNOWN_SKU_ID_31 0x439E #define PCH_TGL_H_UNKNOWN_SKU_ID_32 0x439F //define CML H PCH Device Ids #define PCH_CMP_H_DEV_P1_ID 0x0680 #define PCH_CMP_H_DEV_P2_ID 0x0681 #define PCH_CMP_H_DEV_P3_ID 0x0682 #define PCH_CMP_H_DEV_P4_ID 0x0683 #define PCH_CMP_H_DEV_P5_ID 0x0684 #define PCH_CMP_H_DEV_P6_ID 0x0685 #define PCH_CMP_H_DEV_P7_ID 0x0686 #define PCH_CMP_H_DEV_P8_ID 0x0687 #define PCH_CMP_H_DEV_P9_ID 0x0688 #define PCH_CMP_H_DEV_P10_ID 0x0689 #define PCH_CMP_H_DEV_P11_ID 0x068A #define PCH_CMP_H_DEV_P12_ID 0x068B #define PCH_CMP_H_DEV_P13_ID 0x068C #define PCH_CMP_H_DEV_P14_ID 0x068D #define PCH_CMP_H_DEV_P15_ID 0x068E #define PCH_CMP_H_DEV_P16_ID 0x068F #define PCH_CMP_H_DEV_P17_ID 0x0690 #define PCH_CMP_H_DEV_P18_ID 0x0691 #define PCH_CMP_H_DEV_P19_ID 0x0692 #define PCH_CMP_H_DEV_P20_ID 0x0693 #define PCH_CMP_H_DEV_P21_ID 0x0694 #define PCH_CMP_H_DEV_P22_ID 0x0695 #define PCH_CMP_H_DEV_P23_ID 0x0696 #define PCH_CMP_H_DEV_P24_ID 0x0697 #define PCH_CMP_H_DEV_P25_ID 0x0698 #define PCH_CMP_H_DEV_P26_ID 0x0699 #define PCH_CMP_H_DEV_P27_ID 0x069A #define PCH_CMP_H_DEV_P28_ID 0x069B #define PCH_CMP_H_DEV_P29_ID 0x069C #define PCH_CMP_H_DEV_P30_ID 0x069D #define PCH_CMP_H_DEV_P31_ID 0x069E #define PCH_CMP_H_DEV_P32_ID 0x069F //define CML V PCH Device Ids #define PCH_CMP_V_DEV_P65_ID 0xA3C0 #define PCH_CMP_V_DEV_P66_ID 0xA3C1 #define PCH_CMP_V_DEV_P67_ID 0xA3C2 #define PCH_CMP_V_DEV_P68_ID 0xA3C3 #define PCH_CMP_V_DEV_P69_ID 0xA3C4 #define PCH_CMP_V_DEV_P70_ID 0xA3C5 #define PCH_CMP_V_DEV_P71_ID 0xA3C6 #define PCH_CMP_V_DEV_P72_ID 0xA3C7 #define PCH_CMP_V_DEV_P73_ID 0xA3C8 #define PCH_CMP_V_DEV_P74_ID 0xA3C9 #define PCH_CMP_V_DEV_P75_ID 0xA3CA #define PCH_CMP_V_DEV_P76_ID 0xA3CB #define PCH_CMP_V_DEV_P77_ID 0xA3CC #define PCH_CMP_V_DEV_P78_ID 0xA3CD #define PCH_CMP_V_DEV_P79_ID 0xA3CE #define PCH_CMP_V_DEV_P80_ID 0xA3CF #define PCH_CMP_V_DEV_P81_ID 0xA3D0 #define PCH_CMP_V_DEV_P82_ID 0xA3D1 #define PCH_CMP_V_DEV_P83_ID 0xA3D2 #define PCH_CMP_V_DEV_P84_ID 0xA3D3 #define PCH_CMP_V_DEV_P85_ID 0xA3D4 #define PCH_CMP_V_DEV_P86_ID 0xA3D5 #define PCH_CMP_V_DEV_P87_ID 0xA3D6 #define PCH_CMP_V_DEV_P88_ID 0xA3D7 #define PCH_CMP_V_DEV_P89_ID 0xA3D8 #define PCH_CMP_V_DEV_P90_ID 0xA3D9 #define PCH_CMP_V_DEV_P91_ID 0xA3DA #define PCH_CMP_V_DEV_P92_ID 0xA3DB #define PCH_CMP_V_DEV_P93_ID 0xA3DC #define PCH_CMP_V_DEV_P94_ID 0xA3DD #define PCH_CMP_V_DEV_P95_ID 0xA3DE #define PCH_CMP_V_DEV_P96_ID 0xA3DF // ADL_S PCH Device ID range #define DEV_ID_7A80 0x7A80 #define DEV_ID_7A81 0x7A81 #define DEV_ID_7A82 0x7A82 #define DEV_ID_7A83 0x7A83 #define DEV_ID_7A84 0x7A84 #define DEV_ID_7A85 0x7A85 #define DEV_ID_7A86 0x7A86 #define DEV_ID_7A87 0x7A87 #define DEV_ID_7A88 0x7A88 #define DEV_ID_7A89 0x7A89 #define DEV_ID_7A8A 0x7A8A #define DEV_ID_7A8B 0x7A8B #define DEV_ID_7A8C 0x7A8C #define DEV_ID_7A8D 0x7A8D #define DEV_ID_7A8E 0x7A8E #define DEV_ID_7A8F 0x7A8F #define DEV_ID_7A90 0x7A90 #define DEV_ID_7A91 0x7A91 #define DEV_ID_7A92 0x7A92 #define DEV_ID_7A93 0x7A93 #define DEV_ID_7A94 0x7A94 #define DEV_ID_7A95 0x7A95 #define DEV_ID_7A96 0x7A96 #define DEV_ID_7A97 0x7A97 #define DEV_ID_7A98 0x7A98 #define DEV_ID_7A99 0x7A99 #define DEV_ID_7A9A 0x7A9A #define DEV_ID_7A9B 0x7A9B #define DEV_ID_7A9C 0x7A9C #define DEV_ID_7A9D 0x7A9D #define DEV_ID_7A9E 0x7A9E #define DEV_ID_7A9F 0x7A9F // ADL_P PCH Device ID range #define PCH_DEV_ID_5180 0x5180 #define PCH_DEV_ID_5181 0x5181 #define PCH_DEV_ID_5182 0x5182 #define PCH_DEV_ID_5183 0x5183 #define PCH_DEV_ID_5184 0x5184 #define PCH_DEV_ID_5185 0x5185 #define PCH_DEV_ID_5186 0x5186 #define PCH_DEV_ID_5187 0x5187 #define PCH_DEV_ID_5188 0x5188 #define PCH_DEV_ID_5189 0x5189 #define PCH_DEV_ID_518A 0x518A #define PCH_DEV_ID_518B 0x518B #define PCH_DEV_ID_518C 0x518C #define PCH_DEV_ID_518D 0x518D #define PCH_DEV_ID_518E 0x518E #define PCH_DEV_ID_518F 0x518F #define PCH_DEV_ID_5190 0x5190 #define PCH_DEV_ID_5191 0x5191 #define PCH_DEV_ID_5192 0x5192 #define PCH_DEV_ID_5193 0x5193 #define PCH_DEV_ID_5194 0x5194 #define PCH_DEV_ID_5195 0x5195 #define PCH_DEV_ID_5196 0x5196 #define PCH_DEV_ID_5197 0x5197 #define PCH_DEV_ID_5198 0x5198 #define PCH_DEV_ID_5199 0x5199 #define PCH_DEV_ID_519A 0x519A #define PCH_DEV_ID_519B 0x519B #define PCH_DEV_ID_519C 0x519C #define PCH_DEV_ID_519D 0x519D #define PCH_DEV_ID_519E 0x519E #define PCH_DEV_ID_519F 0x519F // ADL_N PCH Device ID range #define PCH_DEV_ID_5480 0x5480 #define PCH_DEV_ID_5481 0x5481 #define PCH_DEV_ID_5482 0x5482 #define PCH_DEV_ID_5483 0x5483 #define PCH_DEV_ID_5484 0x5484 #define PCH_DEV_ID_5485 0x5485 #define PCH_DEV_ID_5486 0x5486 #define PCH_DEV_ID_5487 0x5487 #define PCH_DEV_ID_5488 0x5488 #define PCH_DEV_ID_5489 0x5489 #define PCH_DEV_ID_548A 0x548A #define PCH_DEV_ID_548B 0x548B #define PCH_DEV_ID_548C 0x548C #define PCH_DEV_ID_548D 0x548D #define PCH_DEV_ID_548E 0x548E #define PCH_DEV_ID_548F 0x548F #define PCH_DEV_ID_5490 0x5490 #define PCH_DEV_ID_5491 0x5491 #define PCH_DEV_ID_5492 0x5492 #define PCH_DEV_ID_5493 0x5493 #define PCH_DEV_ID_5494 0x5494 #define PCH_DEV_ID_5495 0x5495 #define PCH_DEV_ID_5496 0x5496 #define PCH_DEV_ID_5497 0x5497 #define PCH_DEV_ID_5498 0x5498 #define PCH_DEV_ID_5499 0x5499 #define PCH_DEV_ID_549A 0x549A #define PCH_DEV_ID_549B 0x549B #define PCH_DEV_ID_549C 0x549C #define PCH_DEV_ID_549D 0x549D #define PCH_DEV_ID_549E 0x549E #define PCH_DEV_ID_549F 0x549F #define PCH_DEV_ID_54A0 0x54A0 #define PCH_DEV_ID_54A1 0x54A1 #define PCH_DEV_ID_54A2 0x54A2 #define PCH_DEV_ID_54A3 0x54A3 #define PCH_DEV_ID_54A4 0x54A4 #define PCH_DEV_ID_15FB 0x15FB #define PCH_DEV_ID_15FC 0x15FC #define PCH_DEV_ID_54A6 0x54A6 #define PCH_DEV_ID_54A7 0x54A7 #define PCH_DEV_ID_54A8 0x54A8 #define PCH_DEV_ID_54A9 0x54A9 #define PCH_DEV_ID_54AA 0x54AA #define PCH_DEV_ID_54AB 0x54AB #define PCH_DEV_ID_54AC 0x54AC #define PCH_DEV_ID_54AD 0x54AD #define PCH_DEV_ID_54AE 0x54AE #define PCH_DEV_ID_54AF 0x54AF #define PCH_DEV_ID_54B0 0x54B0 #define PCH_DEV_ID_54B1 0x54B1 #define PCH_DEV_ID_54B2 0x54B2 #define PCH_DEV_ID_54B3 0x54B3 #define PCH_DEV_ID_54B4 0x54B4 #define PCH_DEV_ID_54B5 0x54B5 #define PCH_DEV_ID_54B6 0x54B6 #define PCH_DEV_ID_54B7 0x54B7 #define PCH_DEV_ID_54B8 0x54B8 #define PCH_DEV_ID_54B9 0x54B9 #define PCH_DEV_ID_54BA 0x54BA #define PCH_DEV_ID_54BB 0x54BB #define PCH_DEV_ID_54BC 0x54BC #define PCH_DEV_ID_54BD 0x54BD #define PCH_DEV_ID_54BE 0x54BE #define PCH_DEV_ID_54BF 0x54BF #define PCH_DEV_ID_54C4 0x54C4 #define PCH_DEV_ID_54C5 0x54C5 #define PCH_DEV_ID_54C6 0x54C6 #define PCH_DEV_ID_54C7 0x54C7 #define PCH_DEV_ID_54C8 0x54C8 #define PCH_DEV_ID_54C9 0x54C9 #define PCH_DEV_ID_54CA 0x54CA #define PCH_DEV_ID_54CB 0x54CB #define PCH_DEV_ID_54CC 0x54CC #define PCH_DEV_ID_54CD 0x54CD #define PCH_DEV_ID_54CE 0x54CE #define PCH_DEV_ID_54CF 0x54CF #define PCH_DEV_ID_54D0 0x54D0 #define PCH_DEV_ID_54D1 0x54D1 #define PCH_DEV_ID_54D2 0x54D2 #define PCH_DEV_ID_54D3 0x54D3 #define PCH_DEV_ID_54D4 0x54D4 #define PCH_DEV_ID_54D6 0x54D6 #define PCH_DEV_ID_54D7 0x54D7 #define PCH_DEV_ID_282A 0x282A #define PCH_DEV_ID_54D8 0x54D8 #define PCH_DEV_ID_54D9 0x54D9 #define PCH_DEV_ID_54DA 0x54DA #define PCH_DEV_ID_54DB 0x54DB #define PCH_DEV_ID_54DC 0x54DC #define PCH_DEV_ID_54DD 0x54DD #define PCH_DEV_ID_54DE 0x54DE #define PCH_DEV_ID_54DF 0x54DF #define PCH_DEV_ID_54E0 0x54E0 #define PCH_DEV_ID_54E1 0x54E1 #define PCH_DEV_ID_54E2 0x54E2 #define PCH_DEV_ID_54E3 0x54E3 #define PCH_DEV_ID_54E4 0x54E4 #define PCH_DEV_ID_54E5 0x54E5 #define PCH_DEV_ID_54E6 0x54E6 #define PCH_DEV_ID_54E7 0x54E7 #define PCH_DEV_ID_54E8 0x54E8 #define PCH_DEV_ID_54E9 0x54E9 #define PCH_DEV_ID_54EA 0x54EA #define PCH_DEV_ID_54EB 0x54EB #define PCH_DEV_ID_54ED 0x54ED #define PCH_DEV_ID_54EE 0x54EE #define PCH_DEV_ID_54EF 0x54EF #define PCH_DEV_ID_54F0 0x54F0 #define PCH_DEV_ID_54F1 0x54F1 #define PCH_DEV_ID_54F2 0x54F2 #define PCH_DEV_ID_54F3 0x54F3 #define PCH_DEV_ID_54F4 0x54F4 #define PCH_DEV_ID_54F5 0x54F5 #define PCH_DEV_ID_54F6 0x54F6 #define PCH_DEV_ID_54F7 0x54F7 #define PCH_DEV_ID_54F9 0x54F9 #define PCH_DEV_ID_54FA 0x54FA #define PCH_DEV_ID_54FB 0x54FB #define PCH_DEV_ID_54FC 0x54FC #define PCH_DEV_ID_54FD 0x54FD #define PCH_DEV_ID_54FE 0x54FE #define PCH_DEV_ID_54FF 0x54FF // MTL PCH Dev IDs #define PCH_DEV_ID_7E00 0x7E00 #define PCH_DEV_ID_7E01 0x7E01 #define PCH_DEV_ID_7E02 0x7E02 #define PCH_DEV_ID_7E03 0x7E03 #define PCH_DEV_ID_7E04 0x7E04 #define PCH_DEV_ID_7E05 0x7E05 #define PCH_DEV_ID_7E06 0x7E06 #define PCH_DEV_ID_7E07 0x7E07 #define PCH_DEV_ID_7E08 0x7E08 #define PCH_DEV_ID_7E09 0x7E09 #define PCH_DEV_ID_7E0A 0x7E0A #define PCH_DEV_ID_7E0B 0x7E0B #define PCH_DEV_ID_7E0C 0x7E0C #define PCH_DEV_ID_7E0D 0x7E0D #define PCH_DEV_ID_7E0E 0x7E0E #define PCH_DEV_ID_7E0F 0x7E0F #define PCH_DEV_ID_7E10 0x7E10 #define PCH_DEV_ID_7E11 0x7E11 #define PCH_DEV_ID_7E12 0x7E12 #define PCH_DEV_ID_7E13 0x7E13 #define PCH_DEV_ID_7E14 0x7E14 #define PCH_DEV_ID_7E15 0x7E15 #define PCH_DEV_ID_7E16 0x7E16 #define PCH_DEV_ID_7E17 0x7E17 #define PCH_DEV_ID_7E18 0x7E18 #define PCH_DEV_ID_7E19 0x7E19 #define PCH_DEV_ID_7E1A 0x7E1A #define PCH_DEV_ID_7E1B 0x7E1B #define PCH_DEV_ID_7E1C 0x7E1C #define PCH_DEV_ID_7E1D 0x7E1D #define PCH_DEV_ID_7E1E 0x7E1E #define PCH_DEV_ID_7E1F 0x7E1F #define PCH_DEV_ID_AE00 0xAE00 #define PCH_DEV_ID_AE01 0xAE01 #define PCH_DEV_ID_AE02 0xAE02 #define PCH_DEV_ID_AE03 0xAE03 #define PCH_DEV_ID_AE04 0xAE04 #define PCH_DEV_ID_AE05 0xAE05 #define PCH_DEV_ID_AE06 0xAE06 #define PCH_DEV_ID_AE07 0xAE07 #define PCH_DEV_ID_AE08 0xAE08 #define PCH_DEV_ID_AE09 0xAE09 #define PCH_DEV_ID_AE0A 0xAE0A #define PCH_DEV_ID_AE0B 0xAE0B #define PCH_DEV_ID_AE0C 0xAE0C #define PCH_DEV_ID_AE0D 0xAE0D #define PCH_DEV_ID_AE0E 0xAE0E #define PCH_DEV_ID_AE0F 0xAE0F #define PCH_DEV_ID_AE10 0xAE10 #define PCH_DEV_ID_AE11 0xAE11 #define PCH_DEV_ID_AE12 0xAE12 #define PCH_DEV_ID_AE13 0xAE13 #define PCH_DEV_ID_AE14 0xAE14 #define PCH_DEV_ID_AE15 0xAE15 #define PCH_DEV_ID_AE16 0xAE16 #define PCH_DEV_ID_AE17 0xAE17 #define PCH_DEV_ID_AE18 0xAE18 #define PCH_DEV_ID_AE19 0xAE19 #define PCH_DEV_ID_AE1A 0xAE1A #define PCH_DEV_ID_AE1B 0xAE1B #define PCH_DEV_ID_AE1C 0xAE1C #define PCH_DEV_ID_AE1D 0xAE1D #define PCH_DEV_ID_AE1E 0xAE1E #define PCH_DEV_ID_AE1F 0xAE1F // ARL PCH Dev IDs #define PCH_DEV_ID_7700 0x7700 #define PCH_DEV_ID_7701 0x7701 #define PCH_DEV_ID_7702 0x7702 #define PCH_DEV_ID_7703 0x7703 #define PCH_DEV_ID_7704 0x7704 #define PCH_DEV_ID_7705 0x7705 #define PCH_DEV_ID_7706 0x7706 #define PCH_DEV_ID_7707 0x7707 #define PCH_DEV_ID_7708 0x7708 #define PCH_DEV_ID_7709 0x7709 #define PCH_DEV_ID_770A 0x770A #define PCH_DEV_ID_770B 0x770B #define PCH_DEV_ID_770C 0x770C #define PCH_DEV_ID_770D 0x770D #define PCH_DEV_ID_770E 0x770E #define PCH_DEV_ID_770F 0x770F #define PCH_DEV_ID_7710 0x7710 #define PCH_DEV_ID_7711 0x7711 #define PCH_DEV_ID_7712 0x7712 #define PCH_DEV_ID_7713 0x7713 #define PCH_DEV_ID_7714 0x7714 #define PCH_DEV_ID_7715 0x7715 #define PCH_DEV_ID_7716 0x7716 #define PCH_DEV_ID_7717 0x7717 #define PCH_DEV_ID_7718 0x7718 #define PCH_DEV_ID_7719 0x7719 #define PCH_DEV_ID_771A 0x771A #define PCH_DEV_ID_771B 0x771B #define PCH_DEV_ID_771C 0x771C #define PCH_DEV_ID_771D 0x771D #define PCH_DEV_ID_771E 0x771E #define PCH_DEV_ID_771F 0x771F //PVC Device ID #define DEV_ID_0BD0 0x0BD0 #define DEV_ID_0BD5 0x0BD5 #define DEV_ID_0BD6 0x0BD6 #define DEV_ID_0BD7 0x0BD7 #define DEV_ID_0BD8 0x0BD8 #define DEV_ID_0BD9 0x0BD9 #define DEV_ID_0BDA 0x0BDA #define DEV_ID_0BDB 0x0BDB #define DEV_ID_0B69 0x0B69 #define DEV_ID_0B6E 0x0B6E #define DEV_ID_0BD4 0x0BD4 // Macro to identify PVC device ID #define GFX_IS_XT_CONFIG(d) ((d == DEV_ID_0BD5) || \ (d == DEV_ID_0BD6) || \ (d == DEV_ID_0BD7) || \ (d == DEV_ID_0BD8) || \ (d == DEV_ID_0BD9) || \ (d == DEV_ID_0BDA) || \ (d == DEV_ID_0BDB) || \ (d == DEV_ID_0B69) || \ (d == DEV_ID_0B6E) || \ (d == DEV_ID_0BD4)) //DG2 Device IDs #define DEV_ID_4F80 0x4F80 #define DEV_ID_4F81 0x4F81 #define DEV_ID_4F82 0x4F82 #define DEV_ID_4F83 0x4F83 #define DEV_ID_4F84 0x4F84 #define DEV_ID_4F85 0x4F85 #define DEV_ID_4F86 0x4F86 #define DEV_ID_4F87 0x4F87 #define DEV_ID_4F88 0x4F88 #define DEV_ID_5690 0x5690 #define DEV_ID_5691 0x5691 #define DEV_ID_5692 0x5692 #define DEV_ID_5693 0x5693 #define DEV_ID_5694 0x5694 #define DEV_ID_5695 0x5695 #define DEV_ID_5696 0x5696 #define DEV_ID_5697 0x5697 #define DEV_ID_5698 0x5698 #define DEV_ID_56A0 0x56A0 #define DEV_ID_56A1 0x56A1 #define DEV_ID_56A2 0x56A2 #define DEV_ID_56A3 0x56A3 #define DEV_ID_56A4 0x56A4 #define DEV_ID_56A5 0x56A5 #define DEV_ID_56A6 0x56A6 #define DEV_ID_56B0 0x56B0 #define DEV_ID_56B1 0x56B1 #define DEV_ID_56B2 0x56B2 #define DEV_ID_56B3 0x56B3 #define DEV_ID_56BA 0x56BA #define DEV_ID_56BB 0x56BB #define DEV_ID_56BC 0x56BC #define DEV_ID_56BD 0x56BD #define DEV_ID_56BE 0x56BE #define DEV_ID_56BF 0x56BF #define DEV_ID_56C0 0x56C0 #define DEV_ID_56C1 0x56C1 #define DEV_ID_56C2 0x56C2 // RPL-P/U #define DEV_ID_A7A0 0xA7A0 #define DEV_ID_A7A1 0xA7A1 #define DEV_ID_A7A8 0xA7A8 #define DEV_ID_A7A9 0xA7A9 #define DEV_ID_A720 0xA720 #define DEV_ID_A721 0xA721 #define DEV_ID_A7AA 0xA7AA #define DEV_ID_A7AB 0xA7AB #define DEV_ID_A7AC 0xA7AC #define DEV_ID_A7AD 0xA7AD // ADL-N #define DEV_ID_46D0 0x46D0 #define DEV_ID_46D1 0x46D1 #define DEV_ID_46D2 0x46D2 #define DEV_ID_46D3 0x46D3 #define DEV_ID_46D4 0x46D4 // MTL #define DEV_ID_7D40 0x7D40 #define DEV_ID_7D45 0x7D45 #define DEV_ID_7D55 0x7D55 #define DEV_ID_7D57 0x7D57 #define DEV_ID_7D60 0x7D60 #define DEV_ID_7DD5 0x7DD5 #define DEV_ID_7DD7 0x7DD7 // ARL-S #define DEV_ID_7D67 0x7D67 // ARL-H #define DEV_ID_7D41 0x7D41 #define DEV_ID_7D51 0x7D51 #define DEV_ID_7DD1 0x7DD1 // LNL #define DEV_ID_64A0 0x64A0 #define DEV_ID_6420 0x6420 #define DEV_ID_64B0 0x64B0 //BMG #define DEV_ID_E202 0xE202 #define DEV_ID_E20B 0xE20B #define DEV_ID_E20C 0xE20C #define DEV_ID_E20D 0xE20D #define DEV_ID_E212 0xE212 #define MGM_HAS 0 //#define SDG_HAS 1 //Reserve place for Springdale-G HAS //#define SDG_SUPPORT 1 //Springdale G build switch // Macro to identify DG2 device IDs #define GFX_IS_DG2_G11_CONFIG(d) ( ( d == DEV_ID_56A5 ) || \ ( d == DEV_ID_56A6 ) || \ ( d == DEV_ID_5693 ) || \ ( d == DEV_ID_5694 ) || \ ( d == DEV_ID_5695 ) || \ ( d == DEV_ID_56B0 ) || \ ( d == DEV_ID_56B1 ) || \ ( d == DEV_ID_56BA ) || \ ( d == DEV_ID_56BB ) || \ ( d == DEV_ID_56BC ) || \ ( d == DEV_ID_56BD ) || \ ( d == DEV_ID_56C1 ) || \ ( d == DEV_ID_4F87 ) || \ ( d == DEV_ID_4F88 )) #define GFX_IS_DG2_G10_CONFIG(d) ( ( d == DEV_ID_56A0 ) || \ ( d == DEV_ID_56A1 ) || \ ( d == DEV_ID_56A2 ) || \ ( d == DEV_ID_5690 ) || \ ( d == DEV_ID_5691 ) || \ ( d == DEV_ID_5692 ) || \ ( d == DEV_ID_56BE ) || \ ( d == DEV_ID_56BF ) || \ ( d == DEV_ID_56C0 ) || \ ( d == DEV_ID_56C2 ) || \ ( d == DEV_ID_4F80 ) || \ ( d == DEV_ID_4F81 ) || \ ( d == DEV_ID_4F82 ) || \ ( d == DEV_ID_4F83 ) || \ ( d == DEV_ID_4F84 )) #define GFX_IS_DG2_G12_CONFIG(d) ( ( d == DEV_ID_4F85 ) || \ ( d == DEV_ID_4F86 ) || \ ( d == DEV_ID_56A3 ) || \ ( d == DEV_ID_56A4 ) || \ ( d == DEV_ID_5696 ) || \ ( d == DEV_ID_5697 ) || \ ( d == DEV_ID_56B2 ) || \ ( d == DEV_ID_56B3 )) // Macro to identify ARL-S Device ID #define GFX_IS_ARL_S(d) ( ( d == DEV_ID_7D67 ) ) // Macro to identify ARL-H Device ID #define GFX_IS_ARL_H(d) ( ( d == DEV_ID_7D41 ) || \ ( d == DEV_ID_7D51 ) || \ ( d == DEV_ID_7DD1 )) //we define the highest cap and lower cap of stepping IDs #define SI_REV_ID(lo,hi) (lo | hi<<16) #define SI_REV_LO(SteppingID) (SteppingID & 0xFFFF) #define SI_WA_FROM(ulRevID, STEPPING) (ulRevID >= (int)SI_REV_LO(STEPPING)) //define DG2 Media Rev ID #ifdef DG2_MEDIA_REV_ID_B0 #undef DG2_MEDIA_REV_ID_B0 #endif #define DG2_MEDIA_REV_ID_B0 SI_REV_ID(4,4) #ifdef ACM_G10_MEDIA_REV_ID_B0 #undef ACM_G10_MEDIA_REV_ID_B0 #endif #define ACM_G10_MEDIA_REV_ID_B0 SI_REV_ID(4,4) #endif gmmlib-intel-gmmlib-22.5.2/Source/inc/common/sku_wa.h000066400000000000000000000620051466655022700224120ustar00rootroot00000000000000/*============================================================================== Copyright(c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ============================================================================*/ /* File Name: sku_wa.h Description: Common hardware sku and workaround information structures. This file is commented in a manner allowing automated parsing of WA information. Each entry inside WA table should include comments in form of: @WorkaroundName //this field is mandatory @Description @BugType @Component \*****************************************************************************/ #ifndef __SKU_WA_H__ #define __SKU_WA_H__ // Prevent the following... // warning: ISO C++ prohibits anonymous structs [-pedantic] // warning: ISO C90 doesn't support unnamed structs/unions [-pedantic] #if defined(__clang__) #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wpedantic" // clang only recognizes -Wpedantic #elif defined(__GNUC__) #pragma GCC diagnostic push #if __GNUC__ >= 6 #pragma GCC diagnostic ignored "-Wpedantic" #else #pragma GCC diagnostic ignored "-pedantic" // gcc <= 4.7.4 only recognizes -pedantic #endif #endif //********************************** SKU **************************************** // Sku Table structure to abstract sku based hw feature availability // For any Sku based feature, add a field in this structure typedef struct _SKU_FEATURE_TABLE { // flags 1 = available, 0 = not available struct //_sku_Core { unsigned int FtrULT : 1; // Indicates ULT SKU unsigned int FtrVERing : 1; // Separate Ring for VideoEnhancement commands unsigned int FtrVcs2 : 1; // Second VCS engine supported on Gen8 to Gen10 (in some configurations); unsigned int FtrLCIA : 1; // Indicates Atom (Low Cost Intel Architecture) unsigned int FtrCCSRing : 1; // To indicate if CCS hardware ring support is present. unsigned int FtrCCSNode : 1; // To indicate if CCS Node support is present. unsigned int FtrTileY : 1; // Identifies Legacy tiles TileY/Yf/Ys on the platform unsigned int FtrCCSMultiInstance : 1; // To indicate if driver supports MultiContext mode on RCS and more than 1 CCS. unsigned int FtrL3TransientDataFlush : 1; // Transient data flush from L3 cache }; struct //_sku_KMD_render { // MI commends are capable to set unsigned int FtrPPGTT : 1; // Per-Process GTT unsigned int FtrIA32eGfxPTEs : 1; // GTT/PPGTT's use 64-bit IA-32e PTE format. unsigned int FtrMemTypeMocsDeferPAT : 1; // Pre-Gen12 MOCS can defers to PAT, e.g. eLLC Target Cache for MOCS unsigned int FtrPml4Support : 1; // PML4-based gfx page tables are supported (in addition to PD-based tables). unsigned int FtrSVM : 1; // Shared Virtual Memory (i.e. support for SVM buffers which can be accessed by both the CPU and GPU at numerically equivalent addresses.) unsigned int FtrTileMappedResource : 1; // Tiled Resource support aka Sparse Textures. unsigned int FtrTranslationTable : 1; // Translation Table support for Tiled Resources. unsigned int FtrUserModeTranslationTable : 1; // User mode managed Translation Table support for Tiled Resources. unsigned int FtrNullPages : 1; // Support for PTE-based Null pages for Sparse/Tiled Resources). unsigned int FtrEDram : 1; // embedded DRAM enable unsigned int FtrLLCBypass : 1; // Partial tunneling of UC memory traffic via CCF (LLC Bypass) unsigned int FtrCrystalwell : 1; // Crystalwell Sku unsigned int FtrCentralCachePolicy : 1; // Centralized Cache Policy unsigned int FtrWddm2GpuMmu : 1; // WDDMv2 GpuMmu Model (Set in platform SKU files, but disabled by GMM as appropriate for given system.) unsigned int FtrWddm2Svm : 1; // WDDMv2 SVM Model (Set in platform SKU files, but disabled by GMM as appropriate for given system.) unsigned int FtrStandardMipTailFormat : 1; // Dx Standard MipTail Format for TileYf/Ys unsigned int FtrWddm2_1_64kbPages : 1; // WDDMv2.1 64KB page support unsigned int FtrE2ECompression : 1; // E2E Compression ie Aux Table support unsigned int FtrLinearCCS : 1; // Linear Aux surface is supported unsigned int FtrFrameBufferLLC : 1; // Displayable Frame buffers cached in LLC unsigned int FtrDriverFLR : 1; // Enable Function Level Reset (Gen11+) unsigned int FtrLocalMemory : 1; unsigned int FtrCameraCaptureCaching : 1; unsigned int FtrLocalMemoryAllows4KB : 1; unsigned int FtrPpgtt64KBWalkOptimization : 1; // XeHP 64KB Page table walk optimization on PPGTT. unsigned int FtrFlatPhysCCS : 1; // XeHP compression ie flat physical CCS unsigned int FtrDisplayXTiling : 1; // Fallback to Legacy TileX Display, used for Pre-SI platforms. unsigned int FtrMultiTileArch : 1; unsigned int FtrDisplayPageTables : 1; // Display Page Tables: 2-Level Page walk for Displayable Frame buffers in GGTT. unsigned int Ftr57bGPUAddressing : 1; // 57b GPUVA support eg: PVC unsigned int FtrUnified3DMediaCompressionFormats : 1; // DG2 has unified Render/media compression(versus TGLLP/XeHP_SDV 's multiple instances) and requires changes to RC format h/w encodings. unsigned int FtrForceTile4 : 1; // Flag to force Tile4 usage as default in Tile64 supported platforms. unsigned int FtrTile64Optimization : 1; unsigned int FtrDiscrete : 1; // Discrete-gfx unsigned int FtrXe2Compression : 1; // Xe2 Stateless Compression unsigned int FtrXe2PlusTiling : 1; // Tile64 MSAA Layout unsigned int FtrL4Cache : 1; // L4 cache support unsigned int FtrPml5Support : 1; // xe2 page tables }; struct //_sku_3d { unsigned int FtrAstcLdr2D : 1; // ASTC 2D LDR Mode Support (mutually exclusive from other ASTC Ftr's) unsigned int FtrAstcHdr2D : 1; // ASTC 2D HDR Mode Support (mutually exclusive from other ASTC Ftr's) unsigned int FtrAstc3D : 1; // ASTC 3D LDR/HDR Mode Support (mutually exclusive from other ASTC Ftr's) }; struct //_sku_PwrCons { //FBC unsigned int FtrFbc : 1; // Frame Buffer Compression }; struct //_sku_Display { unsigned int FtrRendComp : 1; // For Render Compression Feature on Gen9+ unsigned int FtrDisplayYTiling : 1; // For Y Tile Feature on Gen9+ unsigned int FtrDisplayDisabled : 1; // Server skus with Display }; struct { unsigned int FtrS3D : 1; // Stereoscopic 3D unsigned int FtrDisplayEngineS3d : 1; // Display Engine Stereoscopic 3D }; struct // Virtualization features { unsigned int FtrVgt : 1; }; struct // For MultiTileArch, KMD reports default tile assignment to UMD-GmmLib - via __KmQueryDriverPrivateInfo { unsigned int FtrAssignedGpuTile : 3; // Indicates Gpu Tile number assigned to a process for Naive apps. }; } SKU_FEATURE_TABLE, *PSKU_FEATURE_TABLE; #if defined(__clang__) #pragma clang diagnostic pop #elif defined(__GNUC__) #pragma GCC diagnostic pop #endif //********************************** WA **************************************** #define WA_DECLARE( wa, wa_comment, wa_bugType, wa_impact, wa_component) unsigned int wa : 1; enum WA_BUG_TYPE { WA_BUG_TYPE_UNKNOWN = 0, WA_BUG_TYPE_CORRUPTION = 1, WA_BUG_TYPE_HANG = 2, WA_BUG_TYPE_PERF = 4, WA_BUG_TYPE_FUNCTIONAL = 8, WA_BUG_TYPE_SPEC = 16, WA_BUG_TYPE_FAIL = 32 }; #define WA_BUG_PERF_IMPACT(f) f #define WA_BUG_PERF_IMPACT_UNKNOWN -1 enum WA_COMPONENT { WA_COMPONENT_UNKNOWN = 0, WA_COMPONENT_GMM = 0x1, WA_COMPONENT_MEDIA = 0x2, WA_COMPONENT_OCL = 0x3, }; // Workaround Table structure to abstract WA based on hw and rev id typedef struct _WA_TABLE { // struct wa_3d unsigned int : 0; WA_DECLARE( WaAlignIndexBuffer, "Force the end of the index buffer to be cacheline-aligned to work around a hardware bug that performs no bounds checking on accesses past the end of the index buffer when it only partially fills a cacheline.", WA_BUG_TYPE_CORRUPTION, WA_BUG_PERF_IMPACT_UNKNOWN, WA_COMPONENT_UNKNOWN) // struct _wa_Gmm unsigned int : 0; WA_DECLARE( WaValign2ForR8G8B8UINTFormat, "sampler format decoding error in HW for this particular format double fetching is happening, WA is to use VALIGN_2 instead of VALIGN_4", WA_BUG_TYPE_CORRUPTION, WA_BUG_PERF_IMPACT(0), WA_COMPONENT_UNKNOWN) WA_DECLARE( WaValign2For96bppFormats, "VALIGN_2 only for 96bpp formats.", WA_BUG_TYPE_UNKNOWN, WA_BUG_PERF_IMPACT_UNKNOWN, WA_COMPONENT_UNKNOWN) WA_DECLARE( WaCursor16K, "Cursor memory need to be mapped in GTT", WA_BUG_TYPE_UNKNOWN, WA_BUG_PERF_IMPACT_UNKNOWN, WA_COMPONENT_UNKNOWN) WA_DECLARE( Wa8kAlignforAsyncFlip, "Enable 8k pitch alignment for Asynchronous Flips in rotated mode. (!) Unconventional use! When used, set each XP mode-change (not in platform WA file)!", WA_BUG_TYPE_UNKNOWN, WA_BUG_PERF_IMPACT_UNKNOWN, WA_COMPONENT_UNKNOWN) WA_DECLARE( Wa29BitDisplayAddrLimit, "Sprite/Overlay/Display addresses limited to 29 bits (512MB)", WA_BUG_TYPE_UNKNOWN, WA_BUG_PERF_IMPACT_UNKNOWN, WA_COMPONENT_UNKNOWN) WA_DECLARE( WaAlignContextImage, "WA for context alignment", WA_BUG_TYPE_UNKNOWN, WA_BUG_PERF_IMPACT_UNKNOWN, WA_COMPONENT_UNKNOWN) WA_DECLARE( WaForceGlobalGTT, "WA for cmds requiring memory address to come from global GTT, not PPGTT.", WA_BUG_TYPE_UNKNOWN, WA_BUG_PERF_IMPACT_UNKNOWN, WA_COMPONENT_UNKNOWN) WA_DECLARE( WaReportPerfCountForceGlobalGTT, "WA for MI_REPORT_PERF_COUNT cmd requiring memory address to come from global GTT, not PPGTT.", WA_BUG_TYPE_UNKNOWN, WA_BUG_PERF_IMPACT_UNKNOWN, WA_COMPONENT_UNKNOWN) WA_DECLARE( WaOaAddressTranslation, "WA for STDW and PIPE_CONTROL cmd requiring memory address to come from global GTT, not PPGTT.", WA_BUG_TYPE_UNKNOWN, WA_BUG_PERF_IMPACT_UNKNOWN, WA_COMPONENT_UNKNOWN) WA_DECLARE( Wa2RowVerticalAlignment, "WA to set VALIGN of sample and rt buffers.", WA_BUG_TYPE_UNKNOWN, WA_BUG_PERF_IMPACT_UNKNOWN, WA_COMPONENT_UNKNOWN) WA_DECLARE( WaPpgttAliasGlobalGttSpace, "Disallow independent PPGTT space--i.e. the PPGTT must simply alias global GTT space. (N/A without FtrPageDirectory set.)", WA_BUG_TYPE_UNKNOWN, WA_BUG_PERF_IMPACT_UNKNOWN, WA_COMPONENT_UNKNOWN) WA_DECLARE( WaClearFenceRegistersAtDriverInit, "WA to clear all fence registers at driver init time.", WA_BUG_TYPE_UNKNOWN, WA_BUG_PERF_IMPACT_UNKNOWN, WA_COMPONENT_UNKNOWN) WA_DECLARE( WaRestrictPitch128KB, "Restrict max surface pitch to 128KB.", WA_BUG_TYPE_UNKNOWN, WA_BUG_PERF_IMPACT_UNKNOWN, WA_COMPONENT_UNKNOWN) WA_DECLARE( WaAvoidLLC, "Avoid LLC use. (Intended for debug purposes only.)", WA_BUG_TYPE_UNKNOWN, WA_BUG_PERF_IMPACT_UNKNOWN, WA_COMPONENT_UNKNOWN) WA_DECLARE( WaAvoidL3, "Avoid L3 use (but don't reconfigure; and naturally URB/etc. still need L3). (Intended for debug purposes only.)", WA_BUG_TYPE_UNKNOWN, WA_BUG_PERF_IMPACT_UNKNOWN, WA_COMPONENT_UNKNOWN) WA_DECLARE( Wa16TileFencesOnly, "Limit to 16 tiling fences --Set at run-time by GMM.", WA_BUG_TYPE_UNKNOWN, WA_BUG_PERF_IMPACT_UNKNOWN, WA_COMPONENT_UNKNOWN) WA_DECLARE( Wa16MBOABufferAlignment, "WA align the base address of the OA buffer to 16mb", WA_BUG_TYPE_UNKNOWN, WA_BUG_PERF_IMPACT_UNKNOWN, WA_COMPONENT_UNKNOWN) WA_DECLARE( WaTranslationTableUnavailable, "WA for BXT and SKL skus without Tiled-Resource Translation-Table (TR-TT)", WA_BUG_TYPE_SPEC, WA_BUG_PERF_IMPACT_UNKNOWN, WA_COMPONENT_UNKNOWN) WA_DECLARE( WaNoMinimizedTrivialSurfacePadding, "(Not actual HW WA.) On BDW:B0+ trivial surfaces (single-LOD, non-arrayed, non-MSAA, 1D/2D/Buffers) are exempt from the samplers large padding requirements. This WA identifies platforms that dont yet support that.", WA_BUG_TYPE_UNKNOWN, WA_BUG_PERF_IMPACT_UNKNOWN, WA_COMPONENT_UNKNOWN) WA_DECLARE( WaNoBufferSamplerPadding, "Client agreeing to take responsibility for flushing L3 after sampling/etc.", WA_BUG_TYPE_UNKNOWN, WA_BUG_PERF_IMPACT_UNKNOWN, WA_COMPONENT_UNKNOWN) WA_DECLARE( WaSurfaceStatePlanarYOffsetAlignBy2, "WA to align SURFACE_STATE Y Offset for UV Plane by 2", WA_BUG_TYPE_UNKNOWN, WA_BUG_PERF_IMPACT_UNKNOWN, WA_COMPONENT_UNKNOWN) WA_DECLARE( WaGttCachingOffByDefault, "WA to enable the caching if off by defaultboth at driver init and Resume", WA_BUG_TYPE_UNKNOWN, WA_BUG_PERF_IMPACT_UNKNOWN, WA_COMPONENT_UNKNOWN) WA_DECLARE( WaTouchAllSvmMemory, "When in WDDM2 / SVM mode, all VA memory buffers/surfaces/etc need to be touched to ensure proper PTE mapping", WA_BUG_TYPE_UNKNOWN, WA_BUG_PERF_IMPACT_UNKNOWN, WA_COMPONENT_UNKNOWN) WA_DECLARE( WaIOBAddressMustBeValidInHwContext, "IndirectObjectBase address (of SBA cmd) in HW Context needs to be valid because it gets used every Context load", WA_BUG_TYPE_HANG, WA_BUG_PERF_IMPACT_UNKNOWN, WA_COMPONENT_UNKNOWN) WA_DECLARE( WaFlushTlbAfterCpuGgttWrites, "WA to flush TLB after CPU GTT writes because TLB entry invalidations on GTT writes use wrong address for look-up", WA_BUG_TYPE_FUNCTIONAL, WA_BUG_PERF_IMPACT_UNKNOWN, WA_COMPONENT_UNKNOWN) WA_DECLARE( WaMsaa8xTileYDepthPitchAlignment, "WA to use 256B pitch alignment for MSAA 8x + TileY depth surfaces.", WA_BUG_TYPE_UNKNOWN, WA_BUG_PERF_IMPACT_UNKNOWN, WA_COMPONENT_UNKNOWN) WA_DECLARE( WaDisableNullPageAsDummy, "WA to disable use of NULL bit in dummy PTE", WA_BUG_TYPE_HANG | WA_BUG_TYPE_CORRUPTION, WA_BUG_PERF_IMPACT_UNKNOWN, WA_COMPONENT_GMM) WA_DECLARE( WaUseVAlign16OnTileXYBpp816, "WA to make VAlign = 16, when bpp == 8 or 16 for both TileX and TileY on BDW", WA_BUG_TYPE_CORRUPTION, WA_BUG_PERF_IMPACT_UNKNOWN, WA_COMPONENT_GMM) WA_DECLARE( WaNoMocsEllcOnly, "WA to get eLLC Target Cache for MOCS surfaces, when MOCS defers to PAT", WA_BUG_TYPE_FUNCTIONAL, WA_BUG_PERF_IMPACT, WA_COMPONENT_GMM) WA_DECLARE( WaGttPat0, "GTT accesses hardwired to PAT0", WA_BUG_TYPE_FUNCTIONAL, WA_BUG_PERF_IMPACT, WA_COMPONENT_GMM) WA_DECLARE( WaGttPat0WB, "WA to set WB cache for GTT accessess on PAT0", WA_BUG_TYPE_FUNCTIONAL, WA_BUG_PERF_IMPACT, WA_COMPONENT_GMM) WA_DECLARE( WaMemTypeIsMaxOfPatAndMocs, "WA to set PAT.MT = UC. Since TGLLP uses MAX function to resolve PAT vs MOCS MemType So unless PTE.PAT says UC, MOCS won't be able to set UC!", WA_BUG_TYPE_FUNCTIONAL, WA_BUG_PERF_IMPACT, WA_COMPONENT_GMM) WA_DECLARE( WaGttPat0GttWbOverOsIommuEllcOnly, "WA to set PAT0 to full cacheable (LLC+eLLC) for GTT access over eLLC only usage for OS based SVM", WA_BUG_TYPE_FUNCTIONAL, WA_BUG_PERF_IMPACT, WA_COMPONENT_GMM) WA_DECLARE( WaAddDummyPageForDisplayPrefetch, "WA to add dummy page row after display surfaces to avoid issues with display pre-fetch", WA_BUG_TYPE_CORRUPTION, WA_BUG_PERF_IMPACT_UNKNOWN, WA_COMPONENT_GMM) WA_DECLARE( WaLLCCachingUnsupported, "There is no H/w support for LLC in VLV or VLV Plus", WA_BUG_TYPE_UNKNOWN, WA_BUG_PERF_IMPACT_UNKNOWN, WA_COMPONENT_GMM) WA_DECLARE( WaEncryptedEdramOnlyPartials, "Disable Edram only caching for encrypted usage", WA_BUG_TYPE_CORRUPTION, WA_BUG_PERF_IMPACT_UNKNOWN, WA_COMPONENT_GMM) WA_DECLARE( WaDisableEdramForDisplayRT, "WA to disable EDRAM cacheability of Displayable Render Targets on SKL Steppings until I0", WA_BUG_TYPE_PERF, WA_BUG_PERF_IMPACT, WA_COMPONENT_GMM) WA_DECLARE( WaAstcCorruptionForOddCompressedBlockSizeX, "Enable CHV D0+ WA for ASTC HW bug: sampling from mip levels 2+ returns wrong texels. WA adds XOffset to mip2+, requires D0 HW ECO fix.", WA_BUG_TYPE_CORRUPTION, WA_BUG_PERF_IMPACT_UNKNOWN, WA_COMPONENT_UNKNOWN) WA_DECLARE( WaLosslessCompressionSurfaceStride, "WA to align surface stride for unified aux surfaces", WA_BUG_TYPE_UNKNOWN, WA_BUG_PERF_IMPACT_UNKNOWN, WA_COMPONENT_UNKNOWN) WA_DECLARE( Wa4kAlignUVOffsetNV12LinearSurface, "WA to align UV plane offset at 4k page for NV12 Linear FlipChain surfaces", WA_BUG_TYPE_CORRUPTION, WA_BUG_PERF_IMPACT_UNKNOWN, WA_COMPONENT_UNKNOWN) WA_DECLARE( WaFbcLinearSurfaceStride, "WA to align surface stride for linear primary surfaces", WA_BUG_TYPE_UNKNOWN, WA_BUG_PERF_IMPACT_UNKNOWN, WA_COMPONENT_UNKNOWN) WA_DECLARE( WaDoubleFastClearWidthAlignment, "For all HSW GT3 skus and for all HSW GT E0+ skus, must double the width alignment when performing fast clears.", WA_BUG_TYPE_CORRUPTION, WA_BUG_PERF_IMPACT_UNKNOWN, WA_COMPONENT_UNKNOWN) WA_DECLARE( WaCompressedResourceRequiresConstVA21, "3D and Media compressed resources should not have addresses that change within bit range [20:0]", WA_BUG_TYPE_UNKNOWN, WA_BUG_PERF_IMPACT_UNKNOWN, WA_COMPONENT_UNKNOWN) WA_DECLARE( WaDisregardPlatformChecks, "Disable plarform checks to surface allocation.", WA_BUG_TYPE_UNKNOWN, WA_BUG_PERF_IMPACT_UNKNOWN, WA_COMPONENT_UNKNOWN) WA_DECLARE( WaAlignYUVResourceToLCU, "source and recon surfaces need to be aligned to the LCU size", WA_BUG_TYPE_CORRUPTION, WA_BUG_PERF_IMPACT_UNKNOWN, WA_COMPONENT_GMM) WA_DECLARE( Wa32bppTileY2DColorNoHAlign4, "Wa to defeature HALIGN_4 for 2D 32bpp RT surfaces, due to bug introduced from daprsc changes to help RCPB generate correct offsets to deal with cam match", WA_BUG_TYPE_CORRUPTION, WA_BUG_PERF_IMPACT_UNKNOWN, WA_COMPONENT_GMM) WA_DECLARE( WaAuxTable16KGranular, "AuxTable map granularity changed to 16K ", WA_BUG_TYPE_PERF, WA_BUG_PERF_IMPACT_UNKNOWN, WA_COMPONENT_UNKNOWN) WA_DECLARE( WaAuxTable64KGranular, "AuxTable map granularity changed to 64K ..Remove once Neo switches reference to WaAuxTable16KGranular", WA_BUG_TYPE_PERF, WA_BUG_PERF_IMPACT_UNKNOWN, WA_COMPONENT_UNKNOWN) WA_DECLARE( WaLimit128BMediaCompr, "WA to limit media decompression on Render pipe to 128B (2CLs) 4:n.", WA_BUG_TYPE_FUNCTIONAL, WA_BUG_PERF_IMPACT_UNKNOWN, WA_COMPONENT_GMM) WA_DECLARE( WaUntypedBufferCompression, "WA to allow untyped raw buffer AuxTable mapping", WA_BUG_TYPE_FUNCTIONAL, WA_BUG_PERF_IMPACT_UNKNOWN, WA_COMPONENT_GMM) WA_DECLARE( Wa64kbMappingAt2mbGranularity, "WA to force 2MB alignment for 64KB-LMEM pages", WA_BUG_TYPE_FUNCTIONAL, WA_BUG_PERF_IMPACT_UNKNOWN, WA_COMPONENT_GMM) WA_DECLARE( WaDefaultTile4, "[XeHP] Keep Tile4 as default on XeHP till B stepping", WA_BUG_TYPE_UNKNOWN, WA_BUG_PERF_IMPACT_UNKNOWN, WA_COMPONENT_GMM) WA_DECLARE( Wa_1606955757, "[GPSSCLT] [XeHP] Multicontext (LB) : out-of-order write-read access to scratch space from hdctlbunit", WA_BUG_TYPE_UNKNOWN, WA_BUG_PERF_IMPACT_UNKNOWN, WA_COMPONENT_OGL) WA_DECLARE( WaTile64Optimization, "Tile64 wastge a lot of memory so WA provides optimization to fall back to Tile4 when waste is relatively higher", WA_BUG_TYPE_UNKNOWN, WA_BUG_PERF_IMPACT_UNKNOWN, WA_COMPONENT_GMM) WA_DECLARE( Wa_15010089951, "[DG2][Silicon][Perf]DG2 VESFC performance when Compression feature is enabled.", WA_BUG_TYPE_PERF, WA_BUG_PERF_IMPACT_UNKNOWN, WA_COMPONENT_GMM) WA_DECLARE( Wa_22016140776, "[PVC] operation unexpectedly results in NAN", WA_BUG_TYPE_UNKNOWN, WA_BUG_PERF_IMPACT_UNKNOWN, WA_COMPONENT_UNKNOWN) WA_DECLARE( Wa_14018443005, "[Xe2] - Incorrect handling of compression when changing cached PA usage from compression OFF and another client does partial sector compression ON on W with UC", WA_BUG_TYPE_UNKNOWN, WA_BUG_PERF_IMPACT_UNKNOWN, WA_COMPONENT_GMM) WA_DECLARE( Wa_14018976079, "[LNL] CPU-GPU False sharing broken for 1-way coherent pages", WA_BUG_TYPE_UNKNOWN, WA_BUG_PERF_IMPACT_UNKNOWN, WA_COMPONENT_GMM) WA_DECLARE( Wa_14018984349, "[LNL] CPU-GPU False sharing broken for non-coherent pages", WA_BUG_TYPE_UNKNOWN, WA_BUG_PERF_IMPACT_UNKNOWN, WA_COMPONENT_GMM) WA_DECLARE( Wa_14020040029, "Misalignment on Depth buffer for Zplanes", WA_BUG_TYPE_UNKNOWN, WA_BUG_PERF_IMPACT_UNKNOWN, WA_COMPONENT_GMM) WA_DECLARE( Wa_EmuMufasaSupportOnBmg, "WA for supporting failure seen in BMG with Mufasa", WA_BUG_TYPE_FUNCTIONAL, WA_BUG_PERF_IMPACT_UNKNOWN, WA_COMPONENT_UNKNOWN) } WA_TABLE, *PWA_TABLE; //********************************** SKU/WA Macros ************************************* #if (defined(__MINIPORT) || defined(__KCH) || defined(__SOFTBIOS) || defined(__GRM) || defined(__PWRCONS)) #if LHDM || LINUX #define GFX_IS_SKU(s, f) ((s)->SkuTable.f) #define GFX_IS_WA(s, w) ((s)->WaTable.w) #define GFX_WRITE_WA(x, y, z) ((x)->WaTable.y = z) //No checking is done in the GFX_WRITE_SKU macro that z actually fits into y. // It is up to the user to know the size of y and to pass in z accordingly. #define GFX_WRITE_SKU(x, y, z) ((x)->SkuTable.y = z) #else #define GFX_IS_SKU(h, f) (((PHW_DEVICE_EXTENSION)(h))->pHWStatusPage->pSkuTable->f) #define GFX_IS_WA(h, w) (((PHW_DEVICE_EXTENSION)(h))->pHWStatusPage->pWaTable->w) #define GFX_WRITE_WA(x, y, z) (((HW_DEVICE_EXTENSION *)(x))->pHWStatusPage->pWaTable->y = z) //No checking is done in the GFX_WRITE_SKU macro that z actually fits into y. // It is up to the user to know the size of y and to pass in z accordingly. #define GFX_WRITE_SKU(x, y, z) (((HW_DEVICE_EXTENSION *)(x))->pHWStatusPage->pSkuTable->y = z) #endif // end LHDM #else #define GFX_IS_SKU(s, f) ((s)->SkuTable.f) #define GFX_IS_WA(s, w) ((s)->WaTable.w) #endif #define GRAPHICS_IS_SKU(s, f) ((s)->f) #define GRAPHICS_IS_WA(s, w) ((s)->w) #endif //__SKU_WA_H__ gmmlib-intel-gmmlib-22.5.2/Source/inc/portable_compiler.h000066400000000000000000000054401466655022700233330ustar00rootroot00000000000000/*============================================================================== Copyright(c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ============================================================================*/ #ifndef UFO_PORTABLE_COMPILER_H #define UFO_PORTABLE_COMPILER_H #if __GNUC__ #if __GNUC__ < 4 #error "Unsupported GCC version. Please use 4.0+" #endif #define __noop #define __fastcall #if defined __x86_64__ #define __stdcall // deprecated for x86-64 #define __cdecl // deprecated for x86-64 #elif defined(__ARM_ARCH) #define __stdcall #define __cdecl #else #define __cdecl __attribute__((__cdecl__)) #define __stdcall __attribute__((__stdcall__)) #endif #define __declspec(x) __declspec_##x #define __declspec_align(y) __attribute__((aligned(y))) #define __declspec_deprecated __attribute__((deprecated)) #define __declspec_dllexport #define __declspec_dllimport #define __declspec_noinline __attribute__((__noinline__)) #define __declspec_nothrow __attribute__((nothrow)) #define __declspec_novtable #define __declspec_thread __thread #define __forceinline inline __attribute__((__always_inline__)) #define __debugbreak() do { asm volatile ("int3;"); } while (0) #define __popcnt __builtin_popcount #else #pragma message "unknown compiler!" #endif /* compile-time ASSERT */ #ifndef C_ASSERT #define __CONCATING( a1, a2 ) a1 ## a2 #define __UNIQUENAME( a1, a2 ) __CONCATING( a1, a2 ) #define UNIQUENAME( __text ) __UNIQUENAME( __text, __COUNTER__ ) #define C_ASSERT(e) typedef char UNIQUENAME(STATIC_ASSERT_)[(e)?1:-1] #endif #endif // UFO_PORTABLE_COMPILER_H gmmlib-intel-gmmlib-22.5.2/Source/inc/umKmInc/000077500000000000000000000000001466655022700210205ustar00rootroot00000000000000gmmlib-intel-gmmlib-22.5.2/Source/inc/umKmInc/UmKmDmaPerfTimer.h000066400000000000000000000251721466655022700243110ustar00rootroot00000000000000/*============================================================================== Copyright(c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ============================================================================ ** ** File Name: UmKmDmaPerfTimer.h ** ** Description: ** Contains perftag class and subtype codes used by km dma timer. ** ==============================================================================*/ #pragma once #if defined (LHDM) || defined(KM_PERF_CONTROLLER_BUILD) || defined(_PERF_REPORT) #include "UmKmEnum.h" #endif #include // Set packing alignment #pragma pack(push, 1) #ifdef __cplusplus extern "C" { #endif //=========================================================================== // typedef: // PERF_DATA // // Description: // //--------------------------------------------------------------------------- typedef struct _PERF_DATA { union { struct { uint32_t dmaBufID : 16; uint32_t frameID : 8; uint32_t bufferID : 4; uint32_t batchBufID : 4; }; uint32_t PerfTag; }; } PERF_DATA; //=========================================================================== // enum: // PERFTAG_CLASS_ENUM // // Description: // PerfTag class cmd buffer classification. // //--------------------------------------------------------------------------- //-------------------------------------------------------------------------------- // IMPORTANT NOTE: Please DONOT change the existing perftag values in below enum. // If adding a new perf tag, assign a new value //-------------------------------------------------------------------------------- typedef enum PERFTAG_CLASS_ENUM { PERFTAG_ALL = 0x0000, // Used for capturing all (perfcontroller) PERFTAG_KMD = 0x1000, PERFTAG_3D = 0x2000, PERFTAG_DECODE = 0x3000, // Media Decoding PERFTAG_DXVA2 = 0x4000, PERFTAG_LIBVA = 0x5000, PERFTAG_ENCODE = 0x6000, // Media Encoding PERFTAG_DXVAHD = 0x7000, PERFTAG_DXVA1 = 0x8000, PERFTAG_VPREP = 0x9000, PERFTAG_CM = 0xA000, // C for media PERFTAG_WIDI = 0xB000, PERFTAG_OCL = 0xC000, // OpenCL PERFTAG_PXP = 0xD000, // PXP PERFTAG_DXVA11 = 0xE000, // DX11 Video PERFTAG_FRAME_CAPTURE = 0xF000, // Gfx Frame Capture PERFTAG_FRAME_CAPTURE_NV12 = 0xF100, // Gfx Frame Capture with NV12 output PERFTAG_FRAME_CAPTURE_RGB8 = 0xF200, // Gfx Frame Capture with RGB8 output PERFTAG_UNKNOWN = 0x0FFF }PERFTAG_CLASS; #define PERFTAG_SUBTYPE(PerfTag) ( PerfTag & (ULONG)0x00000FFF ) // Bits[0,11] Usage component specific #define GET_PERFTAG_CLASS(PerfTag) ( PerfTag & (ULONG)0x0000F000 ) // Bits[12,15] #define PERFTAG_CLASS_AND_SUBTYPE(PerfTag) ( PerfTag & (ULONG)0x0000FFFF ) // Bits[0,15] #define PERFTAG_UNKNOWN_BITS(PerfTag) ( PerfTag & (ULONG)0xFFFF0000 ) // Bits[16,31] Usage component specific #define PERFTAG_FRAMEID(PerfTag) ( PerfTag & (ULONG)0x00FF0000 ) // Bits[16,23] Media Specific - frame id #define PERFTAG_BUFFERID(PerfTag) ( PerfTag & (ULONG)0x0F000000 ) // Bits[24,27] Media Specific - buffer id #define PERFTAG_BATCHBUFFERID(PerfTag) ( PerfTag & (ULONG)0xF0000000 ) // Bits[28,31] Media Specific - batch buffer id #define PERFTAG_FRAMEID_SHIFT 16 #define PERFTAG_BUFFERID_SHIFT 24 #define PERFTAG_BATCHBUFFERID_SHIFT 28 //=========================================================================== // enum: // VPHAL_PERFTAG // // Description: // Video Postprocessing perftag sub type. // NOTE: // Please follow instructions in below enum when adding new perf tag values. // Sub Tags (bits 11:0). // When adding new perf tag values, please update // Source\miniport\LHDM\KmPerfTools\PerfController\PerfReportGenerator.h // with the string. //--------------------------------------------------------------------------- typedef enum _VPHAL_PERFTAG { // No pri video VPHAL_NONE = 0x0, VPHAL_1LAYER , VPHAL_2LAYERS, VPHAL_3LAYERS, VPHAL_4LAYERS, VPHAL_5LAYERS, VPHAL_6LAYERS, VPHAL_7LAYERS, VPHAL_8LAYERS, // ADD NEW TAGS FOR NO PRI-VIDEO CASE HERE // pri video present VPHAL_PRI = 0x10, VPHAL_PRI_1LAYER, VPHAL_PRI_2LAYERS, VPHAL_PRI_3LAYERS, VPHAL_PRI_4LAYERS, VPHAL_PRI_5LAYERS, VPHAL_PRI_6LAYERS, VPHAL_PRI_7LAYERS, VPHAL_PRI_8LAYERS, // ADD NEW TAGS FOR PRI-VIDEO CASE HERE // video rotation present VPHAL_ROT = 0x20, VPHAL_ROT_1LAYER, VPHAL_ROT_2LAYERS, VPHAL_ROT_3LAYERS, VPHAL_ROT_4LAYERS, VPHAL_ROT_5LAYERS, VPHAL_ROT_6LAYERS, VPHAL_ROT_7LAYERS, VPHAL_ROT_8LAYERS, // PERFTAGs for AdvProc using VEBOX VPHAL_PA_DI_PA = 0x100, VPHAL_PA_DN_PA, VPHAL_PA_DNUV_PA, VPHAL_PA_DNDI_PA, VPHAL_PA_DI_422CP, VPHAL_PA_DN_422CP, VPHAL_PA_DNDI_422CP, VPHAL_PA_422CP, VPHAL_PA_DN_420CP, VPHAL_PA_420CP, VPHAL_PA_DN_RGB32CP, VPHAL_PA_RGB32CP, VPHAL_PL_DI_PA, VPHAL_PL_DI_422CP, VPHAL_NV12_DN_NV12, VPHAL_NV12_DNUV_NV12, VPHAL_NV12_DNDI_PA, VPHAL_NV12_DN_420CP, VPHAL_NV12_DN_422CP, VPHAL_NV12_DNDI_422CP, VPHAL_NV12_420CP, VPHAL_NV12_422CP, VPHAL_NV12_DN_RGB32CP, VPHAL_NV12_RGB32CP, VPHAL_PL3_DN_PL3, VPHAL_PL3_DNUV_PL3, VPHAL_PL3_DNDI_PA, VPHAL_PL3_DN_422CP, VPHAL_PL3_DNDI_422CP, VPHAL_PL3_422CP, VPHAL_VEBOX_RESERVED1, VPHAL_VEBOX_UPDATE_DN_STATE, VPHAL_VEBOX_ACE, VPHAL_VEBOX_FMD_VAR, VPHAL_VEBOX_P010, VPHAL_VEBOX_P016, VPHAL_VEBOX_P210, VPHAL_VEBOX_P216, VPHAL_VEBOX_Y210, VPHAL_VEBOX_Y216, VPHAL_VEBOX_Y410, VPHAL_VEBOX_Y416, VPHAL_VEBOX_AYUV, VPHAL_VEBOX_RGB32, VPHAL_VEBOX_RGB64, // PERFTAGs for AdvProc using Render VPHAL_ISTAB_PH1_PLY_PLY = 0x200, VPHAL_ISTAB_PH1_PA_PLY, VPHAL_ISTAB_PH2_ME_BS_ATOMIC, VPHAL_ISTAB_PH3_GMC_BS_ATOMIC, VPHAL_ISTAB_PH4_NV12_NV12_BS, VPHAL_ISTAB_PH4_PA_PA_BS, VPHAL_FRC_COPY, VPHAL_FRC_WIDE_SCREEN_DETECTION, VPHAL_FRC_PYRAMIDAL_SCALING, VPHAL_FRC_MOTION_ESTIMATION_L3, VPHAL_FRC_MV_VOTING_L3, VPHAL_FRC_MOTION_ESTIMATION_L2, VPHAL_FRC_MV_VOTING_L2, VPHAL_FRC_MOTION_ESTIMATION_L1, VPHAL_FRC_MV_VOTING_L1, VPHAL_FRC_GMV, VPHAL_FRC_MV_SANITY_CHECK, VPHAL_FRC_GRADIENT_Y, VPHAL_FRC_GRADIENT_UV, VPHAL_FRC_TEMPORAL_DIFF, VPHAL_FRC_SPD_MAP, VPHAL_FRC_CLEAN_MAP, VPHAL_FRC_MOTION_COMP, VPHAL_DRDB_NV12_DERING_NV12, VPHAL_DRDB_NV12_HDEBLOCK_NV12, VPHAL_DRDB_NV12_VDEBLOCK_NV12, VPHAL_3P, VPHAL_DPROTATION_NV12_NV12, VPHAL_DPROTATION_NV12_AVG, VPHAL_DPROTATION_NV12_REP, VPHAL_LACE_HIST_SUM, VPHAL_LACE_STD, VPHAL_LACE_PWLF, VPHAL_LACE_LUT, VPHAL_EU3DLUT, // Capture pipe present VPHAL_CP = 0x300, VPHAL_CP_BAYER8, VPHAL_CP_BAYER16, VPHAL_CP_LGCA_PH1_CALCPARAMS, VPHAL_CP_LGCA_PH2_GEOCORRECTION, // Hdr VPHAL_HDR_GENERIC = 0x400, VPHAL_HDR_1LAYER, VPHAL_HDR_2LAYERS, VPHAL_HDR_3LAYERS, VPHAL_HDR_4LAYERS, VPHAL_HDR_5LAYERS, VPHAL_HDR_6LAYERS, VPHAL_HDR_7LAYERS, VPHAL_HDR_8LAYERS, VPHAL_HDR_AUTO_PER_FRAME_STATE, // Fdfb - FD VPHAL_FDFB_FD_DOWNSCALE = 0x500, VPHAL_FDFB_FD_MLBP, VPHAL_FDFB_FD_CASCADE, VPHAL_FDFB_FD_CASCADE1, VPHAL_FDFB_FD_DOWNSCALE_NOT_FULLY_ENQUEUE, VPHAL_FDFB_FD_MLBP_NOT_FULLY_ENQUEUE, VPHAL_FDFB_FD_CASCADE_NOT_FULLY_ENQUEUE, VPHAL_FDFB_FD_CASCADE1_NOT_FULLY_ENQUEUE, VPHAL_FDFB_FD_MERGE, VPHAL_FDFB_FD_MERGE1, // Fdfb - FLD VPHAL_FDFB_FLD_CAL_GAUSSIAN_WEIGHT = 0x510, VPHAL_FDFB_FLD_PREPROCESSING, VPHAL_FDFB_FLD_RESIZE, VPHAL_FDFB_FLD_EXTRACT_FEATURE_GET_LANDMARK, VPHAL_FDFB_FLD_POST_PROCESSING, VPHAL_FDFB_FLD_VALIDATOR, VPHAL_FDFB_ELD_PREPROCESSING, VPHAL_FDFB_ELD_GET_LANDMARK, VPHAL_FDFB_ELD_POST_PROCESSING, VPHAL_FDFB_ELD_FILTERING, // Fdfb - FB VPHAL_FDFB_FB_VEBOX_SKIN_MAP = 0x520, VPHAL_FDFB_FB_CMK_AVERAGE_FILTER, VPHAL_FDFB_FB_CMK_PROCESSING, VPHAL_FDFB_FB_SMOOTHER, VPHAL_FDFB_FB_SKIN_BLENDER, VPHAL_FDFB_FB_CMK_FOUNDATION, VPHAL_FDFB_FB_CAL_REGIONS, VPHAL_FDFB_FB_CMK_BLUSH_MAP, VPHAL_FDFB_FB_CMK_EYE_CIRCLES, VPHAL_FDFB_FB_SMOOTHER_SKIN_ROI_BLENDER_0, VPHAL_FDFB_FB_SMOOTHER_SKIN_ROI_BLENDER_1, VPHAL_FDFB_FB_RED_LIP_CURVE_1, VPHAL_FDFB_FB_RED_LIP_CURVE_2, VPHAL_FDFB_FB_RED_LIP_CURVE_3, VPHAL_FDFB_FB_RED_LIP_CURVE_4, VPHAL_FDFB_FB_REFINE_LIP_MASK_1, VPHAL_FDFB_FB_REFINE_LIP_MASK_2, VPHAL_FDFB_FB_CMK_COLOR_LIP, VPHAL_FDFB_FB_CMK_BWD_WARP_SCALING, VPHAL_FDFB_FB_CMK_DATA_MOVE, VPHAL_FDFB_FB_CMK_BWD_WARP, VPHAL_FDFB_FB_MDF_SURFACE_COPY, VPHAL_FDFB_FB_RED_LIP, VPHAL_FDFB_FB_STD_GEN, VPHAL_FDFB_FB_CAL_EYECURVE, VPHAL_FDFB_FB_EYE_BRIGHT_PARAM_GEN, VPHAL_FDFB_FB_EYE_BRIGHT, VPHAL_FDFB_FB_EYE_LASH, VPHAL_FDFB_FB_EYE_LINE, VPHAL_FDFB_FB_TEETH_WHITEN, VPHAL_FDFB_FB_EYE_SAHDOW_MASK, VPHAL_FDFB_FB_EYE_SAHDOW, VPHAL_FDFB_FB_EYE_COLOR, // SR VPHAL_SR_CONV_1X1_32_5, VPHAL_SR_CONV_1X1_5_32, VPHAL_SR_CONV_3X3, VPHAL_SR_SUBPIXEL_CONV_2X2, VPHAL_SR_CONV_5X5_Y8, // ADD TAGS FOR NEW ADVPROC KRNS HERE VPHAL_PERFTAG_MAX } VPHAL_PERFTAG, *PVPHAL_PERFTAG; #ifdef __cplusplus } #endif // Reset packing alignment to project default #pragma pack(pop) gmmlib-intel-gmmlib-22.5.2/Source/inc/umKmInc/UmKmEnum.h000066400000000000000000000061741466655022700226770ustar00rootroot00000000000000/*============================================================================== Copyright(c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ============================================================================*/ #ifndef _UMKMENUM_H_ #define _UMKMENUM_H_ #ifdef __cplusplus extern "C" { #endif // PROCESSOR_FAMILY typedef enum PROCESSOR_FAMILY_REC { UNKNOWN_PROCESSOR, P3_PROCESSOR, P4_PROCESSOR, MAX_NUM_PROCESSOR } PROCESSOR_FAMILY; // GPU Engine typedef enum GPUENGINE_REC { GPUENGINE_1 = 0, GPUENGINE_2 = 1, // Dual GT Case GPUENGINE_MAX } GPUENGINE_ORDINAL; // GPUNODE // NOTE: the GPUNODE_*** enums that represent real nodes and have rings must // stay in sync with the corresponding ones defined in IGFX_GEN6_RING_TYPE typedef enum GPUNODE_REC { GPUNODE_3D = 0, // available by default on all platform GPUNODE_VIDEO = 1, // available on CTG+, Virtual node GPUNODE_BLT = 2, // available on GT GPUNODE_VE = 3, // available on HSW+ (VideoEnhancement), virtual node GPUNODE_VCS2 = 4, // available on BDW/SKL/KBL GT3+ and CNL, GPUNODE_CCS0 = 5, // GPUNODE_REAL_MAX, // all nodes beyond this are virtual nodes - they don't have an actual GPU engine GPUNODE_PICS = 6, // available on CNL+. Real node but only for KMD internal use. Hence kept after GPUNODE_REAL_MAX (Note: We need to keep it before overlay node) GPUNODE_OVERLAY = 7, GPUNODE_GDI2D = 8, // GT virtual node for GDI/Present 2D blt/colorfill GPUNODE_VXD = 9, // available on BYT GPUNODE_MAX } GPUNODE_ORDINAL; // UMD_DMA_TYPE typedef enum UMD_DMA_TYPE_REC { UMD_UNKNOWN = 0, UMD_MEDIA = 1, UMD_DX9 = 2, UMD_DX10 = 3, UMD_OGL = 4, UMD_OCL = 5, UMD_DX_COMPUTE = 6, UMD_DX12 = 7, UMD_TYPE_MAX // this should always be the last one } UMD_DMA_TYPE; typedef enum DXVA_OPERATION_ENUM { DXVA_OPERATION_NONE = 0, DXVA_OPERATION_DECODE, // Decode DXVA_OPERATION_ENCODE, // Encode } DXVA_OPERATION; extern char *UmdTypeStr[]; #ifdef __cplusplus } #endif #endif // _UMKMENUM_H_ gmmlib-intel-gmmlib-22.5.2/Source/inc/umKmInc/sharedata.h000066400000000000000000000312151466655022700231270ustar00rootroot00000000000000/*============================================================================== Copyright(c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ============================================================================ ** ** File Name: sharedata.h ** ** Description: These are data structures that are shared between the KMD ** and the UMD ** ==============================================================================*/ #ifndef _SHAREDATA_H_ #define _SHAREDATA_H_ #include "../common/gtsysinfo.h" #include "../common/sku_wa.h" #include "../common/igfxfmid.h" #include "UmKmEnum.h" #include "UmKmDmaPerfTimer.h" #define ADAPTER_STRING_SIZE 250 #ifdef __cplusplus extern "C" { #endif #define UMD_KMD_MAX_REGISTRY_PATH_LENGTH (512) //=========================================================================== // typedef: // DRIVER_VERION_INFO // // Description: // This structure is used to communicate Driver Build version between // KMD and UMD // //--------------------------------------------------------------------------- typedef struct __DRIVER_VERSION_INFO { unsigned :16; unsigned DriverBuildNumber :16; }DRIVER_VERSION_INFO; // BIT field, '1' (i.e. Set) means cap is supported by KMD typedef struct __KMD_CAPS_INFO { unsigned Gamma_Rgb256x3x16 :1; unsigned GDIAcceleration :1; unsigned OsManagedHwContext :1; // wddm1.2+ unsigned GraphicsPreemptionGranularity :3; // wddm1.2+ unsigned ComputePreemptionGranularity :3; // wddm1.2+ unsigned InstrumentationIsEnabled :1; // KMD instrumentation state unsigned DriverStoreEnabled :1; // wddm2.1+ unsigned :21; } KMD_CAPS_INFO; // Programmatically override overlay caps for testing typedef struct __KMD_OVERLAY_OVERRIDE { uint32_t OverrideOverlayCaps : 1; // Override request uint32_t RGBOverlay : 1; // RGB overlay override uint32_t YUY2Overlay : 1; // YUY2 overlay override uint32_t Reserved :29; } KMD_OVERLAY_OVERRIDE; // Overlay caps info needed by WDDM 1.1 Changes typedef struct __KMD_OVERLAY_CAPS_INFO { union { struct { uint32_t FullRangeRGB : 1; // 0x00000001 uint32_t LimitedRangeRGB : 1; // 0x00000002 uint32_t YCbCr_BT601 : 1; // 0x00000004 uint32_t YCbCr_BT709 : 1; // 0x00000008 uint32_t YCbCr_BT601_xvYCC : 1; // 0x00000010 uint32_t YCbCr_BT709_xvYCC : 1; // 0x00000020 uint32_t StretchX : 1; // 0x00000040 uint32_t StretchY : 1; // 0x00000080 uint32_t Reserved :24; // 0xFFFFFF00 } Caps; uint32_t CapsValue; }; KMD_OVERLAY_OVERRIDE OVOverride; uint32_t MaxOverlayDisplayWidth; uint32_t MaxOverlayDisplayHeight; uint8_t HWScalerExists; uint32_t MaxHWScalerStride; } KMD_OVERLAY_CAPS_INFO; // Frame Rate typedef struct { uint32_t uiNumerator; uint32_t uiDenominator; } FRAME_RATE; typedef struct __KM_SYSTEM_INFO { GT_SYSTEM_INFO SystemInfo; // ShadowReg 119 caluclated value required for WA uint32_t ShadowRegValue; uint32_t ShadowRegValueforL3SpecificRegReads; // Shadow reg value for L3 bank specific MMIO reads. uint32_t GfxDevId; // DeviceID }KM_SYSTEM_INFO; typedef struct _KM_DEFERRED_WAIT_INFO { uint32_t FeatureSupported; uint32_t ActiveDisplay; } KM_DEFERRED_WAIT_INFO; // struct to hold Adapter's BDF typedef struct _ADAPTER_BDF_ { union { struct { uint32_t Bus : 8; uint32_t Device : 8; uint32_t Function : 8; uint32_t Reserved : 8; }; uint32_t Data; }; }ADAPTER_BDF; // Private data structure for D3D callback QueryAdapterInfoCB //=========================================================================== // typedef: // _ADAPTER_INFO // // Description: // This structure is private data structure that get passed by UMD to // KMD during QueryAdapterInfoCB // // Note: Structure will be filled by KMD. //--------------------------------------------------------------------------- #pragma pack (push,1) typedef struct _ADAPTER_INFO { uint32_t KmdVersionInfo; // Version ID DRIVER_VERSION_INFO DriverVersionInfo; // PLATFORM GfxPlatform; // Chipset Gfx family, product, render core, display core, etc SKU_FEATURE_TABLE SkuTable; // SKU feature table WA_TABLE WaTable; // WA table uint32_t GfxTimeStampFreq; // In Hz (No. of clock ticks per second). So timestamp base = 1 / GfxTimeStampFreq uint32_t GfxCoreFrequency; // In MHz. uint32_t FSBFrequency; // In MHz. uint32_t MinRenderFreq; // In MHz. uint32_t MaxRenderFreq; // In MHz. uint32_t PackageTdp; // TDP Power for the platform (In Watt) uint32_t MaxFillRate; // Fillrate with Alphablend (In Pix/Clk) uint32_t NumberOfEUs; // Number of EUs in GT // NOTE: Name is kept same so that we don't have to change PC_TARGET macro and usage // of that. uint32_t dwReleaseTarget; // PC Release Target Information supplied by INF // Following member can be use by UMD for optimal use of DMA and // command buffer uint32_t SizeOfDmaBuffer; // Size of DMA buffer set (In Bytes) uint32_t PatchLocationListSize; // Size of Patch Location List (In number of entries) uint32_t AllocationListSize; // Size of Patch Location List (In number of entries) uint32_t SmallPatchLocationListSize; // Size of Patch Location List for UMD context that needs a small Patch Location List, // currently only used by media context (In number of entries) uint32_t DefaultCmdBufferSize; // Size of Cmd buffer default location // Following Members can be use for any UMD optimization (like Size of vertex buffer to allocate) // any cacheline related read/write, etc int64_t GfxMemorySize; // Total GFX memory (In MBytes) uint32_t SystemMemorySize; // Total System Memory (In MBytes) uint32_t CacheLineSize; // Processor CacheLine size PROCESSOR_FAMILY ProcessorFamily; // Processor Family uint8_t IsHTSupported; // Is Hyper Threaded CPU uint8_t IsMutiCoreCpu; // Is Multi Core CPU uint8_t IsVTDSupported; // Is Chipset VT is supported char DeviceRegistryPath[UMD_KMD_MAX_REGISTRY_PATH_LENGTH]; // Array that contains the device registry path uint32_t RegistryPathLength; // Actual chars (not including any trailing NULL) in the array set by the KMD int64_t DedicatedVideoMemory; // Dedicated Video Memory int64_t SystemSharedMemory; // System Shared Memory int64_t SystemVideoMemory; // SystemVideoMemory FRAME_RATE OutputFrameRate; // Output Frame Rate FRAME_RATE InputFrameRate; // Input Frame Rate KMD_CAPS_INFO Caps; // List of capabilities supported by the KMD KMD_OVERLAY_CAPS_INFO OverlayCaps; // List of overlay capabilities supported GT_SYSTEM_INFO SystemInfo; // List of system details KM_DEFERRED_WAIT_INFO DeferredWaitInfo; // Indicates if DeferredWait feature is enabled and value of active display #ifdef _WIN32 ADAPTER_BDF stAdapterBDF; // Adapter BDF #endif } ADAPTER_INFO, *PADAPTER_INFO; #pragma pack (pop) #define MAX_ENGINE_INSTANCE_PER_CLASS 4 // GEN11 Media Scalability 2.0: context based scheduling typedef struct MEDIA_CONTEXT_REQUIREMENT_REC { union { struct { uint32_t UsingSFC : 1; // Use SFC or not uint32_t HWRestrictedEngine : 1; #if (_DEBUG || _RELEASE_INTERNAL || __KMDULT) uint32_t Reserved : 29; uint32_t DebugOverride : 1; // Debug & validation usage #else uint32_t Reserved : 30; #endif }; uint32_t Flags; }; uint32_t LRCACount; // Logical engine instances used by this context; valid only if flag DebugOverride is set. uint8_t EngineInstance[MAX_ENGINE_INSTANCE_PER_CLASS]; } MEDIA_CONTEXT_REQUIREMENT, *PMEDIA_CONTEXT_REQUIREMENT; // Bit-Struct for Driver's Use of D3DDDI_PATCHLOCATIONLIST.DriverId typedef union __D3DDDI_PATCHLOCATIONLIST_DRIVERID { struct { uint32_t UseGlobalGtt : 1; // Indicates patch is to use global GTT space address (instead of PPGTT space). uint32_t HasDecryptBits : 1; uint32_t RenderTargetEnable : 1; // Indicates this is an output surface that may need to be encrypted int32_t DecryptBitDwordOffset : 8; // signed offset (in # of DWORDS) from the patch location to where the cmd's decrypt bit is uint32_t DecryptBitNumber : 5; // which bit to set in the dword specified by DecryptBitDwordOffset (0 - 31) uint32_t GpGpuCsrBaseAddress : 1; // this patch location is for the GPGPU Preempt buffer uint32_t SurfaceStateBaseAddress : 1; // Indicates this is patch for SBA.SurfaceStateBaseAddress uint32_t PreemptPatchType : 3; // Contains list of addresses that may need patching due to Preemption/Resubmit. uint32_t PatchLowDword : 1; // 32-bit patch despite 64-bit platform--Low DWORD. uint32_t PatchHighDword : 1; // 32-bit patch despite 64-bit platform--High DWORD. uint32_t StateSip : 1; // STATE_SIP address that needs to be patched in the context image (for thread-level preemption) uint32_t GpGpuWSDIBegin : 1; // The start of the SDI command seq before GPGPU_WALKER (for restarting thread-level workload) uint32_t GpGpuWSDIEnd : 1; // The end of the SDI command seq before GPGPU_WALKER (for restarting thread-level workload) uint32_t NullPatch : 1; // Don't perform KMD patching (used for SVM, Tiled/Sparse Resources and ExistingSysMem Virtual Padding). uint32_t UpperBoundsPatch : 1; // Indicates the patch is for an UpperBounds/"out-of-bounds" address uint32_t BindingTablePoolPatch : 1; // Indicates the patch is for Binding Table Pool. Needed for bindless head testing. Remove later. }; uint32_t Value; } D3DDDI_PATCHLOCATIONLIST_DRIVERID; #ifdef __cplusplus } #endif #endif // _SHAREDATA_H_ gmmlib-intel-gmmlib-22.5.2/Source/util/000077500000000000000000000000001466655022700176615ustar00rootroot00000000000000gmmlib-intel-gmmlib-22.5.2/Source/util/g_gfxDebug.h000066400000000000000000000202071466655022700220740ustar00rootroot00000000000000//=================================================================================/ //Copyright (c) 2017 Intel Corporation / // / //Permission is hereby granted, free of charge, to any person obtaining a copy / //of this software and associated documentation files (the "Software"), to deal / //in the Software without restriction, including without limitation the rights / //to use, copy, modify, merge, publish, distribute, sublicense, and/or sell / //copies of the Software, and to permit persons to whom the Software is furnished / //to do so, subject to the following conditions: / // //The above copyright notice and this permission notice shall be included in all / //copies or substantial portions of the Software. / // //THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR / //IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, / //FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE / //AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,/ //WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN / //CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. / //--------------------------------------------------------------------------------- #ifndef _G_GFXDEBUG_H_ #define _G_GFXDEBUG_H_ //===================== Debug Message Levels======================== // WARNING!!! DO NOT MODIFY this file - see detail above copyright. #define GFXDBG_OFF (0x00000000) #define GFXDBG_CRITICAL (0x00000001) #define GFXDBG_NORMAL (0x00000002) #define GFXDBG_VERBOSE (0x00000004) #define GFXDBG_FUNCTION (0x80000000) #define GFXDBG_NONCRITICAL (0x00000010) #define GFXDBG_CRITICAL_DEBUG (0x00000020) #define GFXDBG_VERBOSE_VERBOSITY (0x00000040) #define GFXDBG_PROTOCAL (0x00000100) #define GFXDBG_FUNCTION_ENTRY (0x80000000) #define GFXDBG_FUNCTION_EXIT (0x80000000) #define GFXDBG_FUNCTION_ENTRY_VERBOSE (0x20000000) #define GFXDBG_FUNCTION_EXIT_VERBOSE (0x20000000) // WARNING!!! DO NOT MODIFY this file - see detail above copyright. #define DBG_OFF GFXDBG_OFF #define DBG_CRITICAL GFXDBG_CRITICAL #define DBG_NORMAL GFXDBG_NORMAL #define DBG_VERBOSE GFXDBG_VERBOSE #define DBG_FUNCTION GFXDBG_FUNCTION #define DBG_NONCRITICAL GFXDBG_NONCRITICAL #define DBG_CRITICAL_DEBUG GFXDBG_CRITICAL_DEBUG #define DBG_VERBOSE_VERBOSITY GFXDBG_VERBOSE_VERBOSITY #define DBG_PROTOCAL GFXDBG_PROTOCAL #define DBG_FUNCTION_ENTRY GFXDBG_FUNCTION_ENTRY #define DBG_FUNCTION_EXIT GFXDBG_FUNCTION_EXIT #define DBG_FUNCTION_ENTRY_VERBOSE GFXDBG_FUNCTION_ENTRY_VERBOSE #define DBG_FUNCTION_EXIT_VERBOSE GFXDBG_FUNCTION_EXIT_VERBOSE // WARNING!!! DO NOT MODIFY this file - see detail above copyright. // This enum is used by DebugControlUI // Use #define GFXDBG_ to specify debug level in driver code. enum { GFXDBG_ML_OFF = 0, GFXDBG_ML_CRITICAL = 1, GFXDBG_ML_NORMAL = 2, GFXDBG_ML_VERBOSE = 3, GFXDBG_ML_FUNCTION = 4, GFXDBG_ML_COUNT = 5, }; //===================== Component ID's ============================= // WARNING!!! DO NOT MODIFY this file - see detail above copyright. enum { GFX_COMPONENT_GMM = 2, GFX_COMPONENT_COUNT = 12, }; //===================== Component Masks ============================ // WARNING!!! DO NOT MODIFY this file - see detail above copyright. enum { GFX_GMM_MASK = (1 << GFX_COMPONENT_GMM), }; //================= Component Memory Allocation Tags =============== // WARNING!!! DO NOT MODIFY this file - see detail above copyright. // // Tags are 4 byte ASCII character codes in the range 0-127 decimal. // The leading @ character is to provide Intel unique tags. // Passed in calls to ExAllocatePoolWithTag/ExFreePoolWithTag. // Useful for pool tracking. // #define GFX_COMPONENT_GMM_TAG 'MMG@' #define GFX_DEFAULT_TAG 'CTNI' //======================= Component ALLOC_TAG ====================== // WARNING!!! DO NOT MODIFY this file - see detail above copyright. #ifdef __MINIPORT #define REG_ASSERT_ENABLE_MASK L"z AssertEnableMask" #define REG_DEBUG_ENABLE_MASK L"z DebugEnableMask" #define REG_RINGBUF_DEBUG_MASK L"z RingBufDbgMask" #define REG_REPORT_ASSERT_ENABLE L"z ReportAssertEnable" #define REG_ASSERT_BREAK_DISABLE L"z AssertBreakDisable" #define REG_GFX_COMPONENT_GMM L"z GMM_Debug_Lvl" #endif //======================= Component ALLOC_TAG ====================== // WARNING!!! DO NOT MODIFY this file - see detail above copyright. #if defined(__MINIPORT) #define ALLOC_TAG GFX_COMPONENT_MINIPORT_TAG #elif defined(__SOFTBIOS) #define ALLOC_TAG GFX_COMPONENT_SOFTBIOS_TAG #elif defined(__KCH) #define ALLOC_TAG GFX_COMPONENT_KCH_TAG #elif defined(__AIM) #define ALLOC_TAG GFX_COMPONENT_AIM_TAG #else #define ALLOC_TAG GFX_DEFAULT_TAG #endif // WARNING!!! DO NOT MODIFY this file - see detail above copyright. #ifdef __GFXDEBUG_C__ // Only to be defined by "gfxDebug.c" file. // Define the array of component ID strings. Note that the sequence // of these strings must match the component ID's listed above. char *ComponentIdStrings[] = { "INTC GMM: ", }; #endif /* __GFXDEBUG_C__ */ //================ Prototype for print routines ==================== // WARNING!!! DO NOT MODIFY this file - see detail above copyright. #ifdef __cplusplus extern "C" { #endif void GMMPrintMessage(unsigned long DebugLevel, const char *DebugMessageFmt, ...); #ifdef __cplusplus } #endif //==================== Generate debug routines ===================== // WARNING!!! DO NOT MODIFY this file - see detail above copyright. // // Debug routines either map into the base PrintMessage // routine or they map into nothing. A code segment such as // 'DebugPrint(args)' gets converted to '(args)' which // is converted to nothing by the C compiler. #if __DEBUG_MESSAGE #define GMMDebugMessage GMMPrintMessage #define GMMDebugMessage(...) #else #define GMMDebugMessage(...) #endif /* __DEBUG_MESSSAGE */ //=================== Generate release routines ==================== // WARNING!!! DO NOT MODIFY this file - see detail above copyright. // // Release routines either map into the base PrintMessage // routine or they map into nothing. A code segment such as // 'ReleasePrint(args)' gets converted to '(args)' which // is converted to nothing by the C compiler. #if __RELEASE_MESSAGE #define GMMReleaseMessage GMMPrintMessage #else #define GMMReleaseMessage(...) #endif /* __RELEASE_MESSSAGE */ //=================== Generate ASSERT macros ====================== // WARNING!!! DO NOT MODIFY this file - see detail above copyright. #define GMMASSERT(expr) __ASSERT(pDebugControl, GFX_COMPONENT_GMM, GFX_GMM_MASK, expr) // WARNING!!! DO NOT MODIFY this file - see detail above copyright. #define GMMASSERTPTR(expr, ret) __ASSERTPTR(pDebugControl, GFX_COMPONENT_GMM, GFX_GMM_MASK, expr, ret) //=========== void return value for ASSERPTR macros ========================== #define VOIDRETURN //============= Generate Message printing routines ================= // WARNING!!! DO NOT MODIFY this file - see detail above copyright. #ifdef __GFXDEBUG_C__ // Only to be defined by "gfxDebug.c" file. #ifdef __GMM MESSAGE_FUNCTION(GMMPrintMessage, GFX_COMPONENT_GMM); #endif /* __GMM */ // WARNING!!! DO NOT MODIFY this file - see detail above copyright. #endif /* __GFXDEBUG_C__ */ #endif //_G_GFXDEBUG_H_ gmmlib-intel-gmmlib-22.5.2/Source/util/gfxDebug.h000066400000000000000000000450561466655022700215770ustar00rootroot00000000000000/*============================================================================== Copyright(c) 2017 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ============================================================================ ** ** File Name: gfxDebug.h ** ** Description: ** ** Environment: ** ** Notes: ** ============================================================================*/ #pragma once #ifndef _GFXDEBUG_H_ #define _GFXDEBUG_H_ #include #if defined(D3D) && !defined (USERMODE_DRIVER) // The D3D XP Kernel Mode driver will continue to use the old scheme until it // has been updated. #else // This portion is used by new stile debug scheme. // NOTE: There is some overlap between defines. //======================================================================== // Controlling Debug Messages: There are two types of output messages - // debug or release output message. These are controlled through the two // flags listed below. #ifdef _DEBUG #define __DEBUG_MESSAGE 1 #define __RELEASE_MESSAGE 1 #else #define __DEBUG_MESSAGE 0 #define __RELEASE_MESSAGE 1 #endif // !!! HAVE TO FIGURE OOUT HOW TO INCLUDE THIS CORRECTLY // #include "video.h" //==== Define global debug message routine =================== #if __DEBUG_MESSAGE || __RELEASE_MESSAGE #ifdef __UMD #include "stdlib.h" #define MESSAGE_FUNCTION(FUNCTION_NAME,COMPONENT_ID) \ \ void FUNCTION_NAME(unsigned long MessageLevel, const char *MessageFmt, ...) \ { \ uint32_t Length = 0; \ char *PrintBuffer = NULL; \ char *Prefix = NULL; \ va_list ArgList; \ \ unsigned long ComponentId = COMPONENT_ID; \ unsigned long ComponentMask = 1 << COMPONENT_ID; \ \ /* Ensure that CRITICAL messages are printed if the setting of the */ \ /* global debug variables flag is NORMAL or VERBOSE. Similarly, if */ \ /* the setting of the debug variables flag is NORMAL, ensure that */ \ /* the VERBOSE message are printed out too! */ \ \ if (MessageLevel & GFXDBG_CRITICAL) \ { \ MessageLevel |= GFXDBG_NORMAL | GFXDBG_VERBOSE; \ } \ else if (MessageLevel & GFXDBG_NORMAL) \ { \ MessageLevel |= GFXDBG_VERBOSE; \ } \ \ /* Some of routines need to call the debug message functionality */ \ /* before the DebugControl variable has been initialized. Hence, if */ \ /* pDebugControl is NULL, unconditionally print the debug message. */ \ \ if ((pDebugControl == NULL) || \ ((pDebugControl->DebugEnableMask & ComponentMask) && \ (MessageLevel & pDebugControl->DebugLevel[ComponentId]))) \ { \ va_start (ArgList, MessageFmt); \ Length = _vscprintf(MessageFmt, ArgList) + 1; \ PrintBuffer = malloc(Length * sizeof(char)); \ if (PrintBuffer) \ { \ vsprintf_s(PrintBuffer, Length, MessageFmt, ArgList); \ Prefix = ComponentIdStrings[ComponentId]; \ __MESSAGE_PRINT(Prefix, PrintBuffer); \ free(PrintBuffer); \ } \ else \ { \ __MESSAGE_PRINT("INTC DEBUG: ", \ "Can not allocate print buffer\n"); \ __debugbreak(); \ } \ va_end(ArgList); \ } \ } #else #ifndef __linux__ #include "igdKrnlEtwMacros.h" #endif #define MESSAGE_FUNCTION(FUNCTION_NAME,COMPONENT_ID) \ \ void FUNCTION_NAME(unsigned long MessageLevel, const char *MessageFmt, ...) \ { \ int32_t Length = 0; \ char PrintBuffer[GFX_MAX_MESSAGE_LENGTH]; \ char *Prefix = NULL; \ va_list ArgList; \ unsigned long GfxDbgLvl = MessageLevel; \ unsigned long ComponentId = COMPONENT_ID; \ unsigned long ComponentMask = 1 << COMPONENT_ID; \ \ /* Ensure that CRITICAL messages are printed if the setting of the */ \ /* global debug variables flag is NORMAL or VERBOSE. Similarly, if */ \ /* the setting of the debug variables flag is NORMAL, ensure that */ \ /* the VERBOSE message are printed out too! */ \ \ if (MessageLevel & GFXDBG_CRITICAL) \ { \ MessageLevel |= GFXDBG_NORMAL | GFXDBG_VERBOSE; \ } \ else if (MessageLevel & GFXDBG_NORMAL) \ { \ MessageLevel |= GFXDBG_VERBOSE; \ } \ \ /* Some of routines need to call the debug message functionality */ \ /* before the DebugControl variable has been initialized. Hence, if */ \ /* pDebugControl is NULL, unconditionally print the debug message. */ \ \ va_start(ArgList, MessageFmt); \ Length = _vsnprintf_s(PrintBuffer, GFX_MAX_MESSAGE_LENGTH, \ sizeof(PrintBuffer), \ MessageFmt, ArgList); \ if (Length >= 0) \ { \ EtwDebugPrint((uint16_t)GfxDbgLvl, (uint16_t)ComponentId, PrintBuffer); \ \ if ((pDebugControl == NULL) || \ ((pDebugControl->DebugEnableMask & ComponentMask) && \ (MessageLevel & pDebugControl->DebugLevel[ComponentId]))) \ { \ Prefix = ComponentIdStrings[ComponentId]; \ __MESSAGE_PRINT(Prefix, PrintBuffer); \ } \ } \ else \ { \ __MESSAGE_PRINT("INTC DEBUG: ", \ "The print buffer is to small\n"); \ __debugbreak(); \ } \ va_end(ArgList); \ } \ #endif #endif // __DEBUG_MESSAGE || __RELEASE_MESSAGE // Define a max size for the intermediate buffer for storing the // debug error message string. #define GFX_MAX_MESSAGE_LENGTH (512) //============================================================================== // From winnt.h // // C_ASSERT() can be used to perform many COMPILE-TIME assertions: // type sizes, field offsets, etc. // // An assertion failure results in error C2118: negative subscript. // // When this assertion is to be used in the middle of a code block, // use it within {} - e.g. {__GL_C_ASSERT (__GL_NUM == 0);} // // Since all components may not want to include "winnt.h", define a // C_ASSERT that can be used by all components. #ifndef GFX_C_ASSERT #define GFX_C_ASSERT(e) typedef char __GFX_C_ASSERT__[(e)?1:-1] #endif // Unfortunately, we cannot include "g_debug.h" before this structure // definition since it needs this structure - but then this structure // requires the number of components. We get around this by using a // large enough number for the component count. #define MAX_COMPONENT_COUNT_DONOTUSE (20) //------------------------------------------------------------------------------ // Debug and assert control structure. Note that each component has // a separate variable to control its debug level. //------------------------------------------------------------------------------ typedef struct GFX_DEBUG_CONTROL_REC { unsigned long Version; unsigned long Size; unsigned long AssertEnableMask; unsigned long EnableDebugFileDump; unsigned long DebugEnableMask; unsigned long RingBufDbgMask; unsigned long ReportAssertEnable; unsigned long AssertBreakDisable; #ifndef __UMD unsigned long DebugLevel[MAX_COMPONENT_COUNT_DONOTUSE]; #endif } GFX_DEBUG_CONTROL, *PGFX_DEBUG_CONTROL; #ifdef __cplusplus extern "C" { #endif #ifdef __GFXDEBUG_C__ // Only to be defined by "gfxDebug.c" file. GFX_DEBUG_CONTROL *pDebugControl = NULL; #else extern GFX_DEBUG_CONTROL *pDebugControl; #endif #ifdef __cplusplus } #endif void InitializeDebugVariables(PGFX_DEBUG_CONTROL pDebugControl); #if (defined(_DEBUG) || defined( _RELEASE_INTERNAL )) #if ( !defined(REPORT_ASSERT) || !defined(REPORT_ASSERT_ETW)) && defined( _WIN32 ) #include "AssertTracer.h" #elif !defined(REPORT_ASSERT) #define REPORT_ASSERT( expr ) #define REPORT_ASSERT_ETW(compId, componentMask, expr) #endif #endif #ifdef _DEBUG // This function doesn't do anything, it exists so you can put // a break point at the XXX_ASSERT and when you step into it // you will step into this function and then you can // disable/enable the assert by setting AssertOn to FALSE/TRUE. #ifdef _MSC_VER static __inline int ToggleAssert(int AssertOn) #else static inline int ToggleAssert(int AssertOn) #endif { return AssertOn; }; #define __ASSERT(pDebugControl, compId, componentMask, expr) \ { \ static int __assertOn = TRUE; \ __assertOn = ToggleAssert(__assertOn); \ REPORT_ASSERT_ETW(compId, componentMask, expr); \ if (__assertOn) \ { \ if(!(pDebugControl)) \ { \ if(!(expr)) \ { \ REPORT_ASSERT(expr); \ __debugbreak(); \ } \ } \ else \ { \ if (((componentMask) & pDebugControl->AssertEnableMask) && \ !(expr)) \ { \ if(pDebugControl->ReportAssertEnable) \ { \ REPORT_ASSERT(expr); \ } \ if(!pDebugControl->AssertBreakDisable) \ { \ __debugbreak(); \ } \ } \ \ } \ } \ } #define __ASSERTPTR(pDebugControl, compId, componentMask, expr, ret) \ { \ __ASSERT(pDebugControl, compId, componentMask, expr); \ if (!expr) \ { \ return ret; \ } \ } #elif defined(_RELEASE_INTERNAL) #define __ASSERT(pDebugControl, compId, compMask, expr) \ { \ REPORT_ASSERT_ETW(compId, compMask, expr); \ } #define __ASSERTPTR(pDebugControl, compId, compMask, expr, ret) \ { \ __ASSERT(pDebugControl, compId, compMask, expr); \ if (!expr) \ { \ return ret; \ } \ } #else #define __ASSERT(pDebugControl, compId, compMask, expr) #define __ASSERTPTR(pDebugControl, compId, compMask ,expr, ret) #endif // _DEBUG #define __RELEASEASSERT(pDebugControl, componentMask, expr) \ { \ if (((componentMask) & pDebugControl->AssertEnableMask) && !(expr)) \ { \ __debugbreak(); \ } \ } // The common code may use a macro such as "GFXASSERT". This is defined // to be UMD or KMD ASSERT based on the component being compiled. #ifdef __UMD #define GFXASSERT UMDASSERT #else #define GFXASSERT KM_ASSERT #endif #include #include "g_gfxDebug.h" // Include automatically generated component // specific macros etc. GFX_C_ASSERT(MAX_COMPONENT_COUNT_DONOTUSE >= GFX_COMPONENT_COUNT); // !!! WE MIGHT BE ABLE TO DELETE THE FOLLOWING, DOUBLE CHECK FIRST // Ring buffer proxy #define ENABLE_RINGBUF_PROXY_IN_RELEASE_BUILD 0 #endif // D3D not defined #endif // _GFXDEBUG_H_ gmmlib-intel-gmmlib-22.5.2/Tools/000077500000000000000000000000001466655022700165445ustar00rootroot00000000000000gmmlib-intel-gmmlib-22.5.2/Tools/bldsys/000077500000000000000000000000001466655022700200445ustar00rootroot00000000000000gmmlib-intel-gmmlib-22.5.2/Tools/bldsys/bs_init.cmake000077500000000000000000000045571466655022700225130ustar00rootroot00000000000000# Copyright(c) 2017 Intel Corporation # Permission is hereby granted, free of charge, to any person obtaining a # copy of this software and associated documentation files(the "Software"), # to deal in the Software without restriction, including without limitation # the rights to use, copy, modify, merge, publish, distribute, sublicense, # and / or sell copies of the Software, and to permit persons to whom the # Software is furnished to do so, subject to the following conditions: # The above copyright notice and this permission notice shall be included # in all copies or substantial portions of the Software. # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS # OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL # THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR # OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, # ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR # OTHER DEALINGS IN THE SOFTWARE. if(NOT DEFINED BS_USE_OSDM_BUILD_SYSTEM) if(DEFINED ENV{BS_USE_OSDM_BUILD_SYSTEM}) set(BS_USE_OSDM_BUILD_SYSTEM "$ENV{BS_USE_OSDM_BUILD_SYSTEM}") else() set(BS_USE_OSDM_BUILD_SYSTEM TRUE) endif() endif() include(${BUILD_SYS_INC}/bs_base_utils.cmake) bs_check_build_type() if(DEFINED UFO_ANDROID_VERSION) add_definition(-DANDROID_VERSION=${UFO_ANDROID_VERSION}) elseif(DEFINED ENV{UFO_ANDROID_VERSION}) add_definition(-DANDROID_VERSION=$ENV{UFO_ANDROID_VERSION}) endif() # Ensure definitions for some variables that should be set by the overall build system. bs_set_if_undefined(PLATFORM "linux") bs_set_if_undefined(GFXGEN "9") bs_set_if_undefined(CXXFLAGS "-D_GLIBCXX_USE_CXX11_ABI=0") # Other useful definitions bs_set_if_undefined(CMAKE_EXPORT_COMPILE_COMMANDS "ON") bs_set_if_undefined(CMAKE_VERBOSE_MAKEFILE "1") ## bs_set_if_undefined(UFO_CMAKE_DEBUG "ON") ## bs_set_if_undefined(BUILD_VERSION_STRING "9999") include(${BUILD_SYS_INC}/bs_dir_names.cmake) # Needed for bs_add_some_common_includes include(${BUILD_SYS_INC}/utils.cmake) if(BS_USE_OSDM_BUILD_SYSTEM) include(${BUILD_SYS_INC}/stdvars.cmake) include(${BUILD_SYS_DIR}/build_sys.cmake) bs_set_base_flags() endif(BS_USE_OSDM_BUILD_SYSTEM) gmmlib-intel-gmmlib-22.5.2/Tools/bldsys/include/000077500000000000000000000000001466655022700214675ustar00rootroot00000000000000gmmlib-intel-gmmlib-22.5.2/Tools/bldsys/include/bs_base_utils.cmake000077500000000000000000000136211466655022700253150ustar00rootroot00000000000000# Copyright(c) 2017 Intel Corporation # Permission is hereby granted, free of charge, to any person obtaining a # copy of this software and associated documentation files(the "Software"), # to deal in the Software without restriction, including without limitation # the rights to use, copy, modify, merge, publish, distribute, sublicense, # and / or sell copies of the Software, and to permit persons to whom the # Software is furnished to do so, subject to the following conditions: # The above copyright notice and this permission notice shall be included # in all copies or substantial portions of the Software. # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS # OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL # THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR # OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, # ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR # OTHER DEALINGS IN THE SOFTWARE. if(NOT DEFINED _bs_include_base_utils) set(_bs_include_base_utils TRUE) # bs_set_if_undefined - If not defined, assign value from env or arg macro(bs_set_if_undefined VAR_NAME VAR_VALUE) if(DEFINED ${VAR_NAME} AND NOT ${VAR_NAME} STREQUAL "") # Already defined elseif(DEFINED ENV{VAR_NAME} AND NOT "$ENV{VAR_NAME}" STREQUAL "") set(${VAR_NAME} "$ENV{VAR_NAME}") else() set(${VAR_NAME} "${VAR_VALUE}") endif() endmacro() macro(bs_compare_build_type _bs_compare_var) if ("${_bs_compare_var}" STREQUAL "Release" OR "${_bs_compare_var}" STREQUAL "release") set(T_CMAKE_BUILD_TYPE "Release") set(BUILD_TYPE "release") elseif ("${_bs_compare_var}" STREQUAL "ReleaseInternal" OR "${_bs_compare_var}" STREQUAL "release-internal" OR "${_bs_compare_var}" STREQUAL "Release-Internal") set(T_CMAKE_BUILD_TYPE "ReleaseInternal") set(BUILD_TYPE "release-internal") elseif ("${_bs_compare_var}" STREQUAL "Debug" OR "${_bs_compare_var}" STREQUAL "debug") set(T_CMAKE_BUILD_TYPE "Debug") set(BUILD_TYPE "debug") elseif ("${_bs_compare_var}" STREQUAL "RelWithDebInfo" OR "${_bs_compare_var}" STREQUAL "RELWITHDEBINFO" OR "${_bs_compare_var}" STREQUAL "relwithdebinfo") set(T_CMAKE_BUILD_TYPE "RelWithDebInfo") set(BUILD_TYPE "RelWithDebInfo") elseif ("${_bs_compare_var}" STREQUAL "MinSizeRel" OR "${_bs_compare_var}" STREQUAL "MINSIZEREL" OR "${_bs_compare_var}" STREQUAL "minsizerel") set(T_CMAKE_BUILD_TYPE "MinSizeRel") set(BUILD_TYPE "MinSizeRel") else() #Pass the flag as received from user, Could be a custom flag setting message("Build Type: ${_bs_compare_var} is a custom build type") set(T_CMAKE_BUILD_TYPE "${_bs_compare_var}") set(BUILD_TYPE "${_bs_compare_var}") endif() endmacro() set(_bs_check_build_type_done 0) # function bs_check_build_type # Deal with the ambiguity of the three different variables for BUILD_TYPE: # Give them priority in this order: # UFO_BUILD_TYPE # BUILD_TYPE # Note: Despite the similarity of name, CMAKE_BUILD_TYPE is not analogous # to UFO_BUILD_TYPE and BUILD_TYPE. function(bs_check_build_type) if(DEFINED CMAKE_BUILD_TYPE AND NOT "${CMAKE_BUILD_TYPE}" STREQUAL "" AND NOT "${CMAKE_BUILD_TYPE}" STREQUAL "None") set(_bs_check_build_type_done 1 PARENT_SCOPE) bs_compare_build_type("${CMAKE_BUILD_TYPE}") set(CMAKE_BUILD_TYPE "${T_CMAKE_BUILD_TYPE}" PARENT_SCOPE) #set in parent scope set(CMAKE_BUILD_TYPE "${T_CMAKE_BUILD_TYPE}") #set in current scope set(BUILD_TYPE "${BUILD_TYPE}" PARENT_SCOPE) message(STATUS "Single-configuration generator. Build type : ${CMAKE_BUILD_TYPE}") elseif(DEFINED BUILD_TYPE AND NOT "${BUILD_TYPE}" STREQUAL "") set(_bs_check_build_type_done 1 PARENT_SCOPE) bs_compare_build_type("${BUILD_TYPE}") set(CMAKE_BUILD_TYPE "${T_CMAKE_BUILD_TYPE}" PARENT_SCOPE) #set in parent scope set(CMAKE_BUILD_TYPE "${T_CMAKE_BUILD_TYPE}") #set in current scope set(BUILD_TYPE "${BUILD_TYPE}" PARENT_SCOPE) message(STATUS "Single-configuration generator. Build type : ${CMAKE_BUILD_TYPE}") else() # If Build Type is not passed, Set as release builds as default if(NOT ${_bs_check_build_type_done}) set(_bs_check_build_type_done 1 PARENT_SCOPE) set(_bs_bt_var_names UFO_BUILD_TYPE BUILD_TYPE) foreach(_bs_bt_var_a ${_bs_bt_var_names}) foreach(_bs_bt_var_b ${_bs_bt_var_names}) if(NOT _bs_bt_var_a STREQUAL _bs_bt_var_b) if(DEFINED ${_bs_bt_var_a} AND DEFINED ${_bs_bt_var_b} AND NOT ${_bs_bt_var_a} STREQUAL ${_bs_bt_var_b}) message(FATAL_ERROR "Conflict: ${_bs_bt_var_a}=${${_bs_bt_var_a}} vs ${_bs_bt_var_b=${${_bs_bt_var_b}}}") endif() endif() endforeach() endforeach() set(_bs_bt_value "") foreach(_bs_bt_var_a ${_bs_bt_var_names}) if(DEFINED ${_bs_bt_var_a}) set(_bs_bt_value ${${_bs_bt_var_a}}) break() endif() endforeach() if(_bs_bt_value STREQUAL "") message("*BUILD_TYPE not defined, default to: release") set(_bs_bt_value "release") endif() foreach(_bs_bt_var_a ${_bs_bt_var_names}) if(NOT DEFINED ${_bs_bt_var_a}) set(${_bs_bt_var_a} "${_bs_bt_value}" PARENT_SCOPE) endif() endforeach() endif() endif() endfunction(bs_check_build_type) endif(NOT DEFINED _bs_include_base_utils) gmmlib-intel-gmmlib-22.5.2/Tools/bldsys/include/bs_dir_names.cmake000077500000000000000000000044131466655022700251230ustar00rootroot00000000000000# Copyright(c) 2017 Intel Corporation # Permission is hereby granted, free of charge, to any person obtaining a # copy of this software and associated documentation files(the "Software"), # to deal in the Software without restriction, including without limitation # the rights to use, copy, modify, merge, publish, distribute, sublicense, # and / or sell copies of the Software, and to permit persons to whom the # Software is furnished to do so, subject to the following conditions: # The above copyright notice and this permission notice shall be included # in all copies or substantial portions of the Software. # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS # OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL # THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR # OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, # ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR # OTHER DEALINGS IN THE SOFTWARE. if(NOT DEFINED _bs_include_dir_names) set(_bs_include_dir_names TRUE) include(${BUILD_SYS_INC}/bs_base_utils.cmake) if(NOT DEFINED GFX_DEVELOPMENT_DIR) if(DEFINED ENV{GFX_DEVELOPMENT_DIR}) set(GFX_DEVELOPMENT_DIR "$ENV{GFX_DEVELOPMENT_DIR}") else() message(FATAL_ERROR "Required variable not defined: GFX_DEVELOPMENT_DIR") endif() endif(NOT DEFINED GFX_DEVELOPMENT_DIR) # base dir vars # # These will be used later to help with separation of components. # bs_set_if_undefined(BS_DIR_SOURCE "${GFX_DEVELOPMENT_DIR}/Source") bs_set_if_undefined(BS_DIR_COMMON "${BS_DIR_SOURCE}/Common") bs_set_if_undefined(BS_DIR_3D_COMMON "${BS_DIR_SOURCE}/3d/common") bs_set_if_undefined(BS_DIR_GMMLIB "${BS_DIR_SOURCE}/GmmLib") bs_set_if_undefined(BS_DIR_INC "${BS_DIR_SOURCE}/inc") bs_set_if_undefined(BS_DIR_INSTALL "${BS_DIR_SOURCE}/install") bs_set_if_undefined(BS_DIR_MEDIA "${BS_DIR_SOURCE}/media") bs_set_if_undefined(BS_DIR_OPENCL "${BS_DIR_SOURCE}/OpenCL") bs_set_if_undefined(BS_DIR_UTIL "${BS_DIR_SOURCE}/util") endif(NOT DEFINED _bs_include_dir_names) gmmlib-intel-gmmlib-22.5.2/Tools/bldsys/include/utils.cmake000077500000000000000000000273711466655022700236460ustar00rootroot00000000000000# Copyright(c) 2017 Intel Corporation # Permission is hereby granted, free of charge, to any person obtaining a # copy of this software and associated documentation files(the "Software"), # to deal in the Software without restriction, including without limitation # the rights to use, copy, modify, merge, publish, distribute, sublicense, # and / or sell copies of the Software, and to permit persons to whom the # Software is furnished to do so, subject to the following conditions: # The above copyright notice and this permission notice shall be included # in all copies or substantial portions of the Software. # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS # OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL # THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR # OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, # ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR # OTHER DEALINGS IN THE SOFTWARE. # utility functions for cmake if(NOT DEFINED _bs_include_utils) set(_bs_include_utils TRUE) include(${BUILD_SYS_INC}/bs_base_utils.cmake) # macro bs_assignments_from_file - Execute a file of assignments. # This must be a macro and not a function so as to not provide an # additional level of symbol scope. # # For an example, see file include/bs_enable.mk . # # Example file content: # # A comment looks like this. Assignments follow: # BS_ENABLE_gmmlib = 0 # BS_ENABLE_igc = 0 macro(bs_assignments_from_file file_path) file(STRINGS "${file_path}" bsa_list) bs_assignments_from_string("${bsa_list}") endmacro(bs_assignments_from_file) # Function to capitalize SourceString and return # the result on ResultString function(_bs_capitalize SourceString ResultString) string(SUBSTRING ${SourceString} 0 1 FIRST_LETTER) string(TOUPPER ${FIRST_LETTER} FIRST_LETTER) string(REGEX REPLACE "^.(.*)" "${FIRST_LETTER}\\1" CapString "${SourceString}") set(${ResultString} ${CapString} PARENT_SCOPE) endfunction(_bs_capitalize) # Function to return the canonical string for gen # Ex: gen7.5 becomes gen75 function(bs_canonicalize_string_gen SourceGen AllGens) if ( ${SourceGen} MATCHES "[0-9].[0-9]") STRING(REPLACE "." "" tempstr ${SourceGen}) else() set(tempstr "${SourceGen}0") endif() set(${AllGens} ${tempstr} PARENT_SCOPE) endfunction(bs_canonicalize_string_gen) # bs_list_to_string - Convert a cmake list to a string. macro(bs_list_to_string varnam) string(REPLACE ";" " " ${varnam} "${${varnam}}") endmacro(bs_list_to_string) # bs_string_to_list - Convert a string to a cmake list. macro(bs_string_to_list varnam) string(REPLACE " " ";" ${varnam} "${${varnam}}") endmacro(bs_string_to_list) # Macro to find the xsltproc installed on # the system. macro(bs_find_xsltproc) if (NOT ${PLATFORM} STREQUAL Windows) find_program(XSLTPROC xsltproc) else() find_program(XSLTPROC NAMES xslt msxsl msxsl.exe PATHS "${BS_DIR_INSTRUMENTATION}/tools") endif() endmacro(bs_find_xsltproc) # Macro to find the python installed on # the system. macro(bs_find_python) if (NOT ${PLATFORM} STREQUAL Windows) find_program(PYTHON python) else() find_program(PYTHON NAMES python.exe PATHS "${GFX_DEVELOPMENT_DIR}/Tools/Build/scripts/deps/python27" NO_DEFAULT_PATH) endif() message("python is ${PYTHON}") endmacro(bs_find_python) # Macro to find the flex installed on # the system. macro(bs_find_flex) if (NOT ${PLATFORM} STREQUAL Windows) find_program(FLEX flex) else() find_program(FLEX NAMES flex flex.exe PATHS "${GFX_DEVELOPMENT_DIR}/Tools//OpenGL/BisonFlex/win") endif() endmacro(bs_find_flex) # Macro to find the bison installed on # the system. macro(bs_find_bison) if (NOT ${PLATFORM} STREQUAL Windows) find_program(BISON bison) else() find_program(BISON NAMES bison bison.exe PATHS "${GFX_DEVELOPMENT_DIR}/Tools//OpenGL/BisonFlex/win") endif() endmacro(bs_find_bison) # Macro to find the patch installed on # the system. macro(bs_find_patch) find_program(PATCH NAMES patch patch.exe) endmacro() macro(bs_find_7z) if (NOT ${PLATFORM} STREQUAL Windows) find_program(7Z NAMES 7za 7z) else() find_program(7Z NAMES 7z.exe PATHS "${GFX_DEVELOPMENT_DIR}/Tools/Build/scripts/deps/7zip") endif() endmacro() function(bs_check_component_enable component_name enable_flag_name) set(_component_enable "${BS_ENABLE_${component_name}}") if("${_component_enable}" STREQUAL "1") set(_enable_flag 1) elseif("${_component_enable}" STREQUAL "W") if("${PLATFORM}" STREQUAL "Windows") set(_enable_flag 1) else() set(_enable_flag 0) endif() elseif("${_component_enable}" STREQUAL "NW") if(NOT "${PLATFORM}" STREQUAL "Windows") set(_enable_flag 1) else() set(_enable_flag 0) endif() elseif("${_component_enable}" STREQUAL "0") set(_enable_flag 0) elseif("${_component_enable}" STREQUAL "t") set(_enable_flag 0) message(WARNING "${CMAKE_CURRENT_LIST_FILE}: warning: Obsolete component enable flag, now same as 0: ${component_name}: \"${_component_enable}\"") else() set(_enable_flag 0) message(SEND_ERROR "${CMAKE_CURRENT_LIST_FILE}: error: Invalid component enable flag: ${component_name}: \"${_component_enable}\"") endif() if("${_enable_flag}") message("${CMAKE_CURRENT_LIST_FILE}: component enabled (${_component_enable}): ${component_name}") else() message("${CMAKE_CURRENT_LIST_FILE}: component disabled: ${component_name}") endif() set(${enable_flag_name} ${_enable_flag} PARENT_SCOPE) endfunction(bs_check_component_enable) # macro to setup output name to OUTPUT_NAME # and turn on position independent code. This # was pulled in to cover the separate v2c hooks # that each component was using to a standard macro # for Linux builds only. Can be extended to # cover other OS targets without the need to update # individual component lists. macro(bs_set_post_target) if (${PLATFORM} STREQUAL linux) set_property(TARGET ${LIB_NAME} PROPERTY OUTPUT_NAME ${OUTPUT_NAME}) set_property(TARGET ${LIB_NAME} PROPERTY POSITION_INDEPENDENT_CODE ON) endif(${PLATFORM} STREQUAL linux) endmacro() # macro to setup standard defines This # was pulled in to cover the separate v2c hooks # that each component was using to a standard macro # Can be extended to cover more OS targets without the need to update # individual component lists. macro(bs_set_defines) if (${PLATFORM} STREQUAL linux) add_definitions(-D__STDC_LIMIT_MACROS) add_definitions(-D__STDC_CONSTANT_MACROS) endif (${PLATFORM} STREQUAL linux) endmacro() # macro to setup forced exceptions for Linux # builds only. Should be extended for other # targets that require forced exceptions. macro(bs_set_force_exceptions) if (${PLATFORM} STREQUAL "linux") string(REPLACE "no-exceptions" "exceptions" CMAKE_C_FLAGS "${CMAKE_C_FLAGS}") string(REPLACE "no-exceptions" "exceptions" CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG}") string(REPLACE "no-exceptions" "exceptions" CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE}") string(REPLACE "no-exceptions" "exceptions" CMAKE_C_FLAGS_RELEASEINTERNAL "${CMAKE_C_FLAGS_RELEASEINTERNAL}") string(REPLACE "no-exceptions" "exceptions" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") string(REPLACE "no-exceptions" "exceptions" CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG}") string(REPLACE "no-exceptions" "exceptions" CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE}") string(REPLACE "no-exceptions" "exceptions" CMAKE_CXX_FLAGS_RELEASEINTERNAL "${CMAKE_CXX_FLAGS_RELEASEINTERNAL}") string(REPLACE "-DNO_EXCEPTION_HANDLING" "" CMAKE_C_FLAGS "${CMAKE_C_FLAGS}") string(REPLACE "-DNO_EXCEPTION_HANDLING" "" CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG}") string(REPLACE "-DNO_EXCEPTION_HANDLING" "" CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE}") string(REPLACE "-DNO_EXCEPTION_HANDLING" "" CMAKE_C_FLAGS_RELEASEINERNAL "${CMAKE_C_FLAGS_RELEASEINERNAL}") string(REPLACE "-DNO_EXCEPTION_HANDLING" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") string(REPLACE "-DNO_EXCEPTION_HANDLING" "" CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG}") string(REPLACE "-DNO_EXCEPTION_HANDLING" "" CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE}") string(REPLACE "-DNO_EXCEPTION_HANDLING" "" CMAKE_CXX_FLAGS_RELEASEINTERNAL "${CMAKE_CXX_FLAGS_RELEASEINTERNAL}") endif() endmacro() # function to force an error if a variable if it is not # defined function(bs_fatal_if_undefined) string(REPLACE " " ";" _var_names "${ARGV}") set(_undef_seen FALSE) foreach(_varnam ${_var_names}) if(NOT DEFINED ${_varnam}) message(SEND_ERROR "Required variable not defined: ${_varnam}") set(_undef_seen TRUE) endif() endforeach() if(_undef_seen) message(FATAL_ERROR "Stopping due to undefined variables") endif(_undef_seen) endfunction(bs_fatal_if_undefined) # macro to return the llvm directory path # for host and target builds. macro(bs_get_llvm_dir) set(LLVM_DIR ${DUMP_DIR}/igc/llvm/${LLVM_INT_DIR}) set(CODEGEN_DIR ${DUMP_DIR}/codegen) endmacro() # macro to add common includes used by multiple components. macro(bs_add_some_common_includes) bs_fatal_if_undefined(PLATFORM) if (${PLATFORM} STREQUAL linux) bs_get_llvm_dir() bs_fatal_if_undefined(CODEGEN_DIR LLVM_DIR GFX_DEVELOPMENT_DIR) include_directories(${CODEGEN_DIR}) include_directories(${LLVM_DIR}/include) include_directories(${GFX_DEVELOPMENT_DIR}/Source/OpenGL/source/os/linux/oskl) if(NOT "${LIBDRM_SRC}" STREQUAL "") message("using LIBDRM_SRC=${LIBDRM_SRC}") include_directories(${LIBDRM_SRC}) include_directories(${LIBDRM_SRC}/include/drm) include_directories(${LIBDRM_SRC}/intel) else() include_directories(${BS_DIR_OPENGL}/source/os/linux/oskl/drm_intel) include_directories(${BS_DIR_INSTRUMENTATION}/driver/linux/drm_intel) endif() set(DRM_LIB_PATH drm) set(DRM_INTEL_LIB_PATH drm_intel) endif() endmacro() # macro to allow setting a list of extra compile # definitions. macro(bs_set_extra_target_properties targ propValues) string(REPLACE " " ";" PROP_VALUES "${ARGV}") if(TARGET "${targ}") foreach(prop ${PROP_VALUES}) if (${prop} STREQUAL ${targ}) continue() endif() set_property(TARGET "${targ}" APPEND PROPERTY COMPILE_DEFINITIONS ${prop} ) endforeach() endif(TARGET "${targ}") endmacro() # # Macro to help find libraries when they are build as external projects. # macro(bs_external_add_library names paths target_name shared) find_library(_LIB NAMES ${names} PATHS ${paths}) if(_LIB AND NOT TARGET ${target_name}) message("importing external library ${target_name}") if(${shared} MATCHES y) add_library(${target_name} SHARED IMPORTED GLOBAL) else() add_library(${target_name} STATIC IMPORTED GLOBAL) endif() set_target_properties(${target_name} PROPERTIES IMPORTED_LOCATION "${_LIB}") endif() endmacro() endif(NOT DEFINED _bs_include_utils) gmmlib-intel-gmmlib-22.5.2/third_party/000077500000000000000000000000001466655022700177755ustar00rootroot00000000000000gmmlib-intel-gmmlib-22.5.2/third_party/sse2neon/000077500000000000000000000000001466655022700215315ustar00rootroot00000000000000gmmlib-intel-gmmlib-22.5.2/third_party/sse2neon/LICENSE000066400000000000000000000020141466655022700225330ustar00rootroot00000000000000MIT License Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. gmmlib-intel-gmmlib-22.5.2/third_party/sse2neon/README.md000066400000000000000000000274161466655022700230220ustar00rootroot00000000000000# sse2neon ![Github Actions](https://github.com/DLTcollab/sse2neon/workflows/Github%20Actions/badge.svg?branch=master) A C/C++ header file that converts Intel SSE intrinsics to Arm/Aarch64 NEON intrinsics. ## Introduction `sse2neon` is a translator of Intel SSE (Streaming SIMD Extensions) intrinsics to [Arm NEON](https://developer.arm.com/architectures/instruction-sets/simd-isas/neon), shortening the time needed to get an Arm working program that then can be used to extract profiles and to identify hot paths in the code. The header file `sse2neon.h` contains several of the functions provided by Intel intrinsic headers such as ``, only implemented with NEON-based counterparts to produce the exact semantics of the intrinsics. ## Mapping and Coverage Header file | Extension | ---|---| `` | MMX | `` | SSE | `` | SSE2 | `` | SSE3 | `` | SSSE3 | `` | SSE4.1 | `` | SSE4.2 | `` | AES | `sse2neon` aims to support SSE, SSE2, SSE3, SSSE3, SSE4.1, SSE4.2 and AES extension. In order to deliver NEON-equivalent intrinsics for all SSE intrinsics used widely, please be aware that some SSE intrinsics exist a direct mapping with a concrete NEON-equivalent intrinsic. However, others lack of 1-to-1 mapping, that means the equivalents are implemented using several NEON intrinsics. For example, SSE intrinsic `_mm_loadu_si128` has a direct NEON mapping (`vld1q_s32`), but SSE intrinsic `_mm_maddubs_epi16` has to be implemented with 13+ NEON instructions. ## Usage - Put the file `sse2neon.h` in to your source code directory. - Locate the following SSE header files included in the code: ```C #include #include ``` {p,t,s,n,w}mmintrin.h should be replaceable, but the coverage of these extensions might be limited though. - Replace them with: ```C #include "sse2neon.h" ``` - Explicitly specify platform-specific options to gcc/clang compilers. * On ARMv8-A targets, you should specify the following compiler option: (Remove `crypto` and/or `crc` if your architecture does not support cryptographic and/or CRC32 extensions) ```shell -march=armv8-a+fp+simd+crypto+crc ``` * On ARMv7-A targets, you need to append the following compiler option: ```shell -mfpu=neon ``` ## Compile-time Configurations Considering the balance between correctness and performance, `sse2neon` recognizes the following compile-time configurations: * `SSE2NEON_PRECISE_MINMAX`: Enable precise implementation of `_mm_min_ps` and `_mm_max_ps`. If you need consistent results such as NaN special cases, enable it. * `SSE2NEON_PRECISE_DIV`: Enable precise implementation of `_mm_rcp_ps` and `_mm_div_ps` by additional Netwon-Raphson iteration for accuracy. * `SSE2NEON_PRECISE_SQRT`: Enable precise implementation of `_mm_sqrt_ps` and `_mm_rsqrt_ps` by additional Netwon-Raphson iteration for accuracy. The above are turned off by default, and you should define the corresponding macro(s) as `1` before including `sse2neon.h` if you need the precise implementations. ## Run Built-in Test Suite `sse2neon` provides a unified interface for developing test cases. These test cases are located in `tests` directory, and the input data is specified at runtime. Use the following commands to perform test cases: ```shell $ make check ``` You can specify GNU toolchain for cross compilation as well. [QEMU](https://www.qemu.org/) should be installed in advance. ```shell $ make CROSS_COMPILE=aarch64-linux-gnu- check # ARMv8-A ``` or ```shell $ make CROSS_COMPILE=arm-linux-gnueabihf- check # ARMv7-A ``` Check the details via [Test Suite for SSE2NEON](tests/README.md). ## Adoptions Here is a partial list of open source projects that have adopted `sse2neon` for Arm/Aarch64 support. * [aether-game-utils](https://github.com/johnhues/aether-game-utils) is a collection of cross platform utilities for quickly creating small game prototypes in C++. * [Apache Impala](https://impala.apache.org/) is a lightning-fast, distributed SQL queries for petabytes of data stored in Apache Hadoop clusters. * [Apache Kudu](https://kudu.apache.org/) completes Hadoop's storage layer to enable fast analytics on fast data. * [ART](https://github.com/dinosaure/art) is an implementation in OCaml of [Adaptive Radix Tree](https://db.in.tum.de/~leis/papers/ART.pdf) (ART). * [Async](https://github.com/romange/async) is a set of c++ primitives that allows efficient and rapid development in C++17 on GNU/Linux systems. * [Blender](https://www.blender.org/) is the free and open source 3D creation suite, supporting the entirety of the 3D pipeline. * [Boo](https://github.com/AxioDL/boo) is a cross-platform windowing and event manager similar to SDL or SFML, with additional 3D rendering functionality. * [CARTA](https://github.com/CARTAvis/carta-backend) is a new visualization tool designed for viewing radio astronomy images in CASA, FITS, MIRIAD, and HDF5 formats (using the IDIA custom schema for HDF5). * [Catcoon](https://github.com/i-evi/catcoon) is a [feedforward neural network](https://en.wikipedia.org/wiki/Feedforward_neural_network) implementation in C. * [dab-cmdline](https://github.com/JvanKatwijk/dab-cmdline) provides entries for the functionality to handle Digital audio broadcasting (DAB)/DAB+ through some simple calls. * [EDGE](https://github.com/3dfxdev/EDGE) is an advanced OpenGL source port spawned from the DOOM engine, with focus on easy development and expansion for modders and end-users. * [Embree](https://github.com/embree/embree) a collection of high-performance ray tracing kernels. Its target users are graphics application engineers who want to improve the performance of their photo-realistic rendering application by leveraging Embree's performance-optimized ray tracing kernels. * [emp-tool](https://github.com/emp-toolkit/emp-tool) aims to provide a benchmark for secure computation and allowing other researchers to experiment and extend. * [FoundationDB](https://www.foundationdb.org) is a distributed database designed to handle large volumes of structured data across clusters of commodity servers. * [iqtree_arm_neon](https://github.com/joshlvmh/iqtree_arm_neon) is the Arm NEON port of [IQ-TREE](http://www.iqtree.org/), fast and effective stochastic algorithm to infer phylogenetic trees by maximum likelihood. * [kram](https://github.com/alecazam/kram) is a wrapper to several popular encoders to and from PNG/[KTX](https://www.khronos.org/opengles/sdk/tools/KTX/file_format_spec/) files with [LDR/HDR and BC/ASTC/ETC2](https://developer.arm.com/solutions/graphics-and-gaming/developer-guides/learn-the-basics/adaptive-scalable-texture-compression/single-page). * [libscapi](https://github.com/cryptobiu/libscapi) stands for the "Secure Computation API", providing reliable, efficient, and highly flexible cryptographic infrastructure. * [libmatoya](https://github.com/matoya/libmatoya) is a cross-platform application development library, providing various features such as common cryptography tasks. * [Madronalib](https://github.com/madronalabs/madronalib) enables efficient audio DSP on SIMD processors with readable and brief C++ code. * [minimap2](https://github.com/lh3/minimap2) is a versatile sequence alignment program that aligns DNA or mRNA sequences against a large reference database. * [MMseqs2](https://github.com/soedinglab/MMseqs2) (Many-against-Many sequence searching) is a software suite to search and cluster huge protein and nucleotide sequence sets. * [MRIcroGL](https://github.com/rordenlab/MRIcroGL) is a cross-platform tool for viewing NIfTI, DICOM, MGH, MHD, NRRD, AFNI format medical images. * [N2](https://github.com/oddconcepts/n2o) is an approximate nearest neighborhoods algorithm library written in C++, providing a much faster search speed than other implementations when modeling large dataset. * [niimath](https://github.com/rordenlab/niimath) is a general image calculator with superior performance. * [OBS Studio](https://github.com/obsproject/obs-studio) is software designed for capturing, compositing, encoding, recording, and streaming video content, efficiently. * [OGRE](https://github.com/OGRECave/ogre) is a scene-oriented, flexible 3D engine written in C++ designed to make it easier and more intuitive for developers to produce games and demos utilising 3D hardware. * [OpenXRay](https://github.com/OpenXRay/xray-16) is an improved version of the X-Ray engine, used in world famous S.T.A.L.K.E.R. game series by GSC Game World. * [parallel-n64](https://github.com/libretro/parallel-n64) is an optimized/rewritten Nintendo 64 emulator made specifically for [Libretro](https://www.libretro.com/). * [PFFFT](https://github.com/marton78/pffft) does 1D Fast Fourier Transforms, of single precision real and complex vectors. * [PlutoSDR Firmware](https://github.com/seanstone/plutosdr-fw) is the customized firmware for the [PlutoSDR](https://wiki.analog.com/university/tools/pluto) that can be used to introduce fundamentals of Software Defined Radio (SDR) or Radio Frequency (RF) or Communications as advanced topics in electrical engineering in a self or instructor lead setting. * [Pygame](https://www.pygame.org) is cross-platform and designed to make it easy to write multimedia software, such as games, in Python. * [simd_utils](https://github.com/JishinMaster/simd_utils) is a header-only library implementing common mathematical functions using SIMD intrinsics. * [SMhasher](https://github.com/rurban/smhasher) provides comprehensive Hash function quality and speed tests. * [Spack](https://github.com/spack/spack) is a multi-platform package manager that builds and installs multiple versions and configurations of software. * [srsLTE](https://github.com/srsLTE/srsLTE) is an open source SDR LTE software suite. * [Surge](https://github.com/surge-synthesizer/surge) is an open source digital synthesizer. * [XMRig](https://github.com/xmrig/xmrig) is an open source CPU miner for [Monero](https://web.getmonero.org/) cryptocurrency. ## Related Projects * [SIMDe](https://github.com/simd-everywhere/simde): fast and portable implementations of SIMD intrinsics on hardware which doesn't natively support them, such as calling SSE functions on ARM. * [CatBoost's sse2neon](https://github.com/catboost/catboost/blob/master/library/cpp/sse/sse2neon.h) * [ARM\_NEON\_2\_x86\_SSE](https://github.com/intel/ARM_NEON_2_x86_SSE) * [AvxToNeon](https://github.com/kunpengcompute/AvxToNeon) * [POWER/PowerPC support for GCC](https://github.com/gcc-mirror/gcc/blob/master/gcc/config/rs6000) contains a series of headers simplifying porting x86_64 code that makes explicit use of Intel intrinsics to powerpc64le (pure little-endian mode that has been introduced with the [POWER8](https://en.wikipedia.org/wiki/POWER8)). - implementation: [xmmintrin.h](https://github.com/gcc-mirror/gcc/blob/master/gcc/config/rs6000/xmmintrin.h), [emmintrin.h](https://github.com/gcc-mirror/gcc/blob/master/gcc/config/rs6000/emmintrin.h), [pmmintrin.h](https://github.com/gcc-mirror/gcc/blob/master/gcc/config/rs6000/pmmintrin.h), [tmmintrin.h](https://github.com/gcc-mirror/gcc/blob/master/gcc/config/rs6000/tmmintrin.h), [smmintrin.h](https://github.com/gcc-mirror/gcc/blob/master/gcc/config/rs6000/smmintrin.h) ## Reference * [Intel Intrinsics Guide](https://software.intel.com/sites/landingpage/IntrinsicsGuide/) * [Arm Neon Intrinsics Reference](https://developer.arm.com/architectures/instruction-sets/simd-isas/neon/intrinsics) * [Neon Programmer's Guide for Armv8-A](https://developer.arm.com/architectures/instruction-sets/simd-isas/neon/neon-programmers-guide-for-armv8-a) * [NEON Programmer's Guide](https://static.docs.arm.com/den0018/a/DEN0018A_neon_programmers_guide_en.pdf) * [qemu/target/i386/ops_sse.h](https://github.com/qemu/qemu/blob/master/target/i386/ops_sse.h): Comprehensive SSE instruction emulation in C. Ideal for semantic checks. ## Licensing `sse2neon` is freely redistributable under the MIT License. gmmlib-intel-gmmlib-22.5.2/third_party/sse2neon/sse2neon.h000066400000000000000000011757511466655022700234570ustar00rootroot00000000000000#ifndef SSE2NEON_H #define SSE2NEON_H // This header file provides a simple API translation layer // between SSE intrinsics to their corresponding Arm/Aarch64 NEON versions // // This header file does not yet translate all of the SSE intrinsics. // // Contributors to this work are: // John W. Ratcliff // Brandon Rowlett // Ken Fast // Eric van Beurden // Alexander Potylitsin // Hasindu Gamaarachchi // Jim Huang // Mark Cheng // Malcolm James MacLeod // Devin Hussey (easyaspi314) // Sebastian Pop // Developer Ecosystem Engineering // Danila Kutenin // François Turban (JishinMaster) // Pei-Hsuan Hung // Yang-Hao Yuan // Syoyo Fujita // Brecht Van Lommel /* * sse2neon is freely redistributable under the MIT License. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ /* Tunable configurations */ /* Enable precise implementation of math operations * This would slow down the computation a bit, but gives consistent result with * x86 SSE2. (e.g. would solve a hole or NaN pixel in the rendering result) */ /* _mm_min_ps and _mm_max_ps */ #ifndef SSE2NEON_PRECISE_MINMAX #define SSE2NEON_PRECISE_MINMAX (0) #endif /* _mm_rcp_ps and _mm_div_ps */ #ifndef SSE2NEON_PRECISE_DIV #define SSE2NEON_PRECISE_DIV (0) #endif /* _mm_sqrt_ps and _mm_rsqrt_ps */ #ifndef SSE2NEON_PRECISE_SQRT #define SSE2NEON_PRECISE_SQRT (0) #endif #if defined(__GNUC__) || defined(__clang__) #pragma push_macro("FORCE_INLINE") #pragma push_macro("ALIGN_STRUCT") #define FORCE_INLINE static inline __attribute__((always_inline)) #define ALIGN_STRUCT(x) __attribute__((aligned(x))) #ifndef likely #define likely(x) __builtin_expect(!!(x), 1) #endif #ifndef unlikely #define unlikely(x) __builtin_expect(!!(x), 0) #endif #else #error "Macro name collisions may happen with unsupported compiler." #ifdef FORCE_INLINE #undef FORCE_INLINE #endif #define FORCE_INLINE static inline #ifndef ALIGN_STRUCT #define ALIGN_STRUCT(x) __declspec(align(x)) #endif #endif #ifndef likely #define likely(x) (x) #endif #ifndef unlikely #define unlikely(x) (x) #endif #include #include /* Architecture-specific build options */ /* FIXME: #pragma GCC push_options is only available on GCC */ #if defined(__GNUC__) #if defined(__arm__) && __ARM_ARCH == 7 /* According to ARM C Language Extensions Architecture specification, * __ARM_NEON is defined to a value indicating the Advanced SIMD (NEON) * architecture supported. */ #if !defined(__ARM_NEON) || !defined(__ARM_NEON__) #error "You must enable NEON instructions (e.g. -mfpu=neon) to use SSE2NEON." #endif #if !defined(__clang__) #pragma GCC push_options #pragma GCC target("fpu=neon") #endif #elif defined(__aarch64__) #if !defined(__clang__) #pragma GCC push_options #pragma GCC target("+simd") #endif #else #error "Unsupported target. Must be either ARMv7-A+NEON or ARMv8-A." #endif #endif #include /* Rounding functions require either Aarch64 instructions or libm failback */ #if !defined(__aarch64__) #include #endif /* "__has_builtin" can be used to query support for built-in functions * provided by gcc/clang and other compilers that support it. */ #ifndef __has_builtin /* GCC prior to 10 or non-clang compilers */ /* Compatibility with gcc <= 9 */ #if __GNUC__ <= 9 #define __has_builtin(x) HAS##x #define HAS__builtin_popcount 1 #define HAS__builtin_popcountll 1 #else #define __has_builtin(x) 0 #endif #endif /** * MACRO for shuffle parameter for _mm_shuffle_ps(). * Argument fp3 is a digit[0123] that represents the fp from argument "b" * of mm_shuffle_ps that will be placed in fp3 of result. fp2 is the same * for fp2 in result. fp1 is a digit[0123] that represents the fp from * argument "a" of mm_shuffle_ps that will be places in fp1 of result. * fp0 is the same for fp0 of result. */ #define _MM_SHUFFLE(fp3, fp2, fp1, fp0) \ (((fp3) << 6) | ((fp2) << 4) | ((fp1) << 2) | ((fp0))) /* Rounding mode macros. */ #define _MM_FROUND_TO_NEAREST_INT 0x00 #define _MM_FROUND_TO_NEG_INF 0x01 #define _MM_FROUND_TO_POS_INF 0x02 #define _MM_FROUND_TO_ZERO 0x03 #define _MM_FROUND_CUR_DIRECTION 0x04 #define _MM_FROUND_NO_EXC 0x08 #define _MM_ROUND_NEAREST 0x0000 #define _MM_ROUND_DOWN 0x2000 #define _MM_ROUND_UP 0x4000 #define _MM_ROUND_TOWARD_ZERO 0x6000 /* indicate immediate constant argument in a given range */ #define __constrange(a, b) const /* A few intrinsics accept traditional data types like ints or floats, but * most operate on data types that are specific to SSE. * If a vector type ends in d, it contains doubles, and if it does not have * a suffix, it contains floats. An integer vector type can contain any type * of integer, from chars to shorts to unsigned long longs. */ typedef int64x1_t __m64; typedef float32x4_t __m128; /* 128-bit vector containing 4 floats */ // On ARM 32-bit architecture, the float64x2_t is not supported. // The data type __m128d should be represented in a different way for related // intrinsic conversion. #if defined(__aarch64__) typedef float64x2_t __m128d; /* 128-bit vector containing 2 doubles */ #else typedef float32x4_t __m128d; #endif typedef int64x2_t __m128i; /* 128-bit vector containing integers */ /* type-safe casting between types */ #define vreinterpretq_m128_f16(x) vreinterpretq_f32_f16(x) #define vreinterpretq_m128_f32(x) (x) #define vreinterpretq_m128_f64(x) vreinterpretq_f32_f64(x) #define vreinterpretq_m128_u8(x) vreinterpretq_f32_u8(x) #define vreinterpretq_m128_u16(x) vreinterpretq_f32_u16(x) #define vreinterpretq_m128_u32(x) vreinterpretq_f32_u32(x) #define vreinterpretq_m128_u64(x) vreinterpretq_f32_u64(x) #define vreinterpretq_m128_s8(x) vreinterpretq_f32_s8(x) #define vreinterpretq_m128_s16(x) vreinterpretq_f32_s16(x) #define vreinterpretq_m128_s32(x) vreinterpretq_f32_s32(x) #define vreinterpretq_m128_s64(x) vreinterpretq_f32_s64(x) #define vreinterpretq_f16_m128(x) vreinterpretq_f16_f32(x) #define vreinterpretq_f32_m128(x) (x) #define vreinterpretq_f64_m128(x) vreinterpretq_f64_f32(x) #define vreinterpretq_u8_m128(x) vreinterpretq_u8_f32(x) #define vreinterpretq_u16_m128(x) vreinterpretq_u16_f32(x) #define vreinterpretq_u32_m128(x) vreinterpretq_u32_f32(x) #define vreinterpretq_u64_m128(x) vreinterpretq_u64_f32(x) #define vreinterpretq_s8_m128(x) vreinterpretq_s8_f32(x) #define vreinterpretq_s16_m128(x) vreinterpretq_s16_f32(x) #define vreinterpretq_s32_m128(x) vreinterpretq_s32_f32(x) #define vreinterpretq_s64_m128(x) vreinterpretq_s64_f32(x) #define vreinterpretq_m128i_s8(x) vreinterpretq_s64_s8(x) #define vreinterpretq_m128i_s16(x) vreinterpretq_s64_s16(x) #define vreinterpretq_m128i_s32(x) vreinterpretq_s64_s32(x) #define vreinterpretq_m128i_s64(x) (x) #define vreinterpretq_m128i_u8(x) vreinterpretq_s64_u8(x) #define vreinterpretq_m128i_u16(x) vreinterpretq_s64_u16(x) #define vreinterpretq_m128i_u32(x) vreinterpretq_s64_u32(x) #define vreinterpretq_m128i_u64(x) vreinterpretq_s64_u64(x) #define vreinterpretq_f32_m128i(x) vreinterpretq_f32_s64(x) #define vreinterpretq_f64_m128i(x) vreinterpretq_f64_s64(x) #define vreinterpretq_s8_m128i(x) vreinterpretq_s8_s64(x) #define vreinterpretq_s16_m128i(x) vreinterpretq_s16_s64(x) #define vreinterpretq_s32_m128i(x) vreinterpretq_s32_s64(x) #define vreinterpretq_s64_m128i(x) (x) #define vreinterpretq_u8_m128i(x) vreinterpretq_u8_s64(x) #define vreinterpretq_u16_m128i(x) vreinterpretq_u16_s64(x) #define vreinterpretq_u32_m128i(x) vreinterpretq_u32_s64(x) #define vreinterpretq_u64_m128i(x) vreinterpretq_u64_s64(x) #define vreinterpret_m64_s8(x) vreinterpret_s64_s8(x) #define vreinterpret_m64_s16(x) vreinterpret_s64_s16(x) #define vreinterpret_m64_s32(x) vreinterpret_s64_s32(x) #define vreinterpret_m64_s64(x) (x) #define vreinterpret_m64_u8(x) vreinterpret_s64_u8(x) #define vreinterpret_m64_u16(x) vreinterpret_s64_u16(x) #define vreinterpret_m64_u32(x) vreinterpret_s64_u32(x) #define vreinterpret_m64_u64(x) vreinterpret_s64_u64(x) #define vreinterpret_m64_f16(x) vreinterpret_s64_f16(x) #define vreinterpret_m64_f32(x) vreinterpret_s64_f32(x) #define vreinterpret_m64_f64(x) vreinterpret_s64_f64(x) #define vreinterpret_u8_m64(x) vreinterpret_u8_s64(x) #define vreinterpret_u16_m64(x) vreinterpret_u16_s64(x) #define vreinterpret_u32_m64(x) vreinterpret_u32_s64(x) #define vreinterpret_u64_m64(x) vreinterpret_u64_s64(x) #define vreinterpret_s8_m64(x) vreinterpret_s8_s64(x) #define vreinterpret_s16_m64(x) vreinterpret_s16_s64(x) #define vreinterpret_s32_m64(x) vreinterpret_s32_s64(x) #define vreinterpret_s64_m64(x) (x) #define vreinterpret_f32_m64(x) vreinterpret_f32_s64(x) #if defined(__aarch64__) #define vreinterpretq_m128d_s32(x) vreinterpretq_f64_s32(x) #define vreinterpretq_m128d_s64(x) vreinterpretq_f64_s64(x) #define vreinterpretq_m128d_u64(x) vreinterpretq_f64_u64(x) #define vreinterpretq_m128d_f32(x) vreinterpretq_f64_f32(x) #define vreinterpretq_m128d_f64(x) (x) #define vreinterpretq_s64_m128d(x) vreinterpretq_s64_f64(x) #define vreinterpretq_u32_m128d(x) vreinterpretq_u32_f64(x) #define vreinterpretq_u64_m128d(x) vreinterpretq_u64_f64(x) #define vreinterpretq_f64_m128d(x) (x) #define vreinterpretq_f32_m128d(x) vreinterpretq_f32_f64(x) #else #define vreinterpretq_m128d_s32(x) vreinterpretq_f32_s32(x) #define vreinterpretq_m128d_s64(x) vreinterpretq_f32_s64(x) #define vreinterpretq_m128d_u32(x) vreinterpretq_f32_u32(x) #define vreinterpretq_m128d_u64(x) vreinterpretq_f32_u64(x) #define vreinterpretq_m128d_f32(x) (x) #define vreinterpretq_s64_m128d(x) vreinterpretq_s64_f32(x) #define vreinterpretq_u32_m128d(x) vreinterpretq_u32_f32(x) #define vreinterpretq_u64_m128d(x) vreinterpretq_u64_f32(x) #define vreinterpretq_f32_m128d(x) (x) #endif // A struct is defined in this header file called 'SIMDVec' which can be used // by applications which attempt to access the contents of an _m128 struct // directly. It is important to note that accessing the __m128 struct directly // is bad coding practice by Microsoft: @see: // https://msdn.microsoft.com/en-us/library/ayeb3ayc.aspx // // However, some legacy source code may try to access the contents of an __m128 // struct directly so the developer can use the SIMDVec as an alias for it. Any // casting must be done manually by the developer, as you cannot cast or // otherwise alias the base NEON data type for intrinsic operations. // // union intended to allow direct access to an __m128 variable using the names // that the MSVC compiler provides. This union should really only be used when // trying to access the members of the vector as integer values. GCC/clang // allow native access to the float members through a simple array access // operator (in C since 4.6, in C++ since 4.8). // // Ideally direct accesses to SIMD vectors should not be used since it can cause // a performance hit. If it really is needed however, the original __m128 // variable can be aliased with a pointer to this union and used to access // individual components. The use of this union should be hidden behind a macro // that is used throughout the codebase to access the members instead of always // declaring this type of variable. typedef union ALIGN_STRUCT(16) SIMDVec { float m128_f32[4]; // as floats - DON'T USE. Added for convenience. int8_t m128_i8[16]; // as signed 8-bit integers. int16_t m128_i16[8]; // as signed 16-bit integers. int32_t m128_i32[4]; // as signed 32-bit integers. int64_t m128_i64[2]; // as signed 64-bit integers. uint8_t m128_u8[16]; // as unsigned 8-bit integers. uint16_t m128_u16[8]; // as unsigned 16-bit integers. uint32_t m128_u32[4]; // as unsigned 32-bit integers. uint64_t m128_u64[2]; // as unsigned 64-bit integers. } SIMDVec; // casting using SIMDVec #define vreinterpretq_nth_u64_m128i(x, n) (((SIMDVec *) &x)->m128_u64[n]) #define vreinterpretq_nth_u32_m128i(x, n) (((SIMDVec *) &x)->m128_u32[n]) #define vreinterpretq_nth_u8_m128i(x, n) (((SIMDVec *) &x)->m128_u8[n]) // Function declaration // SSE FORCE_INLINE unsigned int _MM_GET_ROUNDING_MODE(); FORCE_INLINE __m128 _mm_move_ss(__m128, __m128); // SSE2 FORCE_INLINE __m128i _mm_cvtps_epi32(__m128); FORCE_INLINE __m128d _mm_move_sd(__m128d, __m128d); FORCE_INLINE __m128i _mm_set_epi32(int, int, int, int); FORCE_INLINE __m128i _mm_set_epi64x(int64_t, int64_t); FORCE_INLINE __m128d _mm_set_pd(double, double); // SSE4.1 FORCE_INLINE __m128d _mm_ceil_pd(__m128d); FORCE_INLINE __m128 _mm_ceil_ps(__m128); FORCE_INLINE __m128d _mm_floor_pd(__m128d); FORCE_INLINE __m128 _mm_floor_ps(__m128); FORCE_INLINE __m128d _mm_round_pd(__m128d, int); FORCE_INLINE __m128 _mm_round_ps(__m128, int); // SSE4.2 FORCE_INLINE uint32_t _mm_crc32_u8(uint32_t, uint8_t); /* Backwards compatibility for compilers with lack of specific type support */ // Older gcc does not define vld1q_u8_x4 type #if defined(__GNUC__) && !defined(__clang__) && \ ((__GNUC__ <= 10 && defined(__arm__)) || \ (__GNUC__ == 10 && __GNUC_MINOR__ < 3 && defined(__aarch64__)) || \ (__GNUC__ <= 9 && defined(__aarch64__))) FORCE_INLINE uint8x16x4_t _sse2neon_vld1q_u8_x4(const uint8_t *p) { uint8x16x4_t ret; ret.val[0] = vld1q_u8(p + 0); ret.val[1] = vld1q_u8(p + 16); ret.val[2] = vld1q_u8(p + 32); ret.val[3] = vld1q_u8(p + 48); return ret; } #else // Wraps vld1q_u8_x4 FORCE_INLINE uint8x16x4_t _sse2neon_vld1q_u8_x4(const uint8_t *p) { return vld1q_u8_x4(p); } #endif /* Function Naming Conventions * The naming convention of SSE intrinsics is straightforward. A generic SSE * intrinsic function is given as follows: * _mm__ * * The parts of this format are given as follows: * 1. describes the operation performed by the intrinsic * 2. identifies the data type of the function's primary arguments * * This last part, , is a little complicated. It identifies the * content of the input values, and can be set to any of the following values: * + ps - vectors contain floats (ps stands for packed single-precision) * + pd - vectors cantain doubles (pd stands for packed double-precision) * + epi8/epi16/epi32/epi64 - vectors contain 8-bit/16-bit/32-bit/64-bit * signed integers * + epu8/epu16/epu32/epu64 - vectors contain 8-bit/16-bit/32-bit/64-bit * unsigned integers * + si128 - unspecified 128-bit vector or 256-bit vector * + m128/m128i/m128d - identifies input vector types when they are different * than the type of the returned vector * * For example, _mm_setzero_ps. The _mm implies that the function returns * a 128-bit vector. The _ps at the end implies that the argument vectors * contain floats. * * A complete example: Byte Shuffle - pshufb (_mm_shuffle_epi8) * // Set packed 16-bit integers. 128 bits, 8 short, per 16 bits * __m128i v_in = _mm_setr_epi16(1, 2, 3, 4, 5, 6, 7, 8); * // Set packed 8-bit integers * // 128 bits, 16 chars, per 8 bits * __m128i v_perm = _mm_setr_epi8(1, 0, 2, 3, 8, 9, 10, 11, * 4, 5, 12, 13, 6, 7, 14, 15); * // Shuffle packed 8-bit integers * __m128i v_out = _mm_shuffle_epi8(v_in, v_perm); // pshufb * * Data (Number, Binary, Byte Index): +------+------+-------------+------+------+-------------+ | 1 | 2 | 3 | 4 | Number +------+------+------+------+------+------+------+------+ | 0000 | 0001 | 0000 | 0010 | 0000 | 0011 | 0000 | 0100 | Binary +------+------+------+------+------+------+------+------+ | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | Index +------+------+------+------+------+------+------+------+ +------+------+------+------+------+------+------+------+ | 5 | 6 | 7 | 8 | Number +------+------+------+------+------+------+------+------+ | 0000 | 0101 | 0000 | 0110 | 0000 | 0111 | 0000 | 1000 | Binary +------+------+------+------+------+------+------+------+ | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | Index +------+------+------+------+------+------+------+------+ * Index (Byte Index): +------+------+------+------+------+------+------+------+ | 1 | 0 | 2 | 3 | 8 | 9 | 10 | 11 | +------+------+------+------+------+------+------+------+ +------+------+------+------+------+------+------+------+ | 4 | 5 | 12 | 13 | 6 | 7 | 14 | 15 | +------+------+------+------+------+------+------+------+ * Result: +------+------+------+------+------+------+------+------+ | 1 | 0 | 2 | 3 | 8 | 9 | 10 | 11 | Index +------+------+------+------+------+------+------+------+ | 0001 | 0000 | 0000 | 0010 | 0000 | 0101 | 0000 | 0110 | Binary +------+------+------+------+------+------+------+------+ | 256 | 2 | 5 | 6 | Number +------+------+------+------+------+------+------+------+ +------+------+------+------+------+------+------+------+ | 4 | 5 | 12 | 13 | 6 | 7 | 14 | 15 | Index +------+------+------+------+------+------+------+------+ | 0000 | 0011 | 0000 | 0111 | 0000 | 0100 | 0000 | 1000 | Binary +------+------+------+------+------+------+------+------+ | 3 | 7 | 4 | 8 | Number +------+------+------+------+------+------+-------------+ */ /* Constants for use with _mm_prefetch. */ enum _mm_hint { _MM_HINT_NTA = 0, /* load data to L1 and L2 cache, mark it as NTA */ _MM_HINT_T0 = 1, /* load data to L1 and L2 cache */ _MM_HINT_T1 = 2, /* load data to L2 cache only */ _MM_HINT_T2 = 3, /* load data to L2 cache only, mark it as NTA */ _MM_HINT_ENTA = 4, /* exclusive version of _MM_HINT_NTA */ _MM_HINT_ET0 = 5, /* exclusive version of _MM_HINT_T0 */ _MM_HINT_ET1 = 6, /* exclusive version of _MM_HINT_T1 */ _MM_HINT_ET2 = 7 /* exclusive version of _MM_HINT_T2 */ }; // The bit field mapping to the FPCR(floating-point control register) typedef struct { uint16_t res0; uint8_t res1 : 6; uint8_t bit22 : 1; uint8_t bit23 : 1; uint8_t res2; #if defined(__aarch64__) uint32_t res3; #endif } fpcr_bitfield; // Takes the upper 64 bits of a and places it in the low end of the result // Takes the lower 64 bits of b and places it into the high end of the result. FORCE_INLINE __m128 _mm_shuffle_ps_1032(__m128 a, __m128 b) { float32x2_t a32 = vget_high_f32(vreinterpretq_f32_m128(a)); float32x2_t b10 = vget_low_f32(vreinterpretq_f32_m128(b)); return vreinterpretq_m128_f32(vcombine_f32(a32, b10)); } // takes the lower two 32-bit values from a and swaps them and places in high // end of result takes the higher two 32 bit values from b and swaps them and // places in low end of result. FORCE_INLINE __m128 _mm_shuffle_ps_2301(__m128 a, __m128 b) { float32x2_t a01 = vrev64_f32(vget_low_f32(vreinterpretq_f32_m128(a))); float32x2_t b23 = vrev64_f32(vget_high_f32(vreinterpretq_f32_m128(b))); return vreinterpretq_m128_f32(vcombine_f32(a01, b23)); } FORCE_INLINE __m128 _mm_shuffle_ps_0321(__m128 a, __m128 b) { float32x2_t a21 = vget_high_f32( vextq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(a), 3)); float32x2_t b03 = vget_low_f32( vextq_f32(vreinterpretq_f32_m128(b), vreinterpretq_f32_m128(b), 3)); return vreinterpretq_m128_f32(vcombine_f32(a21, b03)); } FORCE_INLINE __m128 _mm_shuffle_ps_2103(__m128 a, __m128 b) { float32x2_t a03 = vget_low_f32( vextq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(a), 3)); float32x2_t b21 = vget_high_f32( vextq_f32(vreinterpretq_f32_m128(b), vreinterpretq_f32_m128(b), 3)); return vreinterpretq_m128_f32(vcombine_f32(a03, b21)); } FORCE_INLINE __m128 _mm_shuffle_ps_1010(__m128 a, __m128 b) { float32x2_t a10 = vget_low_f32(vreinterpretq_f32_m128(a)); float32x2_t b10 = vget_low_f32(vreinterpretq_f32_m128(b)); return vreinterpretq_m128_f32(vcombine_f32(a10, b10)); } FORCE_INLINE __m128 _mm_shuffle_ps_1001(__m128 a, __m128 b) { float32x2_t a01 = vrev64_f32(vget_low_f32(vreinterpretq_f32_m128(a))); float32x2_t b10 = vget_low_f32(vreinterpretq_f32_m128(b)); return vreinterpretq_m128_f32(vcombine_f32(a01, b10)); } FORCE_INLINE __m128 _mm_shuffle_ps_0101(__m128 a, __m128 b) { float32x2_t a01 = vrev64_f32(vget_low_f32(vreinterpretq_f32_m128(a))); float32x2_t b01 = vrev64_f32(vget_low_f32(vreinterpretq_f32_m128(b))); return vreinterpretq_m128_f32(vcombine_f32(a01, b01)); } // keeps the low 64 bits of b in the low and puts the high 64 bits of a in the // high FORCE_INLINE __m128 _mm_shuffle_ps_3210(__m128 a, __m128 b) { float32x2_t a10 = vget_low_f32(vreinterpretq_f32_m128(a)); float32x2_t b32 = vget_high_f32(vreinterpretq_f32_m128(b)); return vreinterpretq_m128_f32(vcombine_f32(a10, b32)); } FORCE_INLINE __m128 _mm_shuffle_ps_0011(__m128 a, __m128 b) { float32x2_t a11 = vdup_lane_f32(vget_low_f32(vreinterpretq_f32_m128(a)), 1); float32x2_t b00 = vdup_lane_f32(vget_low_f32(vreinterpretq_f32_m128(b)), 0); return vreinterpretq_m128_f32(vcombine_f32(a11, b00)); } FORCE_INLINE __m128 _mm_shuffle_ps_0022(__m128 a, __m128 b) { float32x2_t a22 = vdup_lane_f32(vget_high_f32(vreinterpretq_f32_m128(a)), 0); float32x2_t b00 = vdup_lane_f32(vget_low_f32(vreinterpretq_f32_m128(b)), 0); return vreinterpretq_m128_f32(vcombine_f32(a22, b00)); } FORCE_INLINE __m128 _mm_shuffle_ps_2200(__m128 a, __m128 b) { float32x2_t a00 = vdup_lane_f32(vget_low_f32(vreinterpretq_f32_m128(a)), 0); float32x2_t b22 = vdup_lane_f32(vget_high_f32(vreinterpretq_f32_m128(b)), 0); return vreinterpretq_m128_f32(vcombine_f32(a00, b22)); } FORCE_INLINE __m128 _mm_shuffle_ps_3202(__m128 a, __m128 b) { float32_t a0 = vgetq_lane_f32(vreinterpretq_f32_m128(a), 0); float32x2_t a22 = vdup_lane_f32(vget_high_f32(vreinterpretq_f32_m128(a)), 0); float32x2_t a02 = vset_lane_f32(a0, a22, 1); /* TODO: use vzip ?*/ float32x2_t b32 = vget_high_f32(vreinterpretq_f32_m128(b)); return vreinterpretq_m128_f32(vcombine_f32(a02, b32)); } FORCE_INLINE __m128 _mm_shuffle_ps_1133(__m128 a, __m128 b) { float32x2_t a33 = vdup_lane_f32(vget_high_f32(vreinterpretq_f32_m128(a)), 1); float32x2_t b11 = vdup_lane_f32(vget_low_f32(vreinterpretq_f32_m128(b)), 1); return vreinterpretq_m128_f32(vcombine_f32(a33, b11)); } FORCE_INLINE __m128 _mm_shuffle_ps_2010(__m128 a, __m128 b) { float32x2_t a10 = vget_low_f32(vreinterpretq_f32_m128(a)); float32_t b2 = vgetq_lane_f32(vreinterpretq_f32_m128(b), 2); float32x2_t b00 = vdup_lane_f32(vget_low_f32(vreinterpretq_f32_m128(b)), 0); float32x2_t b20 = vset_lane_f32(b2, b00, 1); return vreinterpretq_m128_f32(vcombine_f32(a10, b20)); } FORCE_INLINE __m128 _mm_shuffle_ps_2001(__m128 a, __m128 b) { float32x2_t a01 = vrev64_f32(vget_low_f32(vreinterpretq_f32_m128(a))); float32_t b2 = vgetq_lane_f32(b, 2); float32x2_t b00 = vdup_lane_f32(vget_low_f32(vreinterpretq_f32_m128(b)), 0); float32x2_t b20 = vset_lane_f32(b2, b00, 1); return vreinterpretq_m128_f32(vcombine_f32(a01, b20)); } FORCE_INLINE __m128 _mm_shuffle_ps_2032(__m128 a, __m128 b) { float32x2_t a32 = vget_high_f32(vreinterpretq_f32_m128(a)); float32_t b2 = vgetq_lane_f32(b, 2); float32x2_t b00 = vdup_lane_f32(vget_low_f32(vreinterpretq_f32_m128(b)), 0); float32x2_t b20 = vset_lane_f32(b2, b00, 1); return vreinterpretq_m128_f32(vcombine_f32(a32, b20)); } // Kahan summation for accurate summation of floating-point numbers. // http://blog.zachbjornson.com/2019/08/11/fast-float-summation.html FORCE_INLINE void _sse2neon_kadd_f32(float *sum, float *c, float y) { y -= *c; float t = *sum + y; *c = (t - *sum) - y; *sum = t; } #if defined(__ARM_FEATURE_CRYPTO) // Wraps vmull_p64 FORCE_INLINE uint64x2_t _sse2neon_vmull_p64(uint64x1_t _a, uint64x1_t _b) { poly64_t a = vget_lane_p64(vreinterpret_p64_u64(_a), 0); poly64_t b = vget_lane_p64(vreinterpret_p64_u64(_b), 0); return vreinterpretq_u64_p128(vmull_p64(a, b)); } #else // ARMv7 polyfill // ARMv7/some A64 lacks vmull_p64, but it has vmull_p8. // // vmull_p8 calculates 8 8-bit->16-bit polynomial multiplies, but we need a // 64-bit->128-bit polynomial multiply. // // It needs some work and is somewhat slow, but it is still faster than all // known scalar methods. // // Algorithm adapted to C from // https://www.workofard.com/2017/07/ghash-for-low-end-cores/, which is adapted // from "Fast Software Polynomial Multiplication on ARM Processors Using the // NEON Engine" by Danilo Camara, Conrado Gouvea, Julio Lopez and Ricardo Dahab // (https://hal.inria.fr/hal-01506572) static uint64x2_t _sse2neon_vmull_p64(uint64x1_t _a, uint64x1_t _b) { poly8x8_t a = vreinterpret_p8_u64(_a); poly8x8_t b = vreinterpret_p8_u64(_b); // Masks uint8x16_t k48_32 = vcombine_u8(vcreate_u8(0x0000ffffffffffff), vcreate_u8(0x00000000ffffffff)); uint8x16_t k16_00 = vcombine_u8(vcreate_u8(0x000000000000ffff), vcreate_u8(0x0000000000000000)); // Do the multiplies, rotating with vext to get all combinations uint8x16_t d = vreinterpretq_u8_p16(vmull_p8(a, b)); // D = A0 * B0 uint8x16_t e = vreinterpretq_u8_p16(vmull_p8(a, vext_p8(b, b, 1))); // E = A0 * B1 uint8x16_t f = vreinterpretq_u8_p16(vmull_p8(vext_p8(a, a, 1), b)); // F = A1 * B0 uint8x16_t g = vreinterpretq_u8_p16(vmull_p8(a, vext_p8(b, b, 2))); // G = A0 * B2 uint8x16_t h = vreinterpretq_u8_p16(vmull_p8(vext_p8(a, a, 2), b)); // H = A2 * B0 uint8x16_t i = vreinterpretq_u8_p16(vmull_p8(a, vext_p8(b, b, 3))); // I = A0 * B3 uint8x16_t j = vreinterpretq_u8_p16(vmull_p8(vext_p8(a, a, 3), b)); // J = A3 * B0 uint8x16_t k = vreinterpretq_u8_p16(vmull_p8(a, vext_p8(b, b, 4))); // L = A0 * B4 // Add cross products uint8x16_t l = veorq_u8(e, f); // L = E + F uint8x16_t m = veorq_u8(g, h); // M = G + H uint8x16_t n = veorq_u8(i, j); // N = I + J // Interleave. Using vzip1 and vzip2 prevents Clang from emitting TBL // instructions. #if defined(__aarch64__) uint8x16_t lm_p0 = vreinterpretq_u8_u64( vzip1q_u64(vreinterpretq_u64_u8(l), vreinterpretq_u64_u8(m))); uint8x16_t lm_p1 = vreinterpretq_u8_u64( vzip2q_u64(vreinterpretq_u64_u8(l), vreinterpretq_u64_u8(m))); uint8x16_t nk_p0 = vreinterpretq_u8_u64( vzip1q_u64(vreinterpretq_u64_u8(n), vreinterpretq_u64_u8(k))); uint8x16_t nk_p1 = vreinterpretq_u8_u64( vzip2q_u64(vreinterpretq_u64_u8(n), vreinterpretq_u64_u8(k))); #else uint8x16_t lm_p0 = vcombine_u8(vget_low_u8(l), vget_low_u8(m)); uint8x16_t lm_p1 = vcombine_u8(vget_high_u8(l), vget_high_u8(m)); uint8x16_t nk_p0 = vcombine_u8(vget_low_u8(n), vget_low_u8(k)); uint8x16_t nk_p1 = vcombine_u8(vget_high_u8(n), vget_high_u8(k)); #endif // t0 = (L) (P0 + P1) << 8 // t1 = (M) (P2 + P3) << 16 uint8x16_t t0t1_tmp = veorq_u8(lm_p0, lm_p1); uint8x16_t t0t1_h = vandq_u8(lm_p1, k48_32); uint8x16_t t0t1_l = veorq_u8(t0t1_tmp, t0t1_h); // t2 = (N) (P4 + P5) << 24 // t3 = (K) (P6 + P7) << 32 uint8x16_t t2t3_tmp = veorq_u8(nk_p0, nk_p1); uint8x16_t t2t3_h = vandq_u8(nk_p1, k16_00); uint8x16_t t2t3_l = veorq_u8(t2t3_tmp, t2t3_h); // De-interleave #if defined(__aarch64__) uint8x16_t t0 = vreinterpretq_u8_u64( vuzp1q_u64(vreinterpretq_u64_u8(t0t1_l), vreinterpretq_u64_u8(t0t1_h))); uint8x16_t t1 = vreinterpretq_u8_u64( vuzp2q_u64(vreinterpretq_u64_u8(t0t1_l), vreinterpretq_u64_u8(t0t1_h))); uint8x16_t t2 = vreinterpretq_u8_u64( vuzp1q_u64(vreinterpretq_u64_u8(t2t3_l), vreinterpretq_u64_u8(t2t3_h))); uint8x16_t t3 = vreinterpretq_u8_u64( vuzp2q_u64(vreinterpretq_u64_u8(t2t3_l), vreinterpretq_u64_u8(t2t3_h))); #else uint8x16_t t1 = vcombine_u8(vget_high_u8(t0t1_l), vget_high_u8(t0t1_h)); uint8x16_t t0 = vcombine_u8(vget_low_u8(t0t1_l), vget_low_u8(t0t1_h)); uint8x16_t t3 = vcombine_u8(vget_high_u8(t2t3_l), vget_high_u8(t2t3_h)); uint8x16_t t2 = vcombine_u8(vget_low_u8(t2t3_l), vget_low_u8(t2t3_h)); #endif // Shift the cross products uint8x16_t t0_shift = vextq_u8(t0, t0, 15); // t0 << 8 uint8x16_t t1_shift = vextq_u8(t1, t1, 14); // t1 << 16 uint8x16_t t2_shift = vextq_u8(t2, t2, 13); // t2 << 24 uint8x16_t t3_shift = vextq_u8(t3, t3, 12); // t3 << 32 // Accumulate the products uint8x16_t cross1 = veorq_u8(t0_shift, t1_shift); uint8x16_t cross2 = veorq_u8(t2_shift, t3_shift); uint8x16_t mix = veorq_u8(d, cross1); uint8x16_t r = veorq_u8(mix, cross2); return vreinterpretq_u64_u8(r); } #endif // ARMv7 polyfill // C equivalent: // __m128i _mm_shuffle_epi32_default(__m128i a, // __constrange(0, 255) int imm) { // __m128i ret; // ret[0] = a[imm & 0x3]; ret[1] = a[(imm >> 2) & 0x3]; // ret[2] = a[(imm >> 4) & 0x03]; ret[3] = a[(imm >> 6) & 0x03]; // return ret; // } #define _mm_shuffle_epi32_default(a, imm) \ __extension__({ \ int32x4_t ret; \ ret = vmovq_n_s32( \ vgetq_lane_s32(vreinterpretq_s32_m128i(a), (imm) & (0x3))); \ ret = vsetq_lane_s32( \ vgetq_lane_s32(vreinterpretq_s32_m128i(a), ((imm) >> 2) & 0x3), \ ret, 1); \ ret = vsetq_lane_s32( \ vgetq_lane_s32(vreinterpretq_s32_m128i(a), ((imm) >> 4) & 0x3), \ ret, 2); \ ret = vsetq_lane_s32( \ vgetq_lane_s32(vreinterpretq_s32_m128i(a), ((imm) >> 6) & 0x3), \ ret, 3); \ vreinterpretq_m128i_s32(ret); \ }) // Takes the upper 64 bits of a and places it in the low end of the result // Takes the lower 64 bits of a and places it into the high end of the result. FORCE_INLINE __m128i _mm_shuffle_epi_1032(__m128i a) { int32x2_t a32 = vget_high_s32(vreinterpretq_s32_m128i(a)); int32x2_t a10 = vget_low_s32(vreinterpretq_s32_m128i(a)); return vreinterpretq_m128i_s32(vcombine_s32(a32, a10)); } // takes the lower two 32-bit values from a and swaps them and places in low end // of result takes the higher two 32 bit values from a and swaps them and places // in high end of result. FORCE_INLINE __m128i _mm_shuffle_epi_2301(__m128i a) { int32x2_t a01 = vrev64_s32(vget_low_s32(vreinterpretq_s32_m128i(a))); int32x2_t a23 = vrev64_s32(vget_high_s32(vreinterpretq_s32_m128i(a))); return vreinterpretq_m128i_s32(vcombine_s32(a01, a23)); } // rotates the least significant 32 bits into the most significant 32 bits, and // shifts the rest down FORCE_INLINE __m128i _mm_shuffle_epi_0321(__m128i a) { return vreinterpretq_m128i_s32( vextq_s32(vreinterpretq_s32_m128i(a), vreinterpretq_s32_m128i(a), 1)); } // rotates the most significant 32 bits into the least significant 32 bits, and // shifts the rest up FORCE_INLINE __m128i _mm_shuffle_epi_2103(__m128i a) { return vreinterpretq_m128i_s32( vextq_s32(vreinterpretq_s32_m128i(a), vreinterpretq_s32_m128i(a), 3)); } // gets the lower 64 bits of a, and places it in the upper 64 bits // gets the lower 64 bits of a and places it in the lower 64 bits FORCE_INLINE __m128i _mm_shuffle_epi_1010(__m128i a) { int32x2_t a10 = vget_low_s32(vreinterpretq_s32_m128i(a)); return vreinterpretq_m128i_s32(vcombine_s32(a10, a10)); } // gets the lower 64 bits of a, swaps the 0 and 1 elements, and places it in the // lower 64 bits gets the lower 64 bits of a, and places it in the upper 64 bits FORCE_INLINE __m128i _mm_shuffle_epi_1001(__m128i a) { int32x2_t a01 = vrev64_s32(vget_low_s32(vreinterpretq_s32_m128i(a))); int32x2_t a10 = vget_low_s32(vreinterpretq_s32_m128i(a)); return vreinterpretq_m128i_s32(vcombine_s32(a01, a10)); } // gets the lower 64 bits of a, swaps the 0 and 1 elements and places it in the // upper 64 bits gets the lower 64 bits of a, swaps the 0 and 1 elements, and // places it in the lower 64 bits FORCE_INLINE __m128i _mm_shuffle_epi_0101(__m128i a) { int32x2_t a01 = vrev64_s32(vget_low_s32(vreinterpretq_s32_m128i(a))); return vreinterpretq_m128i_s32(vcombine_s32(a01, a01)); } FORCE_INLINE __m128i _mm_shuffle_epi_2211(__m128i a) { int32x2_t a11 = vdup_lane_s32(vget_low_s32(vreinterpretq_s32_m128i(a)), 1); int32x2_t a22 = vdup_lane_s32(vget_high_s32(vreinterpretq_s32_m128i(a)), 0); return vreinterpretq_m128i_s32(vcombine_s32(a11, a22)); } FORCE_INLINE __m128i _mm_shuffle_epi_0122(__m128i a) { int32x2_t a22 = vdup_lane_s32(vget_high_s32(vreinterpretq_s32_m128i(a)), 0); int32x2_t a01 = vrev64_s32(vget_low_s32(vreinterpretq_s32_m128i(a))); return vreinterpretq_m128i_s32(vcombine_s32(a22, a01)); } FORCE_INLINE __m128i _mm_shuffle_epi_3332(__m128i a) { int32x2_t a32 = vget_high_s32(vreinterpretq_s32_m128i(a)); int32x2_t a33 = vdup_lane_s32(vget_high_s32(vreinterpretq_s32_m128i(a)), 1); return vreinterpretq_m128i_s32(vcombine_s32(a32, a33)); } // FORCE_INLINE __m128i _mm_shuffle_epi32_splat(__m128i a, __constrange(0,255) // int imm) #if defined(__aarch64__) #define _mm_shuffle_epi32_splat(a, imm) \ __extension__({ \ vreinterpretq_m128i_s32( \ vdupq_laneq_s32(vreinterpretq_s32_m128i(a), (imm))); \ }) #else #define _mm_shuffle_epi32_splat(a, imm) \ __extension__({ \ vreinterpretq_m128i_s32( \ vdupq_n_s32(vgetq_lane_s32(vreinterpretq_s32_m128i(a), (imm)))); \ }) #endif // NEON does not support a general purpose permute intrinsic // Selects four specific single-precision, floating-point values from a and b, // based on the mask i. // // C equivalent: // __m128 _mm_shuffle_ps_default(__m128 a, __m128 b, // __constrange(0, 255) int imm) { // __m128 ret; // ret[0] = a[imm & 0x3]; ret[1] = a[(imm >> 2) & 0x3]; // ret[2] = b[(imm >> 4) & 0x03]; ret[3] = b[(imm >> 6) & 0x03]; // return ret; // } // // https://msdn.microsoft.com/en-us/library/vstudio/5f0858x0(v=vs.100).aspx #define _mm_shuffle_ps_default(a, b, imm) \ __extension__({ \ float32x4_t ret; \ ret = vmovq_n_f32( \ vgetq_lane_f32(vreinterpretq_f32_m128(a), (imm) & (0x3))); \ ret = vsetq_lane_f32( \ vgetq_lane_f32(vreinterpretq_f32_m128(a), ((imm) >> 2) & 0x3), \ ret, 1); \ ret = vsetq_lane_f32( \ vgetq_lane_f32(vreinterpretq_f32_m128(b), ((imm) >> 4) & 0x3), \ ret, 2); \ ret = vsetq_lane_f32( \ vgetq_lane_f32(vreinterpretq_f32_m128(b), ((imm) >> 6) & 0x3), \ ret, 3); \ vreinterpretq_m128_f32(ret); \ }) // Shuffles the lower 4 signed or unsigned 16-bit integers in a as specified // by imm. // https://docs.microsoft.com/en-us/previous-versions/visualstudio/visual-studio-2010/y41dkk37(v=vs.100) // FORCE_INLINE __m128i _mm_shufflelo_epi16_function(__m128i a, // __constrange(0,255) int // imm) #define _mm_shufflelo_epi16_function(a, imm) \ __extension__({ \ int16x8_t ret = vreinterpretq_s16_m128i(a); \ int16x4_t lowBits = vget_low_s16(ret); \ ret = vsetq_lane_s16(vget_lane_s16(lowBits, (imm) & (0x3)), ret, 0); \ ret = vsetq_lane_s16(vget_lane_s16(lowBits, ((imm) >> 2) & 0x3), ret, \ 1); \ ret = vsetq_lane_s16(vget_lane_s16(lowBits, ((imm) >> 4) & 0x3), ret, \ 2); \ ret = vsetq_lane_s16(vget_lane_s16(lowBits, ((imm) >> 6) & 0x3), ret, \ 3); \ vreinterpretq_m128i_s16(ret); \ }) // Shuffles the upper 4 signed or unsigned 16-bit integers in a as specified // by imm. // https://msdn.microsoft.com/en-us/library/13ywktbs(v=vs.100).aspx // FORCE_INLINE __m128i _mm_shufflehi_epi16_function(__m128i a, // __constrange(0,255) int // imm) #define _mm_shufflehi_epi16_function(a, imm) \ __extension__({ \ int16x8_t ret = vreinterpretq_s16_m128i(a); \ int16x4_t highBits = vget_high_s16(ret); \ ret = vsetq_lane_s16(vget_lane_s16(highBits, (imm) & (0x3)), ret, 4); \ ret = vsetq_lane_s16(vget_lane_s16(highBits, ((imm) >> 2) & 0x3), ret, \ 5); \ ret = vsetq_lane_s16(vget_lane_s16(highBits, ((imm) >> 4) & 0x3), ret, \ 6); \ ret = vsetq_lane_s16(vget_lane_s16(highBits, ((imm) >> 6) & 0x3), ret, \ 7); \ vreinterpretq_m128i_s16(ret); \ }) /* SSE */ // Adds the four single-precision, floating-point values of a and b. // // r0 := a0 + b0 // r1 := a1 + b1 // r2 := a2 + b2 // r3 := a3 + b3 // // https://msdn.microsoft.com/en-us/library/vstudio/c9848chc(v=vs.100).aspx FORCE_INLINE __m128 _mm_add_ps(__m128 a, __m128 b) { return vreinterpretq_m128_f32( vaddq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(b))); } // adds the scalar single-precision floating point values of a and b. // https://msdn.microsoft.com/en-us/library/be94x2y6(v=vs.100).aspx FORCE_INLINE __m128 _mm_add_ss(__m128 a, __m128 b) { float32_t b0 = vgetq_lane_f32(vreinterpretq_f32_m128(b), 0); float32x4_t value = vsetq_lane_f32(b0, vdupq_n_f32(0), 0); // the upper values in the result must be the remnants of . return vreinterpretq_m128_f32(vaddq_f32(a, value)); } // Computes the bitwise AND of the four single-precision, floating-point values // of a and b. // // r0 := a0 & b0 // r1 := a1 & b1 // r2 := a2 & b2 // r3 := a3 & b3 // // https://msdn.microsoft.com/en-us/library/vstudio/73ck1xc5(v=vs.100).aspx FORCE_INLINE __m128 _mm_and_ps(__m128 a, __m128 b) { return vreinterpretq_m128_s32( vandq_s32(vreinterpretq_s32_m128(a), vreinterpretq_s32_m128(b))); } // Computes the bitwise AND-NOT of the four single-precision, floating-point // values of a and b. // // r0 := ~a0 & b0 // r1 := ~a1 & b1 // r2 := ~a2 & b2 // r3 := ~a3 & b3 // // https://msdn.microsoft.com/en-us/library/vstudio/68h7wd02(v=vs.100).aspx FORCE_INLINE __m128 _mm_andnot_ps(__m128 a, __m128 b) { return vreinterpretq_m128_s32( vbicq_s32(vreinterpretq_s32_m128(b), vreinterpretq_s32_m128(a))); // *NOTE* argument swap } // Average packed unsigned 16-bit integers in a and b, and store the results in // dst. // // FOR j := 0 to 3 // i := j*16 // dst[i+15:i] := (a[i+15:i] + b[i+15:i] + 1) >> 1 // ENDFOR // // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_avg_pu16 FORCE_INLINE __m64 _mm_avg_pu16(__m64 a, __m64 b) { return vreinterpret_m64_u16( vrhadd_u16(vreinterpret_u16_m64(a), vreinterpret_u16_m64(b))); } // Average packed unsigned 8-bit integers in a and b, and store the results in // dst. // // FOR j := 0 to 7 // i := j*8 // dst[i+7:i] := (a[i+7:i] + b[i+7:i] + 1) >> 1 // ENDFOR // // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_avg_pu8 FORCE_INLINE __m64 _mm_avg_pu8(__m64 a, __m64 b) { return vreinterpret_m64_u8( vrhadd_u8(vreinterpret_u8_m64(a), vreinterpret_u8_m64(b))); } // Compares for equality. // https://msdn.microsoft.com/en-us/library/vstudio/36aectz5(v=vs.100).aspx FORCE_INLINE __m128 _mm_cmpeq_ps(__m128 a, __m128 b) { return vreinterpretq_m128_u32( vceqq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(b))); } // Compares for equality. // https://docs.microsoft.com/en-us/previous-versions/visualstudio/visual-studio-2010/k423z28e(v=vs.100) FORCE_INLINE __m128 _mm_cmpeq_ss(__m128 a, __m128 b) { return _mm_move_ss(a, _mm_cmpeq_ps(a, b)); } // Compares for greater than or equal. // https://msdn.microsoft.com/en-us/library/vstudio/fs813y2t(v=vs.100).aspx FORCE_INLINE __m128 _mm_cmpge_ps(__m128 a, __m128 b) { return vreinterpretq_m128_u32( vcgeq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(b))); } // Compares for greater than or equal. // https://docs.microsoft.com/en-us/previous-versions/visualstudio/visual-studio-2010/kesh3ddc(v=vs.100) FORCE_INLINE __m128 _mm_cmpge_ss(__m128 a, __m128 b) { return _mm_move_ss(a, _mm_cmpge_ps(a, b)); } // Compares for greater than. // // r0 := (a0 > b0) ? 0xffffffff : 0x0 // r1 := (a1 > b1) ? 0xffffffff : 0x0 // r2 := (a2 > b2) ? 0xffffffff : 0x0 // r3 := (a3 > b3) ? 0xffffffff : 0x0 // // https://msdn.microsoft.com/en-us/library/vstudio/11dy102s(v=vs.100).aspx FORCE_INLINE __m128 _mm_cmpgt_ps(__m128 a, __m128 b) { return vreinterpretq_m128_u32( vcgtq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(b))); } // Compares for greater than. // https://docs.microsoft.com/en-us/previous-versions/visualstudio/visual-studio-2010/1xyyyy9e(v=vs.100) FORCE_INLINE __m128 _mm_cmpgt_ss(__m128 a, __m128 b) { return _mm_move_ss(a, _mm_cmpgt_ps(a, b)); } // Compares for less than or equal. // // r0 := (a0 <= b0) ? 0xffffffff : 0x0 // r1 := (a1 <= b1) ? 0xffffffff : 0x0 // r2 := (a2 <= b2) ? 0xffffffff : 0x0 // r3 := (a3 <= b3) ? 0xffffffff : 0x0 // // https://msdn.microsoft.com/en-us/library/vstudio/1s75w83z(v=vs.100).aspx FORCE_INLINE __m128 _mm_cmple_ps(__m128 a, __m128 b) { return vreinterpretq_m128_u32( vcleq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(b))); } // Compares for less than or equal. // https://docs.microsoft.com/en-us/previous-versions/visualstudio/visual-studio-2010/a7x0hbhw(v=vs.100) FORCE_INLINE __m128 _mm_cmple_ss(__m128 a, __m128 b) { return _mm_move_ss(a, _mm_cmple_ps(a, b)); } // Compares for less than // https://msdn.microsoft.com/en-us/library/vstudio/f330yhc8(v=vs.100).aspx FORCE_INLINE __m128 _mm_cmplt_ps(__m128 a, __m128 b) { return vreinterpretq_m128_u32( vcltq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(b))); } // Compares for less than // https://docs.microsoft.com/en-us/previous-versions/visualstudio/visual-studio-2010/fy94wye7(v=vs.100) FORCE_INLINE __m128 _mm_cmplt_ss(__m128 a, __m128 b) { return _mm_move_ss(a, _mm_cmplt_ps(a, b)); } // Compares for inequality. // https://msdn.microsoft.com/en-us/library/sf44thbx(v=vs.100).aspx FORCE_INLINE __m128 _mm_cmpneq_ps(__m128 a, __m128 b) { return vreinterpretq_m128_u32(vmvnq_u32( vceqq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(b)))); } // Compares for inequality. // https://docs.microsoft.com/en-us/previous-versions/visualstudio/visual-studio-2010/ekya8fh4(v=vs.100) FORCE_INLINE __m128 _mm_cmpneq_ss(__m128 a, __m128 b) { return _mm_move_ss(a, _mm_cmpneq_ps(a, b)); } // Compares for not greater than or equal. // https://docs.microsoft.com/en-us/previous-versions/visualstudio/visual-studio-2010/wsexys62(v=vs.100) FORCE_INLINE __m128 _mm_cmpnge_ps(__m128 a, __m128 b) { return _mm_cmplt_ps(a, b); } // Compares for not greater than or equal. // https://docs.microsoft.com/en-us/previous-versions/visualstudio/visual-studio-2010/fk2y80s8(v=vs.100) FORCE_INLINE __m128 _mm_cmpnge_ss(__m128 a, __m128 b) { return _mm_cmplt_ss(a, b); } // Compares for not greater than. // https://docs.microsoft.com/en-us/previous-versions/visualstudio/visual-studio-2010/d0xh7w0s(v=vs.100) FORCE_INLINE __m128 _mm_cmpngt_ps(__m128 a, __m128 b) { return _mm_cmple_ps(a, b); } // Compares for not greater than. // https://docs.microsoft.com/en-us/previous-versions/visualstudio/visual-studio-2010/z7x9ydwh(v=vs.100) FORCE_INLINE __m128 _mm_cmpngt_ss(__m128 a, __m128 b) { return _mm_cmple_ss(a, b); } // Compares for not less than or equal. // https://docs.microsoft.com/en-us/previous-versions/visualstudio/visual-studio-2010/6a330kxw(v=vs.100) FORCE_INLINE __m128 _mm_cmpnle_ps(__m128 a, __m128 b) { return _mm_cmpgt_ps(a, b); } // Compares for not less than or equal. // https://docs.microsoft.com/en-us/previous-versions/visualstudio/visual-studio-2010/z7x9ydwh(v=vs.100) FORCE_INLINE __m128 _mm_cmpnle_ss(__m128 a, __m128 b) { return _mm_cmpgt_ss(a, b); } // Compares for not less than. // https://docs.microsoft.com/en-us/previous-versions/visualstudio/visual-studio-2010/4686bbdw(v=vs.100) FORCE_INLINE __m128 _mm_cmpnlt_ps(__m128 a, __m128 b) { return _mm_cmpge_ps(a, b); } // Compares for not less than. // https://docs.microsoft.com/en-us/previous-versions/visualstudio/visual-studio-2010/56b9z2wf(v=vs.100) FORCE_INLINE __m128 _mm_cmpnlt_ss(__m128 a, __m128 b) { return _mm_cmpge_ss(a, b); } // Compares the four 32-bit floats in a and b to check if any values are NaN. // Ordered compare between each value returns true for "orderable" and false for // "not orderable" (NaN). // https://msdn.microsoft.com/en-us/library/vstudio/0h9w00fx(v=vs.100).aspx see // also: // http://stackoverflow.com/questions/8627331/what-does-ordered-unordered-comparison-mean // http://stackoverflow.com/questions/29349621/neon-isnanval-intrinsics FORCE_INLINE __m128 _mm_cmpord_ps(__m128 a, __m128 b) { // Note: NEON does not have ordered compare builtin // Need to compare a eq a and b eq b to check for NaN // Do AND of results to get final uint32x4_t ceqaa = vceqq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(a)); uint32x4_t ceqbb = vceqq_f32(vreinterpretq_f32_m128(b), vreinterpretq_f32_m128(b)); return vreinterpretq_m128_u32(vandq_u32(ceqaa, ceqbb)); } // Compares for ordered. // https://docs.microsoft.com/en-us/previous-versions/visualstudio/visual-studio-2010/343t62da(v=vs.100) FORCE_INLINE __m128 _mm_cmpord_ss(__m128 a, __m128 b) { return _mm_move_ss(a, _mm_cmpord_ps(a, b)); } // Compares for unordered. // https://docs.microsoft.com/en-us/previous-versions/visualstudio/visual-studio-2010/khy6fk1t(v=vs.100) FORCE_INLINE __m128 _mm_cmpunord_ps(__m128 a, __m128 b) { uint32x4_t f32a = vceqq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(a)); uint32x4_t f32b = vceqq_f32(vreinterpretq_f32_m128(b), vreinterpretq_f32_m128(b)); return vreinterpretq_m128_u32(vmvnq_u32(vandq_u32(f32a, f32b))); } // Compares for unordered. // https://docs.microsoft.com/en-us/previous-versions/visualstudio/visual-studio-2010/2as2387b(v=vs.100) FORCE_INLINE __m128 _mm_cmpunord_ss(__m128 a, __m128 b) { return _mm_move_ss(a, _mm_cmpunord_ps(a, b)); } // Compares the lower single-precision floating point scalar values of a and b // using an equality operation. : // https://msdn.microsoft.com/en-us/library/93yx2h2b(v=vs.100).aspx FORCE_INLINE int _mm_comieq_ss(__m128 a, __m128 b) { // return vgetq_lane_u32(vceqq_f32(vreinterpretq_f32_m128(a), // vreinterpretq_f32_m128(b)), 0); uint32x4_t a_not_nan = vceqq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(a)); uint32x4_t b_not_nan = vceqq_f32(vreinterpretq_f32_m128(b), vreinterpretq_f32_m128(b)); uint32x4_t a_and_b_not_nan = vandq_u32(a_not_nan, b_not_nan); uint32x4_t a_eq_b = vceqq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(b)); return vgetq_lane_u32(vandq_u32(a_and_b_not_nan, a_eq_b), 0) & 0x1; } // Compares the lower single-precision floating point scalar values of a and b // using a greater than or equal operation. : // https://msdn.microsoft.com/en-us/library/8t80des6(v=vs.100).aspx FORCE_INLINE int _mm_comige_ss(__m128 a, __m128 b) { // return vgetq_lane_u32(vcgeq_f32(vreinterpretq_f32_m128(a), // vreinterpretq_f32_m128(b)), 0); uint32x4_t a_not_nan = vceqq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(a)); uint32x4_t b_not_nan = vceqq_f32(vreinterpretq_f32_m128(b), vreinterpretq_f32_m128(b)); uint32x4_t a_and_b_not_nan = vandq_u32(a_not_nan, b_not_nan); uint32x4_t a_ge_b = vcgeq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(b)); return vgetq_lane_u32(vandq_u32(a_and_b_not_nan, a_ge_b), 0) & 0x1; } // Compares the lower single-precision floating point scalar values of a and b // using a greater than operation. : // https://msdn.microsoft.com/en-us/library/b0738e0t(v=vs.100).aspx FORCE_INLINE int _mm_comigt_ss(__m128 a, __m128 b) { // return vgetq_lane_u32(vcgtq_f32(vreinterpretq_f32_m128(a), // vreinterpretq_f32_m128(b)), 0); uint32x4_t a_not_nan = vceqq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(a)); uint32x4_t b_not_nan = vceqq_f32(vreinterpretq_f32_m128(b), vreinterpretq_f32_m128(b)); uint32x4_t a_and_b_not_nan = vandq_u32(a_not_nan, b_not_nan); uint32x4_t a_gt_b = vcgtq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(b)); return vgetq_lane_u32(vandq_u32(a_and_b_not_nan, a_gt_b), 0) & 0x1; } // Compares the lower single-precision floating point scalar values of a and b // using a less than or equal operation. : // https://msdn.microsoft.com/en-us/library/1w4t7c57(v=vs.90).aspx FORCE_INLINE int _mm_comile_ss(__m128 a, __m128 b) { // return vgetq_lane_u32(vcleq_f32(vreinterpretq_f32_m128(a), // vreinterpretq_f32_m128(b)), 0); uint32x4_t a_not_nan = vceqq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(a)); uint32x4_t b_not_nan = vceqq_f32(vreinterpretq_f32_m128(b), vreinterpretq_f32_m128(b)); uint32x4_t a_and_b_not_nan = vandq_u32(a_not_nan, b_not_nan); uint32x4_t a_le_b = vcleq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(b)); return vgetq_lane_u32(vandq_u32(a_and_b_not_nan, a_le_b), 0) & 0x1; } // Compares the lower single-precision floating point scalar values of a and b // using a less than operation. : // https://msdn.microsoft.com/en-us/library/2kwe606b(v=vs.90).aspx Important // note!! The documentation on MSDN is incorrect! If either of the values is a // NAN the docs say you will get a one, but in fact, it will return a zero!! FORCE_INLINE int _mm_comilt_ss(__m128 a, __m128 b) { uint32x4_t a_not_nan = vceqq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(a)); uint32x4_t b_not_nan = vceqq_f32(vreinterpretq_f32_m128(b), vreinterpretq_f32_m128(b)); uint32x4_t a_and_b_not_nan = vandq_u32(a_not_nan, b_not_nan); uint32x4_t a_lt_b = vcltq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(b)); return vgetq_lane_u32(vandq_u32(a_and_b_not_nan, a_lt_b), 0) & 0x1; } // Compares the lower single-precision floating point scalar values of a and b // using an inequality operation. : // https://msdn.microsoft.com/en-us/library/bafh5e0a(v=vs.90).aspx FORCE_INLINE int _mm_comineq_ss(__m128 a, __m128 b) { // return !vgetq_lane_u32(vceqq_f32(vreinterpretq_f32_m128(a), // vreinterpretq_f32_m128(b)), 0); uint32x4_t a_not_nan = vceqq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(a)); uint32x4_t b_not_nan = vceqq_f32(vreinterpretq_f32_m128(b), vreinterpretq_f32_m128(b)); uint32x4_t a_or_b_nan = vmvnq_u32(vandq_u32(a_not_nan, b_not_nan)); uint32x4_t a_neq_b = vmvnq_u32( vceqq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(b))); return vgetq_lane_u32(vorrq_u32(a_or_b_nan, a_neq_b), 0) & 0x1; } // Convert packed signed 32-bit integers in b to packed single-precision // (32-bit) floating-point elements, store the results in the lower 2 elements // of dst, and copy the upper 2 packed elements from a to the upper elements of // dst. // // dst[31:0] := Convert_Int32_To_FP32(b[31:0]) // dst[63:32] := Convert_Int32_To_FP32(b[63:32]) // dst[95:64] := a[95:64] // dst[127:96] := a[127:96] // // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvt_pi2ps FORCE_INLINE __m128 _mm_cvt_pi2ps(__m128 a, __m64 b) { return vreinterpretq_m128_f32( vcombine_f32(vcvt_f32_s32(vreinterpret_s32_m64(b)), vget_high_f32(vreinterpretq_f32_m128(a)))); } // Convert packed single-precision (32-bit) floating-point elements in a to // packed 32-bit integers, and store the results in dst. // // FOR j := 0 to 1 // i := 32*j // dst[i+31:i] := Convert_FP32_To_Int32(a[i+31:i]) // ENDFOR // // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvt_ps2pi FORCE_INLINE __m64 _mm_cvt_ps2pi(__m128 a) { #if defined(__aarch64__) return vreinterpret_m64_s32( vget_low_s32(vcvtnq_s32_f32(vrndiq_f32(vreinterpretq_f32_m128(a))))); #else return vreinterpret_m64_s32(vcvt_s32_f32(vget_low_f32( vreinterpretq_f32_m128(_mm_round_ps(a, _MM_FROUND_CUR_DIRECTION))))); #endif } // Convert the signed 32-bit integer b to a single-precision (32-bit) // floating-point element, store the result in the lower element of dst, and // copy the upper 3 packed elements from a to the upper elements of dst. // // dst[31:0] := Convert_Int32_To_FP32(b[31:0]) // dst[127:32] := a[127:32] // // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvt_si2ss FORCE_INLINE __m128 _mm_cvt_si2ss(__m128 a, int b) { return vreinterpretq_m128_f32( vsetq_lane_f32((float) b, vreinterpretq_f32_m128(a), 0)); } // Convert the lower single-precision (32-bit) floating-point element in a to a // 32-bit integer, and store the result in dst. // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvt_ss2si FORCE_INLINE int _mm_cvt_ss2si(__m128 a) { #if defined(__aarch64__) return vgetq_lane_s32(vcvtnq_s32_f32(vrndiq_f32(vreinterpretq_f32_m128(a))), 0); #else float32_t data = vgetq_lane_f32( vreinterpretq_f32_m128(_mm_round_ps(a, _MM_FROUND_CUR_DIRECTION)), 0); return (int32_t) data; #endif } // Convert packed 16-bit integers in a to packed single-precision (32-bit) // floating-point elements, and store the results in dst. // // FOR j := 0 to 3 // i := j*16 // m := j*32 // dst[m+31:m] := Convert_Int16_To_FP32(a[i+15:i]) // ENDFOR // // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtpi16_ps FORCE_INLINE __m128 _mm_cvtpi16_ps(__m64 a) { return vreinterpretq_m128_f32( vcvtq_f32_s32(vmovl_s16(vreinterpret_s16_m64(a)))); } // Convert packed 32-bit integers in b to packed single-precision (32-bit) // floating-point elements, store the results in the lower 2 elements of dst, // and copy the upper 2 packed elements from a to the upper elements of dst. // // dst[31:0] := Convert_Int32_To_FP32(b[31:0]) // dst[63:32] := Convert_Int32_To_FP32(b[63:32]) // dst[95:64] := a[95:64] // dst[127:96] := a[127:96] // // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtpi32_ps FORCE_INLINE __m128 _mm_cvtpi32_ps(__m128 a, __m64 b) { return vreinterpretq_m128_f32( vcombine_f32(vcvt_f32_s32(vreinterpret_s32_m64(b)), vget_high_f32(vreinterpretq_f32_m128(a)))); } // Convert packed signed 32-bit integers in a to packed single-precision // (32-bit) floating-point elements, store the results in the lower 2 elements // of dst, then covert the packed signed 32-bit integers in b to // single-precision (32-bit) floating-point element, and store the results in // the upper 2 elements of dst. // // dst[31:0] := Convert_Int32_To_FP32(a[31:0]) // dst[63:32] := Convert_Int32_To_FP32(a[63:32]) // dst[95:64] := Convert_Int32_To_FP32(b[31:0]) // dst[127:96] := Convert_Int32_To_FP32(b[63:32]) // // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtpi32x2_ps FORCE_INLINE __m128 _mm_cvtpi32x2_ps(__m64 a, __m64 b) { return vreinterpretq_m128_f32(vcvtq_f32_s32( vcombine_s32(vreinterpret_s32_m64(a), vreinterpret_s32_m64(b)))); } // Convert the lower packed 8-bit integers in a to packed single-precision // (32-bit) floating-point elements, and store the results in dst. // // FOR j := 0 to 3 // i := j*8 // m := j*32 // dst[m+31:m] := Convert_Int8_To_FP32(a[i+7:i]) // ENDFOR // // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtpi8_ps FORCE_INLINE __m128 _mm_cvtpi8_ps(__m64 a) { return vreinterpretq_m128_f32(vcvtq_f32_s32( vmovl_s16(vget_low_s16(vmovl_s8(vreinterpret_s8_m64(a)))))); } // Convert packed single-precision (32-bit) floating-point elements in a to // packed 16-bit integers, and store the results in dst. Note: this intrinsic // will generate 0x7FFF, rather than 0x8000, for input values between 0x7FFF and // 0x7FFFFFFF. // // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtps_pi16 FORCE_INLINE __m64 _mm_cvtps_pi16(__m128 a) { return vreinterpret_m64_s16( vmovn_s32(vreinterpretq_s32_m128i(_mm_cvtps_epi32(a)))); } // Convert packed single-precision (32-bit) floating-point elements in a to // packed 32-bit integers, and store the results in dst. // // FOR j := 0 to 1 // i := 32*j // dst[i+31:i] := Convert_FP32_To_Int32(a[i+31:i]) // ENDFOR // // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtps_pi32 #define _mm_cvtps_pi32(a) _mm_cvt_ps2pi(a) // Convert packed unsigned 16-bit integers in a to packed single-precision // (32-bit) floating-point elements, and store the results in dst. // // FOR j := 0 to 3 // i := j*16 // m := j*32 // dst[m+31:m] := Convert_UInt16_To_FP32(a[i+15:i]) // ENDFOR // // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtpu16_ps FORCE_INLINE __m128 _mm_cvtpu16_ps(__m64 a) { return vreinterpretq_m128_f32( vcvtq_f32_u32(vmovl_u16(vreinterpret_u16_m64(a)))); } // Convert the lower packed unsigned 8-bit integers in a to packed // single-precision (32-bit) floating-point elements, and store the results in // dst. // // FOR j := 0 to 3 // i := j*8 // m := j*32 // dst[m+31:m] := Convert_UInt8_To_FP32(a[i+7:i]) // ENDFOR // // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtpu8_ps FORCE_INLINE __m128 _mm_cvtpu8_ps(__m64 a) { return vreinterpretq_m128_f32(vcvtq_f32_u32( vmovl_u16(vget_low_u16(vmovl_u8(vreinterpret_u8_m64(a)))))); } // Convert the signed 32-bit integer b to a single-precision (32-bit) // floating-point element, store the result in the lower element of dst, and // copy the upper 3 packed elements from a to the upper elements of dst. // // dst[31:0] := Convert_Int32_To_FP32(b[31:0]) // dst[127:32] := a[127:32] // // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtsi32_ss #define _mm_cvtsi32_ss(a, b) _mm_cvt_si2ss(a, b) // Convert the signed 64-bit integer b to a single-precision (32-bit) // floating-point element, store the result in the lower element of dst, and // copy the upper 3 packed elements from a to the upper elements of dst. // // dst[31:0] := Convert_Int64_To_FP32(b[63:0]) // dst[127:32] := a[127:32] // // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtsi64_ss FORCE_INLINE __m128 _mm_cvtsi64_ss(__m128 a, int64_t b) { return vreinterpretq_m128_f32( vsetq_lane_f32((float) b, vreinterpretq_f32_m128(a), 0)); } // Copy the lower single-precision (32-bit) floating-point element of a to dst. // // dst[31:0] := a[31:0] // // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtss_f32 FORCE_INLINE float _mm_cvtss_f32(__m128 a) { return vgetq_lane_f32(vreinterpretq_f32_m128(a), 0); } // Convert the lower single-precision (32-bit) floating-point element in a to a // 32-bit integer, and store the result in dst. // // dst[31:0] := Convert_FP32_To_Int32(a[31:0]) // // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtss_si32 #define _mm_cvtss_si32(a) _mm_cvt_ss2si(a) // Convert the lower single-precision (32-bit) floating-point element in a to a // 64-bit integer, and store the result in dst. // // dst[63:0] := Convert_FP32_To_Int64(a[31:0]) // // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtss_si64 FORCE_INLINE int64_t _mm_cvtss_si64(__m128 a) { #if defined(__aarch64__) return (int64_t) vgetq_lane_f32(vrndiq_f32(vreinterpretq_f32_m128(a)), 0); #else float32_t data = vgetq_lane_f32( vreinterpretq_f32_m128(_mm_round_ps(a, _MM_FROUND_CUR_DIRECTION)), 0); return (int64_t) data; #endif } // Convert packed single-precision (32-bit) floating-point elements in a to // packed 32-bit integers with truncation, and store the results in dst. // // FOR j := 0 to 1 // i := 32*j // dst[i+31:i] := Convert_FP32_To_Int32_Truncate(a[i+31:i]) // ENDFOR // // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtt_ps2pi FORCE_INLINE __m64 _mm_cvtt_ps2pi(__m128 a) { return vreinterpret_m64_s32( vget_low_s32(vcvtq_s32_f32(vreinterpretq_f32_m128(a)))); } // Convert the lower single-precision (32-bit) floating-point element in a to a // 32-bit integer with truncation, and store the result in dst. // // dst[31:0] := Convert_FP32_To_Int32_Truncate(a[31:0]) // // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtt_ss2si FORCE_INLINE int _mm_cvtt_ss2si(__m128 a) { return vgetq_lane_s32(vcvtq_s32_f32(vreinterpretq_f32_m128(a)), 0); } // Convert packed single-precision (32-bit) floating-point elements in a to // packed 32-bit integers with truncation, and store the results in dst. // // FOR j := 0 to 1 // i := 32*j // dst[i+31:i] := Convert_FP32_To_Int32_Truncate(a[i+31:i]) // ENDFOR // // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvttps_pi32 #define _mm_cvttps_pi32(a) _mm_cvtt_ps2pi(a) // Convert the lower single-precision (32-bit) floating-point element in a to a // 32-bit integer with truncation, and store the result in dst. // // dst[31:0] := Convert_FP32_To_Int32_Truncate(a[31:0]) // // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvttss_si32 #define _mm_cvttss_si32(a) _mm_cvtt_ss2si(a) // Convert the lower single-precision (32-bit) floating-point element in a to a // 64-bit integer with truncation, and store the result in dst. // // dst[63:0] := Convert_FP32_To_Int64_Truncate(a[31:0]) // // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvttss_si64 FORCE_INLINE int64_t _mm_cvttss_si64(__m128 a) { return (int64_t) vgetq_lane_f32(vreinterpretq_f32_m128(a), 0); } // Divides the four single-precision, floating-point values of a and b. // // r0 := a0 / b0 // r1 := a1 / b1 // r2 := a2 / b2 // r3 := a3 / b3 // // https://msdn.microsoft.com/en-us/library/edaw8147(v=vs.100).aspx FORCE_INLINE __m128 _mm_div_ps(__m128 a, __m128 b) { #if defined(__aarch64__) && !SSE2NEON_PRECISE_DIV return vreinterpretq_m128_f32( vdivq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(b))); #else float32x4_t recip = vrecpeq_f32(vreinterpretq_f32_m128(b)); recip = vmulq_f32(recip, vrecpsq_f32(recip, vreinterpretq_f32_m128(b))); #if SSE2NEON_PRECISE_DIV // Additional Netwon-Raphson iteration for accuracy recip = vmulq_f32(recip, vrecpsq_f32(recip, vreinterpretq_f32_m128(b))); #endif return vreinterpretq_m128_f32(vmulq_f32(vreinterpretq_f32_m128(a), recip)); #endif } // Divides the scalar single-precision floating point value of a by b. // https://msdn.microsoft.com/en-us/library/4y73xa49(v=vs.100).aspx FORCE_INLINE __m128 _mm_div_ss(__m128 a, __m128 b) { float32_t value = vgetq_lane_f32(vreinterpretq_f32_m128(_mm_div_ps(a, b)), 0); return vreinterpretq_m128_f32( vsetq_lane_f32(value, vreinterpretq_f32_m128(a), 0)); } // Extract a 16-bit integer from a, selected with imm8, and store the result in // the lower element of dst. // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_extract_pi16 #define _mm_extract_pi16(a, imm) \ (int32_t) vget_lane_u16(vreinterpret_u16_m64(a), (imm)) // Free aligned memory that was allocated with _mm_malloc. // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_free FORCE_INLINE void _mm_free(void *addr) { free(addr); } // Macro: Get the rounding mode bits from the MXCSR control and status register. // The rounding mode may contain any of the following flags: _MM_ROUND_NEAREST, // _MM_ROUND_DOWN, _MM_ROUND_UP, _MM_ROUND_TOWARD_ZERO // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_MM_GET_ROUNDING_MODE FORCE_INLINE unsigned int _MM_GET_ROUNDING_MODE() { union { fpcr_bitfield field; #if defined(__aarch64__) uint64_t value; #else uint32_t value; #endif } r; #if defined(__aarch64__) asm volatile("mrs %0, FPCR" : "=r"(r.value)); /* read */ #else asm volatile("vmrs %0, FPSCR" : "=r"(r.value)); /* read */ #endif if (r.field.bit22) { return r.field.bit23 ? _MM_ROUND_TOWARD_ZERO : _MM_ROUND_UP; } else { return r.field.bit23 ? _MM_ROUND_DOWN : _MM_ROUND_NEAREST; } } // Copy a to dst, and insert the 16-bit integer i into dst at the location // specified by imm8. // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_insert_pi16 #define _mm_insert_pi16(a, b, imm) \ __extension__({ \ vreinterpret_m64_s16( \ vset_lane_s16((b), vreinterpret_s16_m64(a), (imm))); \ }) // Loads four single-precision, floating-point values. // https://msdn.microsoft.com/en-us/library/vstudio/zzd50xxt(v=vs.100).aspx FORCE_INLINE __m128 _mm_load_ps(const float *p) { return vreinterpretq_m128_f32(vld1q_f32(p)); } // Load a single-precision (32-bit) floating-point element from memory into all // elements of dst. // // dst[31:0] := MEM[mem_addr+31:mem_addr] // dst[63:32] := MEM[mem_addr+31:mem_addr] // dst[95:64] := MEM[mem_addr+31:mem_addr] // dst[127:96] := MEM[mem_addr+31:mem_addr] // // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_load_ps1 #define _mm_load_ps1 _mm_load1_ps // Loads an single - precision, floating - point value into the low word and // clears the upper three words. // https://msdn.microsoft.com/en-us/library/548bb9h4%28v=vs.90%29.aspx FORCE_INLINE __m128 _mm_load_ss(const float *p) { return vreinterpretq_m128_f32(vsetq_lane_f32(*p, vdupq_n_f32(0), 0)); } // Loads a single single-precision, floating-point value, copying it into all // four words // https://msdn.microsoft.com/en-us/library/vstudio/5cdkf716(v=vs.100).aspx FORCE_INLINE __m128 _mm_load1_ps(const float *p) { return vreinterpretq_m128_f32(vld1q_dup_f32(p)); } // Sets the upper two single-precision, floating-point values with 64 // bits of data loaded from the address p; the lower two values are passed // through from a. // // r0 := a0 // r1 := a1 // r2 := *p0 // r3 := *p1 // // https://msdn.microsoft.com/en-us/library/w92wta0x(v%3dvs.100).aspx FORCE_INLINE __m128 _mm_loadh_pi(__m128 a, __m64 const *p) { return vreinterpretq_m128_f32( vcombine_f32(vget_low_f32(a), vld1_f32((const float32_t *) p))); } // Sets the lower two single-precision, floating-point values with 64 // bits of data loaded from the address p; the upper two values are passed // through from a. // // Return Value // r0 := *p0 // r1 := *p1 // r2 := a2 // r3 := a3 // // https://msdn.microsoft.com/en-us/library/s57cyak2(v=vs.100).aspx FORCE_INLINE __m128 _mm_loadl_pi(__m128 a, __m64 const *p) { return vreinterpretq_m128_f32( vcombine_f32(vld1_f32((const float32_t *) p), vget_high_f32(a))); } // Load 4 single-precision (32-bit) floating-point elements from memory into dst // in reverse order. mem_addr must be aligned on a 16-byte boundary or a // general-protection exception may be generated. // // dst[31:0] := MEM[mem_addr+127:mem_addr+96] // dst[63:32] := MEM[mem_addr+95:mem_addr+64] // dst[95:64] := MEM[mem_addr+63:mem_addr+32] // dst[127:96] := MEM[mem_addr+31:mem_addr] // // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_loadr_ps FORCE_INLINE __m128 _mm_loadr_ps(const float *p) { float32x4_t v = vrev64q_f32(vld1q_f32(p)); return vreinterpretq_m128_f32(vextq_f32(v, v, 2)); } // Loads four single-precision, floating-point values. // https://msdn.microsoft.com/en-us/library/x1b16s7z%28v=vs.90%29.aspx FORCE_INLINE __m128 _mm_loadu_ps(const float *p) { // for neon, alignment doesn't matter, so _mm_load_ps and _mm_loadu_ps are // equivalent for neon return vreinterpretq_m128_f32(vld1q_f32(p)); } // Load unaligned 16-bit integer from memory into the first element of dst. // // dst[15:0] := MEM[mem_addr+15:mem_addr] // dst[MAX:16] := 0 // // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_loadu_si16 FORCE_INLINE __m128i _mm_loadu_si16(const void *p) { return vreinterpretq_m128i_s16( vsetq_lane_s16(*(const int16_t *) p, vdupq_n_s16(0), 0)); } // Load unaligned 64-bit integer from memory into the first element of dst. // // dst[63:0] := MEM[mem_addr+63:mem_addr] // dst[MAX:64] := 0 // // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_loadu_si64 FORCE_INLINE __m128i _mm_loadu_si64(const void *p) { return vreinterpretq_m128i_s64( vcombine_s64(vld1_s64((const int64_t *) p), vdup_n_s64(0))); } // Allocate aligned blocks of memory. // https://software.intel.com/en-us/ // cpp-compiler-developer-guide-and-reference-allocating-and-freeing-aligned-memory-blocks FORCE_INLINE void *_mm_malloc(size_t size, size_t align) { void *ptr; if (align == 1) return malloc(size); if (align == 2 || (sizeof(void *) == 8 && align == 4)) align = sizeof(void *); if (!posix_memalign(&ptr, align, size)) return ptr; return NULL; } // Conditionally store 8-bit integer elements from a into memory using mask // (elements are not stored when the highest bit is not set in the corresponding // element) and a non-temporal memory hint. // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskmove_si64 FORCE_INLINE void _mm_maskmove_si64(__m64 a, __m64 mask, char *mem_addr) { int8x8_t shr_mask = vshr_n_s8(vreinterpret_s8_m64(mask), 7); __m128 b = _mm_load_ps((const float *) mem_addr); int8x8_t masked = vbsl_s8(vreinterpret_u8_s8(shr_mask), vreinterpret_s8_m64(a), vreinterpret_s8_u64(vget_low_u64(vreinterpretq_u64_m128(b)))); vst1_s8((int8_t *) mem_addr, masked); } // Conditionally store 8-bit integer elements from a into memory using mask // (elements are not stored when the highest bit is not set in the corresponding // element) and a non-temporal memory hint. // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_m_maskmovq #define _m_maskmovq(a, mask, mem_addr) _mm_maskmove_si64(a, mask, mem_addr) // Compare packed signed 16-bit integers in a and b, and store packed maximum // values in dst. // // FOR j := 0 to 3 // i := j*16 // dst[i+15:i] := MAX(a[i+15:i], b[i+15:i]) // ENDFOR // // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_max_pi16 FORCE_INLINE __m64 _mm_max_pi16(__m64 a, __m64 b) { return vreinterpret_m64_s16( vmax_s16(vreinterpret_s16_m64(a), vreinterpret_s16_m64(b))); } // Computes the maximums of the four single-precision, floating-point values of // a and b. // https://msdn.microsoft.com/en-us/library/vstudio/ff5d607a(v=vs.100).aspx FORCE_INLINE __m128 _mm_max_ps(__m128 a, __m128 b) { #if SSE2NEON_PRECISE_MINMAX float32x4_t _a = vreinterpretq_f32_m128(a); float32x4_t _b = vreinterpretq_f32_m128(b); return vbslq_f32(vcltq_f32(_b, _a), _a, _b); #else return vreinterpretq_m128_f32( vmaxq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(b))); #endif } // Compare packed unsigned 8-bit integers in a and b, and store packed maximum // values in dst. // // FOR j := 0 to 7 // i := j*8 // dst[i+7:i] := MAX(a[i+7:i], b[i+7:i]) // ENDFOR // // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_max_pu8 FORCE_INLINE __m64 _mm_max_pu8(__m64 a, __m64 b) { return vreinterpret_m64_u8( vmax_u8(vreinterpret_u8_m64(a), vreinterpret_u8_m64(b))); } // Computes the maximum of the two lower scalar single-precision floating point // values of a and b. // https://msdn.microsoft.com/en-us/library/s6db5esz(v=vs.100).aspx FORCE_INLINE __m128 _mm_max_ss(__m128 a, __m128 b) { float32_t value = vgetq_lane_f32(_mm_max_ps(a, b), 0); return vreinterpretq_m128_f32( vsetq_lane_f32(value, vreinterpretq_f32_m128(a), 0)); } // Compare packed signed 16-bit integers in a and b, and store packed minimum // values in dst. // // FOR j := 0 to 3 // i := j*16 // dst[i+15:i] := MIN(a[i+15:i], b[i+15:i]) // ENDFOR // // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_min_pi16 FORCE_INLINE __m64 _mm_min_pi16(__m64 a, __m64 b) { return vreinterpret_m64_s16( vmin_s16(vreinterpret_s16_m64(a), vreinterpret_s16_m64(b))); } // Computes the minima of the four single-precision, floating-point values of a // and b. // https://msdn.microsoft.com/en-us/library/vstudio/wh13kadz(v=vs.100).aspx FORCE_INLINE __m128 _mm_min_ps(__m128 a, __m128 b) { #if SSE2NEON_PRECISE_MINMAX float32x4_t _a = vreinterpretq_f32_m128(a); float32x4_t _b = vreinterpretq_f32_m128(b); return vbslq_f32(vcltq_f32(_a, _b), _a, _b); #else return vreinterpretq_m128_f32( vminq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(b))); #endif } // Compare packed unsigned 8-bit integers in a and b, and store packed minimum // values in dst. // // FOR j := 0 to 7 // i := j*8 // dst[i+7:i] := MIN(a[i+7:i], b[i+7:i]) // ENDFOR // // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_min_pu8 FORCE_INLINE __m64 _mm_min_pu8(__m64 a, __m64 b) { return vreinterpret_m64_u8( vmin_u8(vreinterpret_u8_m64(a), vreinterpret_u8_m64(b))); } // Computes the minimum of the two lower scalar single-precision floating point // values of a and b. // https://msdn.microsoft.com/en-us/library/0a9y7xaa(v=vs.100).aspx FORCE_INLINE __m128 _mm_min_ss(__m128 a, __m128 b) { float32_t value = vgetq_lane_f32(_mm_min_ps(a, b), 0); return vreinterpretq_m128_f32( vsetq_lane_f32(value, vreinterpretq_f32_m128(a), 0)); } // Sets the low word to the single-precision, floating-point value of b // https://docs.microsoft.com/en-us/previous-versions/visualstudio/visual-studio-2010/35hdzazd(v=vs.100) FORCE_INLINE __m128 _mm_move_ss(__m128 a, __m128 b) { return vreinterpretq_m128_f32( vsetq_lane_f32(vgetq_lane_f32(vreinterpretq_f32_m128(b), 0), vreinterpretq_f32_m128(a), 0)); } // Moves the upper two values of B into the lower two values of A. // // r3 := a3 // r2 := a2 // r1 := b3 // r0 := b2 FORCE_INLINE __m128 _mm_movehl_ps(__m128 __A, __m128 __B) { float32x2_t a32 = vget_high_f32(vreinterpretq_f32_m128(__A)); float32x2_t b32 = vget_high_f32(vreinterpretq_f32_m128(__B)); return vreinterpretq_m128_f32(vcombine_f32(b32, a32)); } // Moves the lower two values of B into the upper two values of A. // // r3 := b1 // r2 := b0 // r1 := a1 // r0 := a0 FORCE_INLINE __m128 _mm_movelh_ps(__m128 __A, __m128 __B) { float32x2_t a10 = vget_low_f32(vreinterpretq_f32_m128(__A)); float32x2_t b10 = vget_low_f32(vreinterpretq_f32_m128(__B)); return vreinterpretq_m128_f32(vcombine_f32(a10, b10)); } // Create mask from the most significant bit of each 8-bit element in a, and // store the result in dst. // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_movemask_pi8 FORCE_INLINE int _mm_movemask_pi8(__m64 a) { uint8x8_t input = vreinterpret_u8_m64(a); #if defined(__aarch64__) static const int8x8_t shift = {0, 1, 2, 3, 4, 5, 6, 7}; uint8x8_t tmp = vshr_n_u8(input, 7); return vaddv_u8(vshl_u8(tmp, shift)); #else // Refer the implementation of `_mm_movemask_epi8` uint16x4_t high_bits = vreinterpret_u16_u8(vshr_n_u8(input, 7)); uint32x2_t paired16 = vreinterpret_u32_u16(vsra_n_u16(high_bits, high_bits, 7)); uint8x8_t paired32 = vreinterpret_u8_u32(vsra_n_u32(paired16, paired16, 14)); return vget_lane_u8(paired32, 0) | ((int) vget_lane_u8(paired32, 4) << 4); #endif } // NEON does not provide this method // Creates a 4-bit mask from the most significant bits of the four // single-precision, floating-point values. // https://msdn.microsoft.com/en-us/library/vstudio/4490ys29(v=vs.100).aspx FORCE_INLINE int _mm_movemask_ps(__m128 a) { uint32x4_t input = vreinterpretq_u32_m128(a); #if defined(__aarch64__) static const int32x4_t shift = {0, 1, 2, 3}; uint32x4_t tmp = vshrq_n_u32(input, 31); return vaddvq_u32(vshlq_u32(tmp, shift)); #else // Uses the exact same method as _mm_movemask_epi8, see that for details. // Shift out everything but the sign bits with a 32-bit unsigned shift // right. uint64x2_t high_bits = vreinterpretq_u64_u32(vshrq_n_u32(input, 31)); // Merge the two pairs together with a 64-bit unsigned shift right + add. uint8x16_t paired = vreinterpretq_u8_u64(vsraq_n_u64(high_bits, high_bits, 31)); // Extract the result. return vgetq_lane_u8(paired, 0) | (vgetq_lane_u8(paired, 8) << 2); #endif } // Multiplies the four single-precision, floating-point values of a and b. // // r0 := a0 * b0 // r1 := a1 * b1 // r2 := a2 * b2 // r3 := a3 * b3 // // https://msdn.microsoft.com/en-us/library/vstudio/22kbk6t9(v=vs.100).aspx FORCE_INLINE __m128 _mm_mul_ps(__m128 a, __m128 b) { return vreinterpretq_m128_f32( vmulq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(b))); } // Multiply the lower single-precision (32-bit) floating-point element in a and // b, store the result in the lower element of dst, and copy the upper 3 packed // elements from a to the upper elements of dst. // // dst[31:0] := a[31:0] * b[31:0] // dst[127:32] := a[127:32] // // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mul_ss FORCE_INLINE __m128 _mm_mul_ss(__m128 a, __m128 b) { return _mm_move_ss(a, _mm_mul_ps(a, b)); } // Multiply the packed unsigned 16-bit integers in a and b, producing // intermediate 32-bit integers, and store the high 16 bits of the intermediate // integers in dst. // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mulhi_pu16 FORCE_INLINE __m64 _mm_mulhi_pu16(__m64 a, __m64 b) { return vreinterpret_m64_u16(vshrn_n_u32( vmull_u16(vreinterpret_u16_m64(a), vreinterpret_u16_m64(b)), 16)); } // Computes the bitwise OR of the four single-precision, floating-point values // of a and b. // https://msdn.microsoft.com/en-us/library/vstudio/7ctdsyy0(v=vs.100).aspx FORCE_INLINE __m128 _mm_or_ps(__m128 a, __m128 b) { return vreinterpretq_m128_s32( vorrq_s32(vreinterpretq_s32_m128(a), vreinterpretq_s32_m128(b))); } // Average packed unsigned 8-bit integers in a and b, and store the results in // dst. // // FOR j := 0 to 7 // i := j*8 // dst[i+7:i] := (a[i+7:i] + b[i+7:i] + 1) >> 1 // ENDFOR // // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_m_pavgb #define _m_pavgb(a, b) _mm_avg_pu8(a, b) // Average packed unsigned 16-bit integers in a and b, and store the results in // dst. // // FOR j := 0 to 3 // i := j*16 // dst[i+15:i] := (a[i+15:i] + b[i+15:i] + 1) >> 1 // ENDFOR // // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_m_pavgw #define _m_pavgw(a, b) _mm_avg_pu16(a, b) // Extract a 16-bit integer from a, selected with imm8, and store the result in // the lower element of dst. // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_m_pextrw #define _m_pextrw(a, imm) _mm_extract_pi16(a, imm) // Copy a to dst, and insert the 16-bit integer i into dst at the location // specified by imm8. // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=m_pinsrw #define _m_pinsrw(a, i, imm) _mm_insert_pi16(a, i, imm) // Compare packed signed 16-bit integers in a and b, and store packed maximum // values in dst. // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_m_pmaxsw #define _m_pmaxsw(a, b) _mm_max_pi16(a, b) // Compare packed unsigned 8-bit integers in a and b, and store packed maximum // values in dst. // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_m_pmaxub #define _m_pmaxub(a, b) _mm_max_pu8(a, b) // Compare packed signed 16-bit integers in a and b, and store packed minimum // values in dst. // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_m_pminsw #define _m_pminsw(a, b) _mm_min_pi16(a, b) // Compare packed unsigned 8-bit integers in a and b, and store packed minimum // values in dst. // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_m_pminub #define _m_pminub(a, b) _mm_min_pu8(a, b) // Create mask from the most significant bit of each 8-bit element in a, and // store the result in dst. // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_m_pmovmskb #define _m_pmovmskb(a) _mm_movemask_pi8(a) // Multiply the packed unsigned 16-bit integers in a and b, producing // intermediate 32-bit integers, and store the high 16 bits of the intermediate // integers in dst. // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_m_pmulhuw #define _m_pmulhuw(a, b) _mm_mulhi_pu16(a, b) // Loads one cache line of data from address p to a location closer to the // processor. https://msdn.microsoft.com/en-us/library/84szxsww(v=vs.100).aspx FORCE_INLINE void _mm_prefetch(const void *p, int i) { (void) i; __builtin_prefetch(p); } // Compute the absolute differences of packed unsigned 8-bit integers in a and // b, then horizontally sum each consecutive 8 differences to produce four // unsigned 16-bit integers, and pack these unsigned 16-bit integers in the low // 16 bits of dst. // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=m_psadbw #define _m_psadbw(a, b) _mm_sad_pu8(a, b) // Shuffle 16-bit integers in a using the control in imm8, and store the results // in dst. // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_m_pshufw #define _m_pshufw(a, imm) _mm_shuffle_pi16(a, imm) // Compute the approximate reciprocal of packed single-precision (32-bit) // floating-point elements in a, and store the results in dst. The maximum // relative error for this approximation is less than 1.5*2^-12. // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_rcp_ps FORCE_INLINE __m128 _mm_rcp_ps(__m128 in) { float32x4_t recip = vrecpeq_f32(vreinterpretq_f32_m128(in)); recip = vmulq_f32(recip, vrecpsq_f32(recip, vreinterpretq_f32_m128(in))); #if SSE2NEON_PRECISE_DIV // Additional Netwon-Raphson iteration for accuracy recip = vmulq_f32(recip, vrecpsq_f32(recip, vreinterpretq_f32_m128(in))); #endif return vreinterpretq_m128_f32(recip); } // Compute the approximate reciprocal of the lower single-precision (32-bit) // floating-point element in a, store the result in the lower element of dst, // and copy the upper 3 packed elements from a to the upper elements of dst. The // maximum relative error for this approximation is less than 1.5*2^-12. // // dst[31:0] := (1.0 / a[31:0]) // dst[127:32] := a[127:32] // // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_rcp_ss FORCE_INLINE __m128 _mm_rcp_ss(__m128 a) { return _mm_move_ss(a, _mm_rcp_ps(a)); } // Computes the approximations of the reciprocal square roots of the four // single-precision floating point values of in. // The current precision is 1% error. // https://msdn.microsoft.com/en-us/library/22hfsh53(v=vs.100).aspx FORCE_INLINE __m128 _mm_rsqrt_ps(__m128 in) { float32x4_t out = vrsqrteq_f32(vreinterpretq_f32_m128(in)); #if SSE2NEON_PRECISE_SQRT // Additional Netwon-Raphson iteration for accuracy out = vmulq_f32( out, vrsqrtsq_f32(vmulq_f32(vreinterpretq_f32_m128(in), out), out)); out = vmulq_f32( out, vrsqrtsq_f32(vmulq_f32(vreinterpretq_f32_m128(in), out), out)); #endif return vreinterpretq_m128_f32(out); } // Compute the approximate reciprocal square root of the lower single-precision // (32-bit) floating-point element in a, store the result in the lower element // of dst, and copy the upper 3 packed elements from a to the upper elements of // dst. // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_rsqrt_ss FORCE_INLINE __m128 _mm_rsqrt_ss(__m128 in) { return vsetq_lane_f32(vgetq_lane_f32(_mm_rsqrt_ps(in), 0), in, 0); } // Compute the absolute differences of packed unsigned 8-bit integers in a and // b, then horizontally sum each consecutive 8 differences to produce four // unsigned 16-bit integers, and pack these unsigned 16-bit integers in the low // 16 bits of dst. // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_sad_pu8 FORCE_INLINE __m64 _mm_sad_pu8(__m64 a, __m64 b) { uint64x1_t t = vpaddl_u32(vpaddl_u16( vpaddl_u8(vabd_u8(vreinterpret_u8_m64(a), vreinterpret_u8_m64(b))))); return vreinterpret_m64_u16( vset_lane_u16(vget_lane_u64(t, 0), vdup_n_u16(0), 0)); } // Sets the four single-precision, floating-point values to the four inputs. // https://msdn.microsoft.com/en-us/library/vstudio/afh0zf75(v=vs.100).aspx FORCE_INLINE __m128 _mm_set_ps(float w, float z, float y, float x) { float ALIGN_STRUCT(16) data[4] = {x, y, z, w}; return vreinterpretq_m128_f32(vld1q_f32(data)); } // Sets the four single-precision, floating-point values to w. // https://msdn.microsoft.com/en-us/library/vstudio/2x1se8ha(v=vs.100).aspx FORCE_INLINE __m128 _mm_set_ps1(float _w) { return vreinterpretq_m128_f32(vdupq_n_f32(_w)); } // Macro: Set the rounding mode bits of the MXCSR control and status register to // the value in unsigned 32-bit integer a. The rounding mode may contain any of // the following flags: _MM_ROUND_NEAREST, _MM_ROUND_DOWN, _MM_ROUND_UP, // _MM_ROUND_TOWARD_ZERO // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_MM_SET_ROUNDING_MODE FORCE_INLINE void _MM_SET_ROUNDING_MODE(int rounding) { union { fpcr_bitfield field; #if defined(__aarch64__) uint64_t value; #else uint32_t value; #endif } r; #if defined(__aarch64__) asm volatile("mrs %0, FPCR" : "=r"(r.value)); /* read */ #else asm volatile("vmrs %0, FPSCR" : "=r"(r.value)); /* read */ #endif switch (rounding) { case _MM_ROUND_TOWARD_ZERO: r.field.bit22 = 1; r.field.bit23 = 1; break; case _MM_ROUND_DOWN: r.field.bit22 = 0; r.field.bit23 = 1; break; case _MM_ROUND_UP: r.field.bit22 = 1; r.field.bit23 = 0; break; default: //_MM_ROUND_NEAREST r.field.bit22 = 0; r.field.bit23 = 0; } #if defined(__aarch64__) asm volatile("msr FPCR, %0" ::"r"(r)); /* write */ #else asm volatile("vmsr FPSCR, %0" ::"r"(r)); /* write */ #endif } // Copy single-precision (32-bit) floating-point element a to the lower element // of dst, and zero the upper 3 elements. // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_set_ss FORCE_INLINE __m128 _mm_set_ss(float a) { float ALIGN_STRUCT(16) data[4] = {a, 0, 0, 0}; return vreinterpretq_m128_f32(vld1q_f32(data)); } // Sets the four single-precision, floating-point values to w. // // r0 := r1 := r2 := r3 := w // // https://msdn.microsoft.com/en-us/library/vstudio/2x1se8ha(v=vs.100).aspx FORCE_INLINE __m128 _mm_set1_ps(float _w) { return vreinterpretq_m128_f32(vdupq_n_f32(_w)); } FORCE_INLINE void _mm_setcsr(unsigned int a) { _MM_SET_ROUNDING_MODE(a); } // Sets the four single-precision, floating-point values to the four inputs in // reverse order. // https://msdn.microsoft.com/en-us/library/vstudio/d2172ct3(v=vs.100).aspx FORCE_INLINE __m128 _mm_setr_ps(float w, float z, float y, float x) { float ALIGN_STRUCT(16) data[4] = {w, z, y, x}; return vreinterpretq_m128_f32(vld1q_f32(data)); } // Clears the four single-precision, floating-point values. // https://msdn.microsoft.com/en-us/library/vstudio/tk1t2tbz(v=vs.100).aspx FORCE_INLINE __m128 _mm_setzero_ps(void) { return vreinterpretq_m128_f32(vdupq_n_f32(0)); } // Shuffle 16-bit integers in a using the control in imm8, and store the results // in dst. // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_shuffle_pi16 #if __has_builtin(__builtin_shufflevector) #define _mm_shuffle_pi16(a, imm) \ __extension__({ \ vreinterpret_m64_s16(__builtin_shufflevector( \ vreinterpret_s16_m64(a), vreinterpret_s16_m64(a), (imm & 0x3), \ ((imm >> 2) & 0x3), ((imm >> 4) & 0x3), ((imm >> 6) & 0x3))); \ }) #else #define _mm_shuffle_pi16(a, imm) \ __extension__({ \ int16x4_t ret; \ ret = \ vmov_n_s16(vget_lane_s16(vreinterpret_s16_m64(a), (imm) & (0x3))); \ ret = vset_lane_s16( \ vget_lane_s16(vreinterpret_s16_m64(a), ((imm) >> 2) & 0x3), ret, \ 1); \ ret = vset_lane_s16( \ vget_lane_s16(vreinterpret_s16_m64(a), ((imm) >> 4) & 0x3), ret, \ 2); \ ret = vset_lane_s16( \ vget_lane_s16(vreinterpret_s16_m64(a), ((imm) >> 6) & 0x3), ret, \ 3); \ vreinterpret_m64_s16(ret); \ }) #endif // Guarantees that every preceding store is globally visible before any // subsequent store. // https://msdn.microsoft.com/en-us/library/5h2w73d1%28v=vs.90%29.aspx FORCE_INLINE void _mm_sfence(void) { __sync_synchronize(); } // FORCE_INLINE __m128 _mm_shuffle_ps(__m128 a, __m128 b, __constrange(0,255) // int imm) #if __has_builtin(__builtin_shufflevector) #define _mm_shuffle_ps(a, b, imm) \ __extension__({ \ float32x4_t _input1 = vreinterpretq_f32_m128(a); \ float32x4_t _input2 = vreinterpretq_f32_m128(b); \ float32x4_t _shuf = __builtin_shufflevector( \ _input1, _input2, (imm) & (0x3), ((imm) >> 2) & 0x3, \ (((imm) >> 4) & 0x3) + 4, (((imm) >> 6) & 0x3) + 4); \ vreinterpretq_m128_f32(_shuf); \ }) #else // generic #define _mm_shuffle_ps(a, b, imm) \ __extension__({ \ __m128 ret; \ switch (imm) { \ case _MM_SHUFFLE(1, 0, 3, 2): \ ret = _mm_shuffle_ps_1032((a), (b)); \ break; \ case _MM_SHUFFLE(2, 3, 0, 1): \ ret = _mm_shuffle_ps_2301((a), (b)); \ break; \ case _MM_SHUFFLE(0, 3, 2, 1): \ ret = _mm_shuffle_ps_0321((a), (b)); \ break; \ case _MM_SHUFFLE(2, 1, 0, 3): \ ret = _mm_shuffle_ps_2103((a), (b)); \ break; \ case _MM_SHUFFLE(1, 0, 1, 0): \ ret = _mm_movelh_ps((a), (b)); \ break; \ case _MM_SHUFFLE(1, 0, 0, 1): \ ret = _mm_shuffle_ps_1001((a), (b)); \ break; \ case _MM_SHUFFLE(0, 1, 0, 1): \ ret = _mm_shuffle_ps_0101((a), (b)); \ break; \ case _MM_SHUFFLE(3, 2, 1, 0): \ ret = _mm_shuffle_ps_3210((a), (b)); \ break; \ case _MM_SHUFFLE(0, 0, 1, 1): \ ret = _mm_shuffle_ps_0011((a), (b)); \ break; \ case _MM_SHUFFLE(0, 0, 2, 2): \ ret = _mm_shuffle_ps_0022((a), (b)); \ break; \ case _MM_SHUFFLE(2, 2, 0, 0): \ ret = _mm_shuffle_ps_2200((a), (b)); \ break; \ case _MM_SHUFFLE(3, 2, 0, 2): \ ret = _mm_shuffle_ps_3202((a), (b)); \ break; \ case _MM_SHUFFLE(3, 2, 3, 2): \ ret = _mm_movehl_ps((b), (a)); \ break; \ case _MM_SHUFFLE(1, 1, 3, 3): \ ret = _mm_shuffle_ps_1133((a), (b)); \ break; \ case _MM_SHUFFLE(2, 0, 1, 0): \ ret = _mm_shuffle_ps_2010((a), (b)); \ break; \ case _MM_SHUFFLE(2, 0, 0, 1): \ ret = _mm_shuffle_ps_2001((a), (b)); \ break; \ case _MM_SHUFFLE(2, 0, 3, 2): \ ret = _mm_shuffle_ps_2032((a), (b)); \ break; \ default: \ ret = _mm_shuffle_ps_default((a), (b), (imm)); \ break; \ } \ ret; \ }) #endif // Computes the approximations of square roots of the four single-precision, // floating-point values of a. First computes reciprocal square roots and then // reciprocals of the four values. // // r0 := sqrt(a0) // r1 := sqrt(a1) // r2 := sqrt(a2) // r3 := sqrt(a3) // // https://msdn.microsoft.com/en-us/library/vstudio/8z67bwwk(v=vs.100).aspx FORCE_INLINE __m128 _mm_sqrt_ps(__m128 in) { #if SSE2NEON_PRECISE_SQRT float32x4_t recip = vrsqrteq_f32(vreinterpretq_f32_m128(in)); // Test for vrsqrteq_f32(0) -> positive infinity case. // Change to zero, so that s * 1/sqrt(s) result is zero too. const uint32x4_t pos_inf = vdupq_n_u32(0x7F800000); const uint32x4_t div_by_zero = vceqq_u32(pos_inf, vreinterpretq_u32_f32(recip)); recip = vreinterpretq_f32_u32( vandq_u32(vmvnq_u32(div_by_zero), vreinterpretq_u32_f32(recip))); // Additional Netwon-Raphson iteration for accuracy recip = vmulq_f32( vrsqrtsq_f32(vmulq_f32(recip, recip), vreinterpretq_f32_m128(in)), recip); recip = vmulq_f32( vrsqrtsq_f32(vmulq_f32(recip, recip), vreinterpretq_f32_m128(in)), recip); // sqrt(s) = s * 1/sqrt(s) return vreinterpretq_m128_f32(vmulq_f32(vreinterpretq_f32_m128(in), recip)); #elif defined(__aarch64__) return vreinterpretq_m128_f32(vsqrtq_f32(vreinterpretq_f32_m128(in))); #else float32x4_t recipsq = vrsqrteq_f32(vreinterpretq_f32_m128(in)); float32x4_t sq = vrecpeq_f32(recipsq); return vreinterpretq_m128_f32(sq); #endif } // Computes the approximation of the square root of the scalar single-precision // floating point value of in. // https://msdn.microsoft.com/en-us/library/ahfsc22d(v=vs.100).aspx FORCE_INLINE __m128 _mm_sqrt_ss(__m128 in) { float32_t value = vgetq_lane_f32(vreinterpretq_f32_m128(_mm_sqrt_ps(in)), 0); return vreinterpretq_m128_f32( vsetq_lane_f32(value, vreinterpretq_f32_m128(in), 0)); } // Stores four single-precision, floating-point values. // https://msdn.microsoft.com/en-us/library/vstudio/s3h4ay6y(v=vs.100).aspx FORCE_INLINE void _mm_store_ps(float *p, __m128 a) { vst1q_f32(p, vreinterpretq_f32_m128(a)); } // Store the lower single-precision (32-bit) floating-point element from a into // 4 contiguous elements in memory. mem_addr must be aligned on a 16-byte // boundary or a general-protection exception may be generated. // // MEM[mem_addr+31:mem_addr] := a[31:0] // MEM[mem_addr+63:mem_addr+32] := a[31:0] // MEM[mem_addr+95:mem_addr+64] := a[31:0] // MEM[mem_addr+127:mem_addr+96] := a[31:0] // // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_store_ps1 FORCE_INLINE void _mm_store_ps1(float *p, __m128 a) { float32_t a0 = vgetq_lane_f32(vreinterpretq_f32_m128(a), 0); vst1q_f32(p, vdupq_n_f32(a0)); } // Stores the lower single - precision, floating - point value. // https://msdn.microsoft.com/en-us/library/tzz10fbx(v=vs.100).aspx FORCE_INLINE void _mm_store_ss(float *p, __m128 a) { vst1q_lane_f32(p, vreinterpretq_f32_m128(a), 0); } // Store the lower single-precision (32-bit) floating-point element from a into // 4 contiguous elements in memory. mem_addr must be aligned on a 16-byte // boundary or a general-protection exception may be generated. // // MEM[mem_addr+31:mem_addr] := a[31:0] // MEM[mem_addr+63:mem_addr+32] := a[31:0] // MEM[mem_addr+95:mem_addr+64] := a[31:0] // MEM[mem_addr+127:mem_addr+96] := a[31:0] // // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_store1_ps #define _mm_store1_ps _mm_store_ps1 // Stores the upper two single-precision, floating-point values of a to the // address p. // // *p0 := a2 // *p1 := a3 // // https://msdn.microsoft.com/en-us/library/a7525fs8(v%3dvs.90).aspx FORCE_INLINE void _mm_storeh_pi(__m64 *p, __m128 a) { *p = vreinterpret_m64_f32(vget_high_f32(a)); } // Stores the lower two single-precision floating point values of a to the // address p. // // *p0 := a0 // *p1 := a1 // // https://msdn.microsoft.com/en-us/library/h54t98ks(v=vs.90).aspx FORCE_INLINE void _mm_storel_pi(__m64 *p, __m128 a) { *p = vreinterpret_m64_f32(vget_low_f32(a)); } // Store 4 single-precision (32-bit) floating-point elements from a into memory // in reverse order. mem_addr must be aligned on a 16-byte boundary or a // general-protection exception may be generated. // // MEM[mem_addr+31:mem_addr] := a[127:96] // MEM[mem_addr+63:mem_addr+32] := a[95:64] // MEM[mem_addr+95:mem_addr+64] := a[63:32] // MEM[mem_addr+127:mem_addr+96] := a[31:0] // // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_storer_ps FORCE_INLINE void _mm_storer_ps(float *p, __m128 a) { float32x4_t tmp = vrev64q_f32(vreinterpretq_f32_m128(a)); float32x4_t rev = vextq_f32(tmp, tmp, 2); vst1q_f32(p, rev); } // Stores four single-precision, floating-point values. // https://msdn.microsoft.com/en-us/library/44e30x22(v=vs.100).aspx FORCE_INLINE void _mm_storeu_ps(float *p, __m128 a) { vst1q_f32(p, vreinterpretq_f32_m128(a)); } // Stores 16-bits of integer data a at the address p. // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_storeu_si16 FORCE_INLINE void _mm_storeu_si16(void *p, __m128i a) { vst1q_lane_s16((int16_t *) p, vreinterpretq_s16_m128i(a), 0); } // Stores 64-bits of integer data a at the address p. // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_storeu_si64 FORCE_INLINE void _mm_storeu_si64(void *p, __m128i a) { vst1q_lane_s64((int64_t *) p, vreinterpretq_s64_m128i(a), 0); } // Store 64-bits of integer data from a into memory using a non-temporal memory // hint. // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_stream_pi FORCE_INLINE void _mm_stream_pi(__m64 *p, __m64 a) { vst1_s64((int64_t *) p, vreinterpret_s64_m64(a)); } // Store 128-bits (composed of 4 packed single-precision (32-bit) floating- // point elements) from a into memory using a non-temporal memory hint. // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_stream_ps FORCE_INLINE void _mm_stream_ps(float *p, __m128 a) { #if __has_builtin(__builtin_nontemporal_store) __builtin_nontemporal_store(a, (float32x4_t *) p); #else vst1q_f32(p, vreinterpretq_f32_m128(a)); #endif } // Subtracts the four single-precision, floating-point values of a and b. // // r0 := a0 - b0 // r1 := a1 - b1 // r2 := a2 - b2 // r3 := a3 - b3 // // https://msdn.microsoft.com/en-us/library/vstudio/1zad2k61(v=vs.100).aspx FORCE_INLINE __m128 _mm_sub_ps(__m128 a, __m128 b) { return vreinterpretq_m128_f32( vsubq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(b))); } // Subtract the lower single-precision (32-bit) floating-point element in b from // the lower single-precision (32-bit) floating-point element in a, store the // result in the lower element of dst, and copy the upper 3 packed elements from // a to the upper elements of dst. // // dst[31:0] := a[31:0] - b[31:0] // dst[127:32] := a[127:32] // // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_sub_ss FORCE_INLINE __m128 _mm_sub_ss(__m128 a, __m128 b) { return _mm_move_ss(a, _mm_sub_ps(a, b)); } // Macro: Transpose the 4x4 matrix formed by the 4 rows of single-precision // (32-bit) floating-point elements in row0, row1, row2, and row3, and store the // transposed matrix in these vectors (row0 now contains column 0, etc.). // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=MM_TRANSPOSE4_PS #define _MM_TRANSPOSE4_PS(row0, row1, row2, row3) \ do { \ float32x4x2_t ROW01 = vtrnq_f32(row0, row1); \ float32x4x2_t ROW23 = vtrnq_f32(row2, row3); \ row0 = vcombine_f32(vget_low_f32(ROW01.val[0]), \ vget_low_f32(ROW23.val[0])); \ row1 = vcombine_f32(vget_low_f32(ROW01.val[1]), \ vget_low_f32(ROW23.val[1])); \ row2 = vcombine_f32(vget_high_f32(ROW01.val[0]), \ vget_high_f32(ROW23.val[0])); \ row3 = vcombine_f32(vget_high_f32(ROW01.val[1]), \ vget_high_f32(ROW23.val[1])); \ } while (0) // according to the documentation, these intrinsics behave the same as the // non-'u' versions. We'll just alias them here. #define _mm_ucomieq_ss _mm_comieq_ss #define _mm_ucomige_ss _mm_comige_ss #define _mm_ucomigt_ss _mm_comigt_ss #define _mm_ucomile_ss _mm_comile_ss #define _mm_ucomilt_ss _mm_comilt_ss #define _mm_ucomineq_ss _mm_comineq_ss // Return vector of type __m128i with undefined elements. // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_undefined_si128 FORCE_INLINE __m128i _mm_undefined_si128(void) { #if defined(__GNUC__) || defined(__clang__) #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wuninitialized" #endif __m128i a; return a; #if defined(__GNUC__) || defined(__clang__) #pragma GCC diagnostic pop #endif } // Return vector of type __m128 with undefined elements. // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_undefined_ps FORCE_INLINE __m128 _mm_undefined_ps(void) { #if defined(__GNUC__) || defined(__clang__) #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wuninitialized" #endif __m128 a; return a; #if defined(__GNUC__) || defined(__clang__) #pragma GCC diagnostic pop #endif } // Selects and interleaves the upper two single-precision, floating-point values // from a and b. // // r0 := a2 // r1 := b2 // r2 := a3 // r3 := b3 // // https://msdn.microsoft.com/en-us/library/skccxx7d%28v=vs.90%29.aspx FORCE_INLINE __m128 _mm_unpackhi_ps(__m128 a, __m128 b) { #if defined(__aarch64__) return vreinterpretq_m128_f32( vzip2q_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(b))); #else float32x2_t a1 = vget_high_f32(vreinterpretq_f32_m128(a)); float32x2_t b1 = vget_high_f32(vreinterpretq_f32_m128(b)); float32x2x2_t result = vzip_f32(a1, b1); return vreinterpretq_m128_f32(vcombine_f32(result.val[0], result.val[1])); #endif } // Selects and interleaves the lower two single-precision, floating-point values // from a and b. // // r0 := a0 // r1 := b0 // r2 := a1 // r3 := b1 // // https://msdn.microsoft.com/en-us/library/25st103b%28v=vs.90%29.aspx FORCE_INLINE __m128 _mm_unpacklo_ps(__m128 a, __m128 b) { #if defined(__aarch64__) return vreinterpretq_m128_f32( vzip1q_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(b))); #else float32x2_t a1 = vget_low_f32(vreinterpretq_f32_m128(a)); float32x2_t b1 = vget_low_f32(vreinterpretq_f32_m128(b)); float32x2x2_t result = vzip_f32(a1, b1); return vreinterpretq_m128_f32(vcombine_f32(result.val[0], result.val[1])); #endif } // Computes bitwise EXOR (exclusive-or) of the four single-precision, // floating-point values of a and b. // https://msdn.microsoft.com/en-us/library/ss6k3wk8(v=vs.100).aspx FORCE_INLINE __m128 _mm_xor_ps(__m128 a, __m128 b) { return vreinterpretq_m128_s32( veorq_s32(vreinterpretq_s32_m128(a), vreinterpretq_s32_m128(b))); } /* SSE2 */ // Adds the 8 signed or unsigned 16-bit integers in a to the 8 signed or // unsigned 16-bit integers in b. // https://msdn.microsoft.com/en-us/library/fceha5k4(v=vs.100).aspx FORCE_INLINE __m128i _mm_add_epi16(__m128i a, __m128i b) { return vreinterpretq_m128i_s16( vaddq_s16(vreinterpretq_s16_m128i(a), vreinterpretq_s16_m128i(b))); } // Adds the 4 signed or unsigned 32-bit integers in a to the 4 signed or // unsigned 32-bit integers in b. // // r0 := a0 + b0 // r1 := a1 + b1 // r2 := a2 + b2 // r3 := a3 + b3 // // https://msdn.microsoft.com/en-us/library/vstudio/09xs4fkk(v=vs.100).aspx FORCE_INLINE __m128i _mm_add_epi32(__m128i a, __m128i b) { return vreinterpretq_m128i_s32( vaddq_s32(vreinterpretq_s32_m128i(a), vreinterpretq_s32_m128i(b))); } // Adds the 4 signed or unsigned 64-bit integers in a to the 4 signed or // unsigned 32-bit integers in b. // https://msdn.microsoft.com/en-us/library/vstudio/09xs4fkk(v=vs.100).aspx FORCE_INLINE __m128i _mm_add_epi64(__m128i a, __m128i b) { return vreinterpretq_m128i_s64( vaddq_s64(vreinterpretq_s64_m128i(a), vreinterpretq_s64_m128i(b))); } // Adds the 16 signed or unsigned 8-bit integers in a to the 16 signed or // unsigned 8-bit integers in b. // https://technet.microsoft.com/en-us/subscriptions/yc7tcyzs(v=vs.90) FORCE_INLINE __m128i _mm_add_epi8(__m128i a, __m128i b) { return vreinterpretq_m128i_s8( vaddq_s8(vreinterpretq_s8_m128i(a), vreinterpretq_s8_m128i(b))); } // Add packed double-precision (64-bit) floating-point elements in a and b, and // store the results in dst. // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_add_pd FORCE_INLINE __m128d _mm_add_pd(__m128d a, __m128d b) { #if defined(__aarch64__) return vreinterpretq_m128d_f64( vaddq_f64(vreinterpretq_f64_m128d(a), vreinterpretq_f64_m128d(b))); #else double *da = (double *) &a; double *db = (double *) &b; double c[2]; c[0] = da[0] + db[0]; c[1] = da[1] + db[1]; return vld1q_f32((float32_t *) c); #endif } // Add the lower double-precision (64-bit) floating-point element in a and b, // store the result in the lower element of dst, and copy the upper element from // a to the upper element of dst. // // dst[63:0] := a[63:0] + b[63:0] // dst[127:64] := a[127:64] // // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_add_sd FORCE_INLINE __m128d _mm_add_sd(__m128d a, __m128d b) { #if defined(__aarch64__) return _mm_move_sd(a, _mm_add_pd(a, b)); #else double *da = (double *) &a; double *db = (double *) &b; double c[2]; c[0] = da[0] + db[0]; c[1] = da[1]; return vld1q_f32((float32_t *) c); #endif } // Add 64-bit integers a and b, and store the result in dst. // // dst[63:0] := a[63:0] + b[63:0] // // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_add_si64 FORCE_INLINE __m64 _mm_add_si64(__m64 a, __m64 b) { return vreinterpret_m64_s64( vadd_s64(vreinterpret_s64_m64(a), vreinterpret_s64_m64(b))); } // Adds the 8 signed 16-bit integers in a to the 8 signed 16-bit integers in b // and saturates. // // r0 := SignedSaturate(a0 + b0) // r1 := SignedSaturate(a1 + b1) // ... // r7 := SignedSaturate(a7 + b7) // // https://msdn.microsoft.com/en-us/library/1a306ef8(v=vs.100).aspx FORCE_INLINE __m128i _mm_adds_epi16(__m128i a, __m128i b) { return vreinterpretq_m128i_s16( vqaddq_s16(vreinterpretq_s16_m128i(a), vreinterpretq_s16_m128i(b))); } // Add packed signed 8-bit integers in a and b using saturation, and store the // results in dst. // // FOR j := 0 to 15 // i := j*8 // dst[i+7:i] := Saturate8( a[i+7:i] + b[i+7:i] ) // ENDFOR // // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_adds_epi8 FORCE_INLINE __m128i _mm_adds_epi8(__m128i a, __m128i b) { return vreinterpretq_m128i_s8( vqaddq_s8(vreinterpretq_s8_m128i(a), vreinterpretq_s8_m128i(b))); } // Add packed unsigned 16-bit integers in a and b using saturation, and store // the results in dst. // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_adds_epu16 FORCE_INLINE __m128i _mm_adds_epu16(__m128i a, __m128i b) { return vreinterpretq_m128i_u16( vqaddq_u16(vreinterpretq_u16_m128i(a), vreinterpretq_u16_m128i(b))); } // Adds the 16 unsigned 8-bit integers in a to the 16 unsigned 8-bit integers in // b and saturates.. // https://msdn.microsoft.com/en-us/library/9hahyddy(v=vs.100).aspx FORCE_INLINE __m128i _mm_adds_epu8(__m128i a, __m128i b) { return vreinterpretq_m128i_u8( vqaddq_u8(vreinterpretq_u8_m128i(a), vreinterpretq_u8_m128i(b))); } // Compute the bitwise AND of packed double-precision (64-bit) floating-point // elements in a and b, and store the results in dst. // // FOR j := 0 to 1 // i := j*64 // dst[i+63:i] := a[i+63:i] AND b[i+63:i] // ENDFOR // // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_and_pd FORCE_INLINE __m128d _mm_and_pd(__m128d a, __m128d b) { return vreinterpretq_m128d_s64( vandq_s64(vreinterpretq_s64_m128d(a), vreinterpretq_s64_m128d(b))); } // Computes the bitwise AND of the 128-bit value in a and the 128-bit value in // b. // // r := a & b // // https://msdn.microsoft.com/en-us/library/vstudio/6d1txsa8(v=vs.100).aspx FORCE_INLINE __m128i _mm_and_si128(__m128i a, __m128i b) { return vreinterpretq_m128i_s32( vandq_s32(vreinterpretq_s32_m128i(a), vreinterpretq_s32_m128i(b))); } // Compute the bitwise NOT of packed double-precision (64-bit) floating-point // elements in a and then AND with b, and store the results in dst. // // FOR j := 0 to 1 // i := j*64 // dst[i+63:i] := ((NOT a[i+63:i]) AND b[i+63:i]) // ENDFOR // // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_andnot_pd FORCE_INLINE __m128d _mm_andnot_pd(__m128d a, __m128d b) { // *NOTE* argument swap return vreinterpretq_m128d_s64( vbicq_s64(vreinterpretq_s64_m128d(b), vreinterpretq_s64_m128d(a))); } // Computes the bitwise AND of the 128-bit value in b and the bitwise NOT of the // 128-bit value in a. // // r := (~a) & b // // https://msdn.microsoft.com/en-us/library/vstudio/1beaceh8(v=vs.100).aspx FORCE_INLINE __m128i _mm_andnot_si128(__m128i a, __m128i b) { return vreinterpretq_m128i_s32( vbicq_s32(vreinterpretq_s32_m128i(b), vreinterpretq_s32_m128i(a))); // *NOTE* argument swap } // Computes the average of the 8 unsigned 16-bit integers in a and the 8 // unsigned 16-bit integers in b and rounds. // // r0 := (a0 + b0) / 2 // r1 := (a1 + b1) / 2 // ... // r7 := (a7 + b7) / 2 // // https://msdn.microsoft.com/en-us/library/vstudio/y13ca3c8(v=vs.90).aspx FORCE_INLINE __m128i _mm_avg_epu16(__m128i a, __m128i b) { return (__m128i) vrhaddq_u16(vreinterpretq_u16_m128i(a), vreinterpretq_u16_m128i(b)); } // Computes the average of the 16 unsigned 8-bit integers in a and the 16 // unsigned 8-bit integers in b and rounds. // // r0 := (a0 + b0) / 2 // r1 := (a1 + b1) / 2 // ... // r15 := (a15 + b15) / 2 // // https://msdn.microsoft.com/en-us/library/vstudio/8zwh554a(v%3dvs.90).aspx FORCE_INLINE __m128i _mm_avg_epu8(__m128i a, __m128i b) { return vreinterpretq_m128i_u8( vrhaddq_u8(vreinterpretq_u8_m128i(a), vreinterpretq_u8_m128i(b))); } // Shift a left by imm8 bytes while shifting in zeros, and store the results in // dst. // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_bslli_si128 #define _mm_bslli_si128(a, imm) _mm_slli_si128(a, imm) // Shift a right by imm8 bytes while shifting in zeros, and store the results in // dst. // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_bsrli_si128 #define _mm_bsrli_si128(a, imm) _mm_srli_si128(a, imm) // Cast vector of type __m128d to type __m128. This intrinsic is only used for // compilation and does not generate any instructions, thus it has zero latency. // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_castpd_ps FORCE_INLINE __m128 _mm_castpd_ps(__m128d a) { return vreinterpretq_m128_s64(vreinterpretq_s64_m128d(a)); } // Cast vector of type __m128d to type __m128i. This intrinsic is only used for // compilation and does not generate any instructions, thus it has zero latency. // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_castpd_si128 FORCE_INLINE __m128i _mm_castpd_si128(__m128d a) { return vreinterpretq_m128i_s64(vreinterpretq_s64_m128d(a)); } // Cast vector of type __m128 to type __m128d. This intrinsic is only used for // compilation and does not generate any instructions, thus it has zero latency. // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_castps_pd FORCE_INLINE __m128d _mm_castps_pd(__m128 a) { return vreinterpretq_m128d_s32(vreinterpretq_s32_m128(a)); } // Applies a type cast to reinterpret four 32-bit floating point values passed // in as a 128-bit parameter as packed 32-bit integers. // https://msdn.microsoft.com/en-us/library/bb514099.aspx FORCE_INLINE __m128i _mm_castps_si128(__m128 a) { return vreinterpretq_m128i_s32(vreinterpretq_s32_m128(a)); } // Cast vector of type __m128i to type __m128d. This intrinsic is only used for // compilation and does not generate any instructions, thus it has zero latency. // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_castsi128_pd FORCE_INLINE __m128d _mm_castsi128_pd(__m128i a) { #if defined(__aarch64__) return vreinterpretq_m128d_f64(vreinterpretq_f64_m128i(a)); #else return vreinterpretq_m128d_f32(vreinterpretq_f32_m128i(a)); #endif } // Applies a type cast to reinterpret four 32-bit integers passed in as a // 128-bit parameter as packed 32-bit floating point values. // https://msdn.microsoft.com/en-us/library/bb514029.aspx FORCE_INLINE __m128 _mm_castsi128_ps(__m128i a) { return vreinterpretq_m128_s32(vreinterpretq_s32_m128i(a)); } // Cache line containing p is flushed and invalidated from all caches in the // coherency domain. : // https://msdn.microsoft.com/en-us/library/ba08y07y(v=vs.100).aspx FORCE_INLINE void _mm_clflush(void const *p) { (void) p; // no corollary for Neon? } // Compares the 8 signed or unsigned 16-bit integers in a and the 8 signed or // unsigned 16-bit integers in b for equality. // https://msdn.microsoft.com/en-us/library/2ay060te(v=vs.100).aspx FORCE_INLINE __m128i _mm_cmpeq_epi16(__m128i a, __m128i b) { return vreinterpretq_m128i_u16( vceqq_s16(vreinterpretq_s16_m128i(a), vreinterpretq_s16_m128i(b))); } // Compare packed 32-bit integers in a and b for equality, and store the results // in dst FORCE_INLINE __m128i _mm_cmpeq_epi32(__m128i a, __m128i b) { return vreinterpretq_m128i_u32( vceqq_s32(vreinterpretq_s32_m128i(a), vreinterpretq_s32_m128i(b))); } // Compares the 16 signed or unsigned 8-bit integers in a and the 16 signed or // unsigned 8-bit integers in b for equality. // https://msdn.microsoft.com/en-us/library/windows/desktop/bz5xk21a(v=vs.90).aspx FORCE_INLINE __m128i _mm_cmpeq_epi8(__m128i a, __m128i b) { return vreinterpretq_m128i_u8( vceqq_s8(vreinterpretq_s8_m128i(a), vreinterpretq_s8_m128i(b))); } // Compare packed double-precision (64-bit) floating-point elements in a and b // for equality, and store the results in dst. // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cmpeq_pd FORCE_INLINE __m128d _mm_cmpeq_pd(__m128d a, __m128d b) { #if defined(__aarch64__) return vreinterpretq_m128d_u64( vceqq_f64(vreinterpretq_f64_m128d(a), vreinterpretq_f64_m128d(b))); #else // (a == b) -> (a_lo == b_lo) && (a_hi == b_hi) uint32x4_t cmp = vceqq_u32(vreinterpretq_u32_m128d(a), vreinterpretq_u32_m128d(b)); uint32x4_t swapped = vrev64q_u32(cmp); return vreinterpretq_m128d_u32(vandq_u32(cmp, swapped)); #endif } // Compare the lower double-precision (64-bit) floating-point elements in a and // b for equality, store the result in the lower element of dst, and copy the // upper element from a to the upper element of dst. // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cmpeq_sd FORCE_INLINE __m128d _mm_cmpeq_sd(__m128d a, __m128d b) { return _mm_move_sd(a, _mm_cmpeq_pd(a, b)); } // Compare packed double-precision (64-bit) floating-point elements in a and b // for greater-than-or-equal, and store the results in dst. // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cmpge_pd FORCE_INLINE __m128d _mm_cmpge_pd(__m128d a, __m128d b) { #if defined(__aarch64__) return vreinterpretq_m128d_u64( vcgeq_f64(vreinterpretq_f64_m128d(a), vreinterpretq_f64_m128d(b))); #else uint64_t a0 = (uint64_t) vget_low_u64(vreinterpretq_u64_m128d(a)); uint64_t a1 = (uint64_t) vget_high_u64(vreinterpretq_u64_m128d(a)); uint64_t b0 = (uint64_t) vget_low_u64(vreinterpretq_u64_m128d(b)); uint64_t b1 = (uint64_t) vget_high_u64(vreinterpretq_u64_m128d(b)); uint64_t d[2]; d[0] = (*(double *) &a0) >= (*(double *) &b0) ? ~UINT64_C(0) : UINT64_C(0); d[1] = (*(double *) &a1) >= (*(double *) &b1) ? ~UINT64_C(0) : UINT64_C(0); return vreinterpretq_m128d_u64(vld1q_u64(d)); #endif } // Compare the lower double-precision (64-bit) floating-point elements in a and // b for greater-than-or-equal, store the result in the lower element of dst, // and copy the upper element from a to the upper element of dst. // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cmpge_sd FORCE_INLINE __m128d _mm_cmpge_sd(__m128d a, __m128d b) { #if defined(__aarch64__) return _mm_move_sd(a, _mm_cmpge_pd(a, b)); #else // expand "_mm_cmpge_pd()" to reduce unnecessary operations uint64_t a0 = (uint64_t) vget_low_u64(vreinterpretq_u64_m128d(a)); uint64_t a1 = (uint64_t) vget_high_u64(vreinterpretq_u64_m128d(a)); uint64_t b0 = (uint64_t) vget_low_u64(vreinterpretq_u64_m128d(b)); uint64_t d[2]; d[0] = (*(double *) &a0) >= (*(double *) &b0) ? ~UINT64_C(0) : UINT64_C(0); d[1] = a1; return vreinterpretq_m128d_u64(vld1q_u64(d)); #endif } // Compares the 8 signed 16-bit integers in a and the 8 signed 16-bit integers // in b for greater than. // // r0 := (a0 > b0) ? 0xffff : 0x0 // r1 := (a1 > b1) ? 0xffff : 0x0 // ... // r7 := (a7 > b7) ? 0xffff : 0x0 // // https://technet.microsoft.com/en-us/library/xd43yfsa(v=vs.100).aspx FORCE_INLINE __m128i _mm_cmpgt_epi16(__m128i a, __m128i b) { return vreinterpretq_m128i_u16( vcgtq_s16(vreinterpretq_s16_m128i(a), vreinterpretq_s16_m128i(b))); } // Compares the 4 signed 32-bit integers in a and the 4 signed 32-bit integers // in b for greater than. // https://msdn.microsoft.com/en-us/library/vstudio/1s9f2z0y(v=vs.100).aspx FORCE_INLINE __m128i _mm_cmpgt_epi32(__m128i a, __m128i b) { return vreinterpretq_m128i_u32( vcgtq_s32(vreinterpretq_s32_m128i(a), vreinterpretq_s32_m128i(b))); } // Compares the 16 signed 8-bit integers in a and the 16 signed 8-bit integers // in b for greater than. // // r0 := (a0 > b0) ? 0xff : 0x0 // r1 := (a1 > b1) ? 0xff : 0x0 // ... // r15 := (a15 > b15) ? 0xff : 0x0 // // https://msdn.microsoft.com/zh-tw/library/wf45zt2b(v=vs.100).aspx FORCE_INLINE __m128i _mm_cmpgt_epi8(__m128i a, __m128i b) { return vreinterpretq_m128i_u8( vcgtq_s8(vreinterpretq_s8_m128i(a), vreinterpretq_s8_m128i(b))); } // Compare packed double-precision (64-bit) floating-point elements in a and b // for greater-than, and store the results in dst. // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cmpgt_pd FORCE_INLINE __m128d _mm_cmpgt_pd(__m128d a, __m128d b) { #if defined(__aarch64__) return vreinterpretq_m128d_u64( vcgtq_f64(vreinterpretq_f64_m128d(a), vreinterpretq_f64_m128d(b))); #else uint64_t a0 = (uint64_t) vget_low_u64(vreinterpretq_u64_m128d(a)); uint64_t a1 = (uint64_t) vget_high_u64(vreinterpretq_u64_m128d(a)); uint64_t b0 = (uint64_t) vget_low_u64(vreinterpretq_u64_m128d(b)); uint64_t b1 = (uint64_t) vget_high_u64(vreinterpretq_u64_m128d(b)); uint64_t d[2]; d[0] = (*(double *) &a0) > (*(double *) &b0) ? ~UINT64_C(0) : UINT64_C(0); d[1] = (*(double *) &a1) > (*(double *) &b1) ? ~UINT64_C(0) : UINT64_C(0); return vreinterpretq_m128d_u64(vld1q_u64(d)); #endif } // Compare the lower double-precision (64-bit) floating-point elements in a and // b for greater-than, store the result in the lower element of dst, and copy // the upper element from a to the upper element of dst. // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cmpgt_sd FORCE_INLINE __m128d _mm_cmpgt_sd(__m128d a, __m128d b) { #if defined(__aarch64__) return _mm_move_sd(a, _mm_cmpgt_pd(a, b)); #else // expand "_mm_cmpge_pd()" to reduce unnecessary operations uint64_t a0 = (uint64_t) vget_low_u64(vreinterpretq_u64_m128d(a)); uint64_t a1 = (uint64_t) vget_high_u64(vreinterpretq_u64_m128d(a)); uint64_t b0 = (uint64_t) vget_low_u64(vreinterpretq_u64_m128d(b)); uint64_t d[2]; d[0] = (*(double *) &a0) > (*(double *) &b0) ? ~UINT64_C(0) : UINT64_C(0); d[1] = a1; return vreinterpretq_m128d_u64(vld1q_u64(d)); #endif } // Compare packed double-precision (64-bit) floating-point elements in a and b // for less-than-or-equal, and store the results in dst. // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cmple_pd FORCE_INLINE __m128d _mm_cmple_pd(__m128d a, __m128d b) { #if defined(__aarch64__) return vreinterpretq_m128d_u64( vcleq_f64(vreinterpretq_f64_m128d(a), vreinterpretq_f64_m128d(b))); #else uint64_t a0 = (uint64_t) vget_low_u64(vreinterpretq_u64_m128d(a)); uint64_t a1 = (uint64_t) vget_high_u64(vreinterpretq_u64_m128d(a)); uint64_t b0 = (uint64_t) vget_low_u64(vreinterpretq_u64_m128d(b)); uint64_t b1 = (uint64_t) vget_high_u64(vreinterpretq_u64_m128d(b)); uint64_t d[2]; d[0] = (*(double *) &a0) <= (*(double *) &b0) ? ~UINT64_C(0) : UINT64_C(0); d[1] = (*(double *) &a1) <= (*(double *) &b1) ? ~UINT64_C(0) : UINT64_C(0); return vreinterpretq_m128d_u64(vld1q_u64(d)); #endif } // Compare the lower double-precision (64-bit) floating-point elements in a and // b for less-than-or-equal, store the result in the lower element of dst, and // copy the upper element from a to the upper element of dst. // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cmple_sd FORCE_INLINE __m128d _mm_cmple_sd(__m128d a, __m128d b) { #if defined(__aarch64__) return _mm_move_sd(a, _mm_cmple_pd(a, b)); #else // expand "_mm_cmpge_pd()" to reduce unnecessary operations uint64_t a0 = (uint64_t) vget_low_u64(vreinterpretq_u64_m128d(a)); uint64_t a1 = (uint64_t) vget_high_u64(vreinterpretq_u64_m128d(a)); uint64_t b0 = (uint64_t) vget_low_u64(vreinterpretq_u64_m128d(b)); uint64_t d[2]; d[0] = (*(double *) &a0) <= (*(double *) &b0) ? ~UINT64_C(0) : UINT64_C(0); d[1] = a1; return vreinterpretq_m128d_u64(vld1q_u64(d)); #endif } // Compares the 8 signed 16-bit integers in a and the 8 signed 16-bit integers // in b for less than. // // r0 := (a0 < b0) ? 0xffff : 0x0 // r1 := (a1 < b1) ? 0xffff : 0x0 // ... // r7 := (a7 < b7) ? 0xffff : 0x0 // // https://technet.microsoft.com/en-us/library/t863edb2(v=vs.100).aspx FORCE_INLINE __m128i _mm_cmplt_epi16(__m128i a, __m128i b) { return vreinterpretq_m128i_u16( vcltq_s16(vreinterpretq_s16_m128i(a), vreinterpretq_s16_m128i(b))); } // Compares the 4 signed 32-bit integers in a and the 4 signed 32-bit integers // in b for less than. // https://msdn.microsoft.com/en-us/library/vstudio/4ak0bf5d(v=vs.100).aspx FORCE_INLINE __m128i _mm_cmplt_epi32(__m128i a, __m128i b) { return vreinterpretq_m128i_u32( vcltq_s32(vreinterpretq_s32_m128i(a), vreinterpretq_s32_m128i(b))); } // Compares the 16 signed 8-bit integers in a and the 16 signed 8-bit integers // in b for lesser than. // https://msdn.microsoft.com/en-us/library/windows/desktop/9s46csht(v=vs.90).aspx FORCE_INLINE __m128i _mm_cmplt_epi8(__m128i a, __m128i b) { return vreinterpretq_m128i_u8( vcltq_s8(vreinterpretq_s8_m128i(a), vreinterpretq_s8_m128i(b))); } // Compare packed double-precision (64-bit) floating-point elements in a and b // for less-than, and store the results in dst. // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cmplt_pd FORCE_INLINE __m128d _mm_cmplt_pd(__m128d a, __m128d b) { #if defined(__aarch64__) return vreinterpretq_m128d_u64( vcltq_f64(vreinterpretq_f64_m128d(a), vreinterpretq_f64_m128d(b))); #else uint64_t a0 = (uint64_t) vget_low_u64(vreinterpretq_u64_m128d(a)); uint64_t a1 = (uint64_t) vget_high_u64(vreinterpretq_u64_m128d(a)); uint64_t b0 = (uint64_t) vget_low_u64(vreinterpretq_u64_m128d(b)); uint64_t b1 = (uint64_t) vget_high_u64(vreinterpretq_u64_m128d(b)); uint64_t d[2]; d[0] = (*(double *) &a0) < (*(double *) &b0) ? ~UINT64_C(0) : UINT64_C(0); d[1] = (*(double *) &a1) < (*(double *) &b1) ? ~UINT64_C(0) : UINT64_C(0); return vreinterpretq_m128d_u64(vld1q_u64(d)); #endif } // Compare the lower double-precision (64-bit) floating-point elements in a and // b for less-than, store the result in the lower element of dst, and copy the // upper element from a to the upper element of dst. // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cmplt_sd FORCE_INLINE __m128d _mm_cmplt_sd(__m128d a, __m128d b) { #if defined(__aarch64__) return _mm_move_sd(a, _mm_cmplt_pd(a, b)); #else uint64_t a0 = (uint64_t) vget_low_u64(vreinterpretq_u64_m128d(a)); uint64_t a1 = (uint64_t) vget_high_u64(vreinterpretq_u64_m128d(a)); uint64_t b0 = (uint64_t) vget_low_u64(vreinterpretq_u64_m128d(b)); uint64_t d[2]; d[0] = (*(double *) &a0) < (*(double *) &b0) ? ~UINT64_C(0) : UINT64_C(0); d[1] = a1; return vreinterpretq_m128d_u64(vld1q_u64(d)); #endif } // Compare packed double-precision (64-bit) floating-point elements in a and b // for not-equal, and store the results in dst. // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cmpneq_pd FORCE_INLINE __m128d _mm_cmpneq_pd(__m128d a, __m128d b) { #if defined(__aarch64__) return vreinterpretq_m128d_s32(vmvnq_s32(vreinterpretq_s32_u64( vceqq_f64(vreinterpretq_f64_m128d(a), vreinterpretq_f64_m128d(b))))); #else // (a == b) -> (a_lo == b_lo) && (a_hi == b_hi) uint32x4_t cmp = vceqq_u32(vreinterpretq_u32_m128d(a), vreinterpretq_u32_m128d(b)); uint32x4_t swapped = vrev64q_u32(cmp); return vreinterpretq_m128d_u32(vmvnq_u32(vandq_u32(cmp, swapped))); #endif } // Compare the lower double-precision (64-bit) floating-point elements in a and // b for not-equal, store the result in the lower element of dst, and copy the // upper element from a to the upper element of dst. // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cmpneq_sd FORCE_INLINE __m128d _mm_cmpneq_sd(__m128d a, __m128d b) { return _mm_move_sd(a, _mm_cmpneq_pd(a, b)); } // Compare packed double-precision (64-bit) floating-point elements in a and b // for not-greater-than-or-equal, and store the results in dst. // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cmpnge_pd #define _mm_cmpnge_pd(a, b) _mm_cmplt_pd(a, b) // Compare the lower double-precision (64-bit) floating-point elements in a and // b for not-greater-than-or-equal, store the result in the lower element of // dst, and copy the upper element from a to the upper element of dst. // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cmpnge_sd #define _mm_cmpnge_sd(a, b) _mm_cmplt_sd(a, b) // Compare packed double-precision (64-bit) floating-point elements in a and b // for not-greater-than, and store the results in dst. // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_cmpngt_pd #define _mm_cmpngt_pd(a, b) _mm_cmple_pd(a, b) // Compare the lower double-precision (64-bit) floating-point elements in a and // b for not-greater-than, store the result in the lower element of dst, and // copy the upper element from a to the upper element of dst. // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cmpngt_sd #define _mm_cmpngt_sd(a, b) _mm_cmple_sd(a, b) // Compare packed double-precision (64-bit) floating-point elements in a and b // for not-less-than-or-equal, and store the results in dst. // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cmpnle_pd #define _mm_cmpnle_pd(a, b) _mm_cmpgt_pd(a, b) // Compare the lower double-precision (64-bit) floating-point elements in a and // b for not-less-than-or-equal, store the result in the lower element of dst, // and copy the upper element from a to the upper element of dst. // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cmpnle_sd #define _mm_cmpnle_sd(a, b) _mm_cmpgt_sd(a, b) // Compare packed double-precision (64-bit) floating-point elements in a and b // for not-less-than, and store the results in dst. // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cmpnlt_pd #define _mm_cmpnlt_pd(a, b) _mm_cmpge_pd(a, b) // Compare the lower double-precision (64-bit) floating-point elements in a and // b for not-less-than, store the result in the lower element of dst, and copy // the upper element from a to the upper element of dst. // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cmpnlt_sd #define _mm_cmpnlt_sd(a, b) _mm_cmpge_sd(a, b) // Compare packed double-precision (64-bit) floating-point elements in a and b // to see if neither is NaN, and store the results in dst. // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cmpord_pd FORCE_INLINE __m128d _mm_cmpord_pd(__m128d a, __m128d b) { #if defined(__aarch64__) // Excluding NaNs, any two floating point numbers can be compared. uint64x2_t not_nan_a = vceqq_f64(vreinterpretq_f64_m128d(a), vreinterpretq_f64_m128d(a)); uint64x2_t not_nan_b = vceqq_f64(vreinterpretq_f64_m128d(b), vreinterpretq_f64_m128d(b)); return vreinterpretq_m128d_u64(vandq_u64(not_nan_a, not_nan_b)); #else uint64_t a0 = (uint64_t) vget_low_u64(vreinterpretq_u64_m128d(a)); uint64_t a1 = (uint64_t) vget_high_u64(vreinterpretq_u64_m128d(a)); uint64_t b0 = (uint64_t) vget_low_u64(vreinterpretq_u64_m128d(b)); uint64_t b1 = (uint64_t) vget_high_u64(vreinterpretq_u64_m128d(b)); uint64_t d[2]; d[0] = ((*(double *) &a0) == (*(double *) &a0) && (*(double *) &b0) == (*(double *) &b0)) ? ~UINT64_C(0) : UINT64_C(0); d[1] = ((*(double *) &a1) == (*(double *) &a1) && (*(double *) &b1) == (*(double *) &b1)) ? ~UINT64_C(0) : UINT64_C(0); return vreinterpretq_m128d_u64(vld1q_u64(d)); #endif } // Compare the lower double-precision (64-bit) floating-point elements in a and // b to see if neither is NaN, store the result in the lower element of dst, and // copy the upper element from a to the upper element of dst. // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cmpord_sd FORCE_INLINE __m128d _mm_cmpord_sd(__m128d a, __m128d b) { #if defined(__aarch64__) return _mm_move_sd(a, _mm_cmpord_pd(a, b)); #else uint64_t a0 = (uint64_t) vget_low_u64(vreinterpretq_u64_m128d(a)); uint64_t b0 = (uint64_t) vget_low_u64(vreinterpretq_u64_m128d(b)); uint64_t a1 = (uint64_t) vget_high_u64(vreinterpretq_u64_m128d(a)); uint64_t d[2]; d[0] = ((*(double *) &a0) == (*(double *) &a0) && (*(double *) &b0) == (*(double *) &b0)) ? ~UINT64_C(0) : UINT64_C(0); d[1] = a1; return vreinterpretq_m128d_u64(vld1q_u64(d)); #endif } // Compare packed double-precision (64-bit) floating-point elements in a and b // to see if either is NaN, and store the results in dst. // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cmpunord_pd FORCE_INLINE __m128d _mm_cmpunord_pd(__m128d a, __m128d b) { #if defined(__aarch64__) // Two NaNs are not equal in comparison operation. uint64x2_t not_nan_a = vceqq_f64(vreinterpretq_f64_m128d(a), vreinterpretq_f64_m128d(a)); uint64x2_t not_nan_b = vceqq_f64(vreinterpretq_f64_m128d(b), vreinterpretq_f64_m128d(b)); return vreinterpretq_m128d_s32( vmvnq_s32(vreinterpretq_s32_u64(vandq_u64(not_nan_a, not_nan_b)))); #else uint64_t a0 = (uint64_t) vget_low_u64(vreinterpretq_u64_m128d(a)); uint64_t a1 = (uint64_t) vget_high_u64(vreinterpretq_u64_m128d(a)); uint64_t b0 = (uint64_t) vget_low_u64(vreinterpretq_u64_m128d(b)); uint64_t b1 = (uint64_t) vget_high_u64(vreinterpretq_u64_m128d(b)); uint64_t d[2]; d[0] = ((*(double *) &a0) == (*(double *) &a0) && (*(double *) &b0) == (*(double *) &b0)) ? UINT64_C(0) : ~UINT64_C(0); d[1] = ((*(double *) &a1) == (*(double *) &a1) && (*(double *) &b1) == (*(double *) &b1)) ? UINT64_C(0) : ~UINT64_C(0); return vreinterpretq_m128d_u64(vld1q_u64(d)); #endif } // Compare the lower double-precision (64-bit) floating-point elements in a and // b to see if either is NaN, store the result in the lower element of dst, and // copy the upper element from a to the upper element of dst. // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cmpunord_sd FORCE_INLINE __m128d _mm_cmpunord_sd(__m128d a, __m128d b) { #if defined(__aarch64__) return _mm_move_sd(a, _mm_cmpunord_pd(a, b)); #else uint64_t a0 = (uint64_t) vget_low_u64(vreinterpretq_u64_m128d(a)); uint64_t b0 = (uint64_t) vget_low_u64(vreinterpretq_u64_m128d(b)); uint64_t a1 = (uint64_t) vget_high_u64(vreinterpretq_u64_m128d(a)); uint64_t d[2]; d[0] = ((*(double *) &a0) == (*(double *) &a0) && (*(double *) &b0) == (*(double *) &b0)) ? UINT64_C(0) : ~UINT64_C(0); d[1] = a1; return vreinterpretq_m128d_u64(vld1q_u64(d)); #endif } // Compare the lower double-precision (64-bit) floating-point element in a and b // for greater-than-or-equal, and return the boolean result (0 or 1). // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_comige_sd FORCE_INLINE int _mm_comige_sd(__m128d a, __m128d b) { #if defined(__aarch64__) return vgetq_lane_u64(vcgeq_f64(a, b), 0) & 0x1; #else uint64_t a0 = (uint64_t) vget_low_u64(vreinterpretq_u64_m128d(a)); uint64_t b0 = (uint64_t) vget_low_u64(vreinterpretq_u64_m128d(b)); return (*(double *) &a0 >= *(double *) &b0); #endif } // Compare the lower double-precision (64-bit) floating-point element in a and b // for greater-than, and return the boolean result (0 or 1). // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_comigt_sd FORCE_INLINE int _mm_comigt_sd(__m128d a, __m128d b) { #if defined(__aarch64__) return vgetq_lane_u64(vcgtq_f64(a, b), 0) & 0x1; #else uint64_t a0 = (uint64_t) vget_low_u64(vreinterpretq_u64_m128d(a)); uint64_t b0 = (uint64_t) vget_low_u64(vreinterpretq_u64_m128d(b)); return (*(double *) &a0 > *(double *) &b0); #endif } // Compare the lower double-precision (64-bit) floating-point element in a and b // for less-than-or-equal, and return the boolean result (0 or 1). // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_comile_sd FORCE_INLINE int _mm_comile_sd(__m128d a, __m128d b) { #if defined(__aarch64__) return vgetq_lane_u64(vcleq_f64(a, b), 0) & 0x1; #else uint64_t a0 = (uint64_t) vget_low_u64(vreinterpretq_u64_m128d(a)); uint64_t b0 = (uint64_t) vget_low_u64(vreinterpretq_u64_m128d(b)); return (*(double *) &a0 <= *(double *) &b0); #endif } // Compare the lower double-precision (64-bit) floating-point element in a and b // for less-than, and return the boolean result (0 or 1). // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_comilt_sd FORCE_INLINE int _mm_comilt_sd(__m128d a, __m128d b) { #if defined(__aarch64__) return vgetq_lane_u64(vcltq_f64(a, b), 0) & 0x1; #else uint64_t a0 = (uint64_t) vget_low_u64(vreinterpretq_u64_m128d(a)); uint64_t b0 = (uint64_t) vget_low_u64(vreinterpretq_u64_m128d(b)); return (*(double *) &a0 < *(double *) &b0); #endif } // Compare the lower double-precision (64-bit) floating-point element in a and b // for equality, and return the boolean result (0 or 1). // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_comieq_sd FORCE_INLINE int _mm_comieq_sd(__m128d a, __m128d b) { #if defined(__aarch64__) return vgetq_lane_u64(vceqq_f64(a, b), 0) & 0x1; #else uint32x4_t a_not_nan = vceqq_u32(vreinterpretq_u32_m128d(a), vreinterpretq_u32_m128d(a)); uint32x4_t b_not_nan = vceqq_u32(vreinterpretq_u32_m128d(b), vreinterpretq_u32_m128d(b)); uint32x4_t a_and_b_not_nan = vandq_u32(a_not_nan, b_not_nan); uint32x4_t a_eq_b = vceqq_u32(vreinterpretq_u32_m128d(a), vreinterpretq_u32_m128d(b)); uint64x2_t and_results = vandq_u64(vreinterpretq_u64_u32(a_and_b_not_nan), vreinterpretq_u64_u32(a_eq_b)); return !!vgetq_lane_u64(and_results, 0); #endif } // Compare the lower double-precision (64-bit) floating-point element in a and b // for not-equal, and return the boolean result (0 or 1). // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_comineq_sd FORCE_INLINE int _mm_comineq_sd(__m128d a, __m128d b) { #if defined(__aarch64__) return !vgetq_lane_u64(vceqq_f64(a, b), 0); #else // FIXME we should handle NaN condition here uint32x4_t a_eq_b = vceqq_u32(vreinterpretq_u32_m128d(a), vreinterpretq_u32_m128d(b)); return !vgetq_lane_u64(vreinterpretq_u64_u32(a_eq_b), 0); #endif } // Convert packed signed 32-bit integers in a to packed double-precision // (64-bit) floating-point elements, and store the results in dst. // // FOR j := 0 to 1 // i := j*32 // m := j*64 // dst[m+63:m] := Convert_Int32_To_FP64(a[i+31:i]) // ENDFOR // // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtepi32_pd FORCE_INLINE __m128d _mm_cvtepi32_pd(__m128i a) { #if defined(__aarch64__) return vreinterpretq_m128d_f64( vcvtq_f64_s64(vmovl_s32(vget_low_s32(vreinterpretq_s32_m128i(a))))); #else double a0 = (double) vgetq_lane_s32(vreinterpretq_s32_m128i(a), 0); double a1 = (double) vgetq_lane_s32(vreinterpretq_s32_m128i(a), 1); return _mm_set_pd(a1, a0); #endif } // Converts the four signed 32-bit integer values of a to single-precision, // floating-point values // https://msdn.microsoft.com/en-us/library/vstudio/36bwxcx5(v=vs.100).aspx FORCE_INLINE __m128 _mm_cvtepi32_ps(__m128i a) { return vreinterpretq_m128_f32(vcvtq_f32_s32(vreinterpretq_s32_m128i(a))); } // Convert packed double-precision (64-bit) floating-point elements in a to // packed 32-bit integers, and store the results in dst. // // FOR j := 0 to 1 // i := 32*j // k := 64*j // dst[i+31:i] := Convert_FP64_To_Int32(a[k+63:k]) // ENDFOR // // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtpd_epi32 FORCE_INLINE __m128i _mm_cvtpd_epi32(__m128d a) { __m128d rnd = _mm_round_pd(a, _MM_FROUND_CUR_DIRECTION); double d0 = ((double *) &rnd)[0]; double d1 = ((double *) &rnd)[1]; return _mm_set_epi32(0, 0, (int32_t) d1, (int32_t) d0); } // Convert packed double-precision (64-bit) floating-point elements in a to // packed 32-bit integers, and store the results in dst. // // FOR j := 0 to 1 // i := 32*j // k := 64*j // dst[i+31:i] := Convert_FP64_To_Int32(a[k+63:k]) // ENDFOR // // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtpd_pi32 FORCE_INLINE __m64 _mm_cvtpd_pi32(__m128d a) { __m128d rnd = _mm_round_pd(a, _MM_FROUND_CUR_DIRECTION); double d0 = ((double *) &rnd)[0]; double d1 = ((double *) &rnd)[1]; int32_t ALIGN_STRUCT(16) data[2] = {(int32_t) d0, (int32_t) d1}; return vreinterpret_m64_s32(vld1_s32(data)); } // Convert packed double-precision (64-bit) floating-point elements in a to // packed single-precision (32-bit) floating-point elements, and store the // results in dst. // // FOR j := 0 to 1 // i := 32*j // k := 64*j // dst[i+31:i] := Convert_FP64_To_FP32(a[k+64:k]) // ENDFOR // dst[127:64] := 0 // // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtpd_ps FORCE_INLINE __m128 _mm_cvtpd_ps(__m128d a) { #if defined(__aarch64__) float32x2_t tmp = vcvt_f32_f64(vreinterpretq_f64_m128d(a)); return vreinterpretq_m128_f32(vcombine_f32(tmp, vdup_n_f32(0))); #else float a0 = (float) ((double *) &a)[0]; float a1 = (float) ((double *) &a)[1]; return _mm_set_ps(0, 0, a1, a0); #endif } // Convert packed signed 32-bit integers in a to packed double-precision // (64-bit) floating-point elements, and store the results in dst. // // FOR j := 0 to 1 // i := j*32 // m := j*64 // dst[m+63:m] := Convert_Int32_To_FP64(a[i+31:i]) // ENDFOR // // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtpi32_pd FORCE_INLINE __m128d _mm_cvtpi32_pd(__m64 a) { #if defined(__aarch64__) return vreinterpretq_m128d_f64( vcvtq_f64_s64(vmovl_s32(vreinterpret_s32_m64(a)))); #else double a0 = (double) vget_lane_s32(vreinterpret_s32_m64(a), 0); double a1 = (double) vget_lane_s32(vreinterpret_s32_m64(a), 1); return _mm_set_pd(a1, a0); #endif } // Converts the four single-precision, floating-point values of a to signed // 32-bit integer values. // // r0 := (int) a0 // r1 := (int) a1 // r2 := (int) a2 // r3 := (int) a3 // // https://msdn.microsoft.com/en-us/library/vstudio/xdc42k5e(v=vs.100).aspx // *NOTE*. The default rounding mode on SSE is 'round to even', which ARMv7-A // does not support! It is supported on ARMv8-A however. FORCE_INLINE __m128i _mm_cvtps_epi32(__m128 a) { #if defined(__aarch64__) switch (_MM_GET_ROUNDING_MODE()) { case _MM_ROUND_NEAREST: return vreinterpretq_m128i_s32(vcvtnq_s32_f32(a)); case _MM_ROUND_DOWN: return vreinterpretq_m128i_s32(vcvtmq_s32_f32(a)); case _MM_ROUND_UP: return vreinterpretq_m128i_s32(vcvtpq_s32_f32(a)); default: // _MM_ROUND_TOWARD_ZERO return vreinterpretq_m128i_s32(vcvtq_s32_f32(a)); } #else float *f = (float *) &a; switch (_MM_GET_ROUNDING_MODE()) { case _MM_ROUND_NEAREST: { uint32x4_t signmask = vdupq_n_u32(0x80000000); float32x4_t half = vbslq_f32(signmask, vreinterpretq_f32_m128(a), vdupq_n_f32(0.5f)); /* +/- 0.5 */ int32x4_t r_normal = vcvtq_s32_f32(vaddq_f32( vreinterpretq_f32_m128(a), half)); /* round to integer: [a + 0.5]*/ int32x4_t r_trunc = vcvtq_s32_f32( vreinterpretq_f32_m128(a)); /* truncate to integer: [a] */ int32x4_t plusone = vreinterpretq_s32_u32(vshrq_n_u32( vreinterpretq_u32_s32(vnegq_s32(r_trunc)), 31)); /* 1 or 0 */ int32x4_t r_even = vbicq_s32(vaddq_s32(r_trunc, plusone), vdupq_n_s32(1)); /* ([a] + {0,1}) & ~1 */ float32x4_t delta = vsubq_f32( vreinterpretq_f32_m128(a), vcvtq_f32_s32(r_trunc)); /* compute delta: delta = (a - [a]) */ uint32x4_t is_delta_half = vceqq_f32(delta, half); /* delta == +/- 0.5 */ return vreinterpretq_m128i_s32( vbslq_s32(is_delta_half, r_even, r_normal)); } case _MM_ROUND_DOWN: return _mm_set_epi32(floorf(f[3]), floorf(f[2]), floorf(f[1]), floorf(f[0])); case _MM_ROUND_UP: return _mm_set_epi32(ceilf(f[3]), ceilf(f[2]), ceilf(f[1]), ceilf(f[0])); default: // _MM_ROUND_TOWARD_ZERO return _mm_set_epi32((int32_t) f[3], (int32_t) f[2], (int32_t) f[1], (int32_t) f[0]); } #endif } // Convert packed single-precision (32-bit) floating-point elements in a to // packed double-precision (64-bit) floating-point elements, and store the // results in dst. // // FOR j := 0 to 1 // i := 64*j // k := 32*j // dst[i+63:i] := Convert_FP32_To_FP64(a[k+31:k]) // ENDFOR // // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtps_pd FORCE_INLINE __m128d _mm_cvtps_pd(__m128 a) { #if defined(__aarch64__) return vreinterpretq_m128d_f64( vcvt_f64_f32(vget_low_f32(vreinterpretq_f32_m128(a)))); #else double a0 = (double) vgetq_lane_f32(vreinterpretq_f32_m128(a), 0); double a1 = (double) vgetq_lane_f32(vreinterpretq_f32_m128(a), 1); return _mm_set_pd(a1, a0); #endif } // Copy the lower double-precision (64-bit) floating-point element of a to dst. // // dst[63:0] := a[63:0] // // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtsd_f64 FORCE_INLINE double _mm_cvtsd_f64(__m128d a) { #if defined(__aarch64__) return (double) vgetq_lane_f64(vreinterpretq_f64_m128d(a), 0); #else return ((double *) &a)[0]; #endif } // Convert the lower double-precision (64-bit) floating-point element in a to a // 32-bit integer, and store the result in dst. // // dst[31:0] := Convert_FP64_To_Int32(a[63:0]) // // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtsd_si32 FORCE_INLINE int32_t _mm_cvtsd_si32(__m128d a) { #if defined(__aarch64__) return (int32_t) vgetq_lane_f64(vrndiq_f64(vreinterpretq_f64_m128d(a)), 0); #else __m128d rnd = _mm_round_pd(a, _MM_FROUND_CUR_DIRECTION); double ret = ((double *) &rnd)[0]; return (int32_t) ret; #endif } // Convert the lower double-precision (64-bit) floating-point element in a to a // 64-bit integer, and store the result in dst. // // dst[63:0] := Convert_FP64_To_Int64(a[63:0]) // // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtsd_si64 FORCE_INLINE int64_t _mm_cvtsd_si64(__m128d a) { #if defined(__aarch64__) return (int64_t) vgetq_lane_f64(vrndiq_f64(vreinterpretq_f64_m128d(a)), 0); #else __m128d rnd = _mm_round_pd(a, _MM_FROUND_CUR_DIRECTION); double ret = ((double *) &rnd)[0]; return (int64_t) ret; #endif } // Convert the lower double-precision (64-bit) floating-point element in a to a // 64-bit integer, and store the result in dst. // // dst[63:0] := Convert_FP64_To_Int64(a[63:0]) // // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtsd_si64x #define _mm_cvtsd_si64x _mm_cvtsd_si64 // Convert the lower double-precision (64-bit) floating-point element in b to a // single-precision (32-bit) floating-point element, store the result in the // lower element of dst, and copy the upper 3 packed elements from a to the // upper elements of dst. // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtsd_ss FORCE_INLINE __m128 _mm_cvtsd_ss(__m128 a, __m128d b) { #if defined(__aarch64__) return vreinterpretq_m128_f32(vsetq_lane_f32( vget_lane_f32(vcvt_f32_f64(vreinterpretq_f64_m128d(b)), 0), vreinterpretq_f32_m128(a), 0)); #else return vreinterpretq_m128_f32(vsetq_lane_f32((float) ((double *) &b)[0], vreinterpretq_f32_m128(a), 0)); #endif } // Copy the lower 32-bit integer in a to dst. // // dst[31:0] := a[31:0] // // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtsi128_si32 FORCE_INLINE int _mm_cvtsi128_si32(__m128i a) { return vgetq_lane_s32(vreinterpretq_s32_m128i(a), 0); } // Copy the lower 64-bit integer in a to dst. // // dst[63:0] := a[63:0] // // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtsi128_si64 FORCE_INLINE int64_t _mm_cvtsi128_si64(__m128i a) { return vgetq_lane_s64(vreinterpretq_s64_m128i(a), 0); } // Copy the lower 64-bit integer in a to dst. // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtsi128_si64x #define _mm_cvtsi128_si64x(a) _mm_cvtsi128_si64(a) // Convert the signed 32-bit integer b to a double-precision (64-bit) // floating-point element, store the result in the lower element of dst, and // copy the upper element from a to the upper element of dst. // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtsi32_sd FORCE_INLINE __m128d _mm_cvtsi32_sd(__m128d a, int32_t b) { #if defined(__aarch64__) return vreinterpretq_m128d_f64( vsetq_lane_f64((double) b, vreinterpretq_f64_m128d(a), 0)); #else double bf = (double) b; return vreinterpretq_m128d_s64( vsetq_lane_s64(*(int64_t *) &bf, vreinterpretq_s64_m128d(a), 0)); #endif } // Copy the lower 64-bit integer in a to dst. // // dst[63:0] := a[63:0] // // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtsi128_si64x #define _mm_cvtsi128_si64x(a) _mm_cvtsi128_si64(a) // Moves 32-bit integer a to the least significant 32 bits of an __m128 object, // zero extending the upper bits. // // r0 := a // r1 := 0x0 // r2 := 0x0 // r3 := 0x0 // // https://msdn.microsoft.com/en-us/library/ct3539ha%28v=vs.90%29.aspx FORCE_INLINE __m128i _mm_cvtsi32_si128(int a) { return vreinterpretq_m128i_s32(vsetq_lane_s32(a, vdupq_n_s32(0), 0)); } // Convert the signed 64-bit integer b to a double-precision (64-bit) // floating-point element, store the result in the lower element of dst, and // copy the upper element from a to the upper element of dst. // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtsi64_sd FORCE_INLINE __m128d _mm_cvtsi64_sd(__m128d a, int64_t b) { #if defined(__aarch64__) return vreinterpretq_m128d_f64( vsetq_lane_f64((double) b, vreinterpretq_f64_m128d(a), 0)); #else double bf = (double) b; return vreinterpretq_m128d_s64( vsetq_lane_s64(*(int64_t *) &bf, vreinterpretq_s64_m128d(a), 0)); #endif } // Moves 64-bit integer a to the least significant 64 bits of an __m128 object, // zero extending the upper bits. // // r0 := a // r1 := 0x0 FORCE_INLINE __m128i _mm_cvtsi64_si128(int64_t a) { return vreinterpretq_m128i_s64(vsetq_lane_s64(a, vdupq_n_s64(0), 0)); } // Copy 64-bit integer a to the lower element of dst, and zero the upper // element. // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtsi64x_si128 #define _mm_cvtsi64x_si128(a) _mm_cvtsi64_si128(a) // Convert the signed 64-bit integer b to a double-precision (64-bit) // floating-point element, store the result in the lower element of dst, and // copy the upper element from a to the upper element of dst. // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtsi64x_sd #define _mm_cvtsi64x_sd(a, b) _mm_cvtsi64_sd(a, b) // Convert the lower single-precision (32-bit) floating-point element in b to a // double-precision (64-bit) floating-point element, store the result in the // lower element of dst, and copy the upper element from a to the upper element // of dst. // // dst[63:0] := Convert_FP32_To_FP64(b[31:0]) // dst[127:64] := a[127:64] // // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtss_sd FORCE_INLINE __m128d _mm_cvtss_sd(__m128d a, __m128 b) { double d = (double) vgetq_lane_f32(vreinterpretq_f32_m128(b), 0); #if defined(__aarch64__) return vreinterpretq_m128d_f64( vsetq_lane_f64(d, vreinterpretq_f64_m128d(a), 0)); #else return vreinterpretq_m128d_s64( vsetq_lane_s64(*(int64_t *) &d, vreinterpretq_s64_m128d(a), 0)); #endif } // Convert packed double-precision (64-bit) floating-point elements in a to // packed 32-bit integers with truncation, and store the results in dst. // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvttpd_epi32 FORCE_INLINE __m128i _mm_cvttpd_epi32(__m128d a) { double a0 = ((double *) &a)[0]; double a1 = ((double *) &a)[1]; return _mm_set_epi32(0, 0, (int32_t) a1, (int32_t) a0); } // Convert packed double-precision (64-bit) floating-point elements in a to // packed 32-bit integers with truncation, and store the results in dst. // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvttpd_pi32 FORCE_INLINE __m64 _mm_cvttpd_pi32(__m128d a) { double a0 = ((double *) &a)[0]; double a1 = ((double *) &a)[1]; int32_t ALIGN_STRUCT(16) data[2] = {(int32_t) a0, (int32_t) a1}; return vreinterpret_m64_s32(vld1_s32(data)); } // Converts the four single-precision, floating-point values of a to signed // 32-bit integer values using truncate. // https://msdn.microsoft.com/en-us/library/vstudio/1h005y6x(v=vs.100).aspx FORCE_INLINE __m128i _mm_cvttps_epi32(__m128 a) { return vreinterpretq_m128i_s32(vcvtq_s32_f32(vreinterpretq_f32_m128(a))); } // Convert the lower double-precision (64-bit) floating-point element in a to a // 32-bit integer with truncation, and store the result in dst. // // dst[63:0] := Convert_FP64_To_Int32_Truncate(a[63:0]) // // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvttsd_si32 FORCE_INLINE int32_t _mm_cvttsd_si32(__m128d a) { double ret = *((double *) &a); return (int32_t) ret; } // Convert the lower double-precision (64-bit) floating-point element in a to a // 64-bit integer with truncation, and store the result in dst. // // dst[63:0] := Convert_FP64_To_Int64_Truncate(a[63:0]) // // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvttsd_si64 FORCE_INLINE int64_t _mm_cvttsd_si64(__m128d a) { #if defined(__aarch64__) return vgetq_lane_s64(vcvtq_s64_f64(vreinterpretq_f64_m128d(a)), 0); #else double ret = *((double *) &a); return (int64_t) ret; #endif } // Convert the lower double-precision (64-bit) floating-point element in a to a // 64-bit integer with truncation, and store the result in dst. // // dst[63:0] := Convert_FP64_To_Int64_Truncate(a[63:0]) // // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvttsd_si64x #define _mm_cvttsd_si64x(a) _mm_cvttsd_si64(a) // Divide packed double-precision (64-bit) floating-point elements in a by // packed elements in b, and store the results in dst. // // FOR j := 0 to 1 // i := 64*j // dst[i+63:i] := a[i+63:i] / b[i+63:i] // ENDFOR // // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_div_pd FORCE_INLINE __m128d _mm_div_pd(__m128d a, __m128d b) { #if defined(__aarch64__) return vreinterpretq_m128d_f64( vdivq_f64(vreinterpretq_f64_m128d(a), vreinterpretq_f64_m128d(b))); #else double *da = (double *) &a; double *db = (double *) &b; double c[2]; c[0] = da[0] / db[0]; c[1] = da[1] / db[1]; return vld1q_f32((float32_t *) c); #endif } // Divide the lower double-precision (64-bit) floating-point element in a by the // lower double-precision (64-bit) floating-point element in b, store the result // in the lower element of dst, and copy the upper element from a to the upper // element of dst. // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_div_sd FORCE_INLINE __m128d _mm_div_sd(__m128d a, __m128d b) { #if defined(__aarch64__) float64x2_t tmp = vdivq_f64(vreinterpretq_f64_m128d(a), vreinterpretq_f64_m128d(b)); return vreinterpretq_m128d_f64( vsetq_lane_f64(vgetq_lane_f64(vreinterpretq_f64_m128d(a), 1), tmp, 1)); #else return _mm_move_sd(a, _mm_div_pd(a, b)); #endif } // Extracts the selected signed or unsigned 16-bit integer from a and zero // extends. // https://msdn.microsoft.com/en-us/library/6dceta0c(v=vs.100).aspx // FORCE_INLINE int _mm_extract_epi16(__m128i a, __constrange(0,8) int imm) #define _mm_extract_epi16(a, imm) \ vgetq_lane_u16(vreinterpretq_u16_m128i(a), (imm)) // Inserts the least significant 16 bits of b into the selected 16-bit integer // of a. // https://msdn.microsoft.com/en-us/library/kaze8hz1%28v=vs.100%29.aspx // FORCE_INLINE __m128i _mm_insert_epi16(__m128i a, int b, // __constrange(0,8) int imm) #define _mm_insert_epi16(a, b, imm) \ __extension__({ \ vreinterpretq_m128i_s16( \ vsetq_lane_s16((b), vreinterpretq_s16_m128i(a), (imm))); \ }) // Loads two double-precision from 16-byte aligned memory, floating-point // values. // // dst[127:0] := MEM[mem_addr+127:mem_addr] // // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_load_pd FORCE_INLINE __m128d _mm_load_pd(const double *p) { #if defined(__aarch64__) return vreinterpretq_m128d_f64(vld1q_f64(p)); #else const float *fp = (const float *) p; float ALIGN_STRUCT(16) data[4] = {fp[0], fp[1], fp[2], fp[3]}; return vreinterpretq_m128d_f32(vld1q_f32(data)); #endif } // Load a double-precision (64-bit) floating-point element from memory into both // elements of dst. // // dst[63:0] := MEM[mem_addr+63:mem_addr] // dst[127:64] := MEM[mem_addr+63:mem_addr] // // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_load_pd1 #define _mm_load_pd1 _mm_load1_pd // Load a double-precision (64-bit) floating-point element from memory into the // lower of dst, and zero the upper element. mem_addr does not need to be // aligned on any particular boundary. // // dst[63:0] := MEM[mem_addr+63:mem_addr] // dst[127:64] := 0 // // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_load_sd FORCE_INLINE __m128d _mm_load_sd(const double *p) { #if defined(__aarch64__) return vreinterpretq_m128d_f64(vsetq_lane_f64(*p, vdupq_n_f64(0), 0)); #else const float *fp = (const float *) p; float ALIGN_STRUCT(16) data[4] = {fp[0], fp[1], 0, 0}; return vreinterpretq_m128d_f32(vld1q_f32(data)); #endif } // Loads 128-bit value. : // https://msdn.microsoft.com/en-us/library/atzzad1h(v=vs.80).aspx FORCE_INLINE __m128i _mm_load_si128(const __m128i *p) { return vreinterpretq_m128i_s32(vld1q_s32((const int32_t *) p)); } // Load a double-precision (64-bit) floating-point element from memory into both // elements of dst. // // dst[63:0] := MEM[mem_addr+63:mem_addr] // dst[127:64] := MEM[mem_addr+63:mem_addr] // // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_load1_pd FORCE_INLINE __m128d _mm_load1_pd(const double *p) { #if defined(__aarch64__) return vreinterpretq_m128d_f64(vld1q_dup_f64(p)); #else return vreinterpretq_m128d_s64(vdupq_n_s64(*(const int64_t *) p)); #endif } // Load a double-precision (64-bit) floating-point element from memory into the // upper element of dst, and copy the lower element from a to dst. mem_addr does // not need to be aligned on any particular boundary. // // dst[63:0] := a[63:0] // dst[127:64] := MEM[mem_addr+63:mem_addr] // // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_loadh_pd FORCE_INLINE __m128d _mm_loadh_pd(__m128d a, const double *p) { #if defined(__aarch64__) return vreinterpretq_m128d_f64( vcombine_f64(vget_low_f64(vreinterpretq_f64_m128d(a)), vld1_f64(p))); #else return vreinterpretq_m128d_f32(vcombine_f32( vget_low_f32(vreinterpretq_f32_m128d(a)), vld1_f32((const float *) p))); #endif } // Load 64-bit integer from memory into the first element of dst. // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_loadl_epi64 FORCE_INLINE __m128i _mm_loadl_epi64(__m128i const *p) { /* Load the lower 64 bits of the value pointed to by p into the * lower 64 bits of the result, zeroing the upper 64 bits of the result. */ return vreinterpretq_m128i_s32( vcombine_s32(vld1_s32((int32_t const *) p), vcreate_s32(0))); } // Load a double-precision (64-bit) floating-point element from memory into the // lower element of dst, and copy the upper element from a to dst. mem_addr does // not need to be aligned on any particular boundary. // // dst[63:0] := MEM[mem_addr+63:mem_addr] // dst[127:64] := a[127:64] // // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_loadl_pd FORCE_INLINE __m128d _mm_loadl_pd(__m128d a, const double *p) { #if defined(__aarch64__) return vreinterpretq_m128d_f64( vcombine_f64(vld1_f64(p), vget_high_f64(vreinterpretq_f64_m128d(a)))); #else return vreinterpretq_m128d_f32( vcombine_f32(vld1_f32((const float *) p), vget_high_f32(vreinterpretq_f32_m128d(a)))); #endif } // Load 2 double-precision (64-bit) floating-point elements from memory into dst // in reverse order. mem_addr must be aligned on a 16-byte boundary or a // general-protection exception may be generated. // // dst[63:0] := MEM[mem_addr+127:mem_addr+64] // dst[127:64] := MEM[mem_addr+63:mem_addr] // // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_loadr_pd FORCE_INLINE __m128d _mm_loadr_pd(const double *p) { #if defined(__aarch64__) float64x2_t v = vld1q_f64(p); return vreinterpretq_m128d_f64(vextq_f64(v, v, 1)); #else int64x2_t v = vld1q_s64((const int64_t *) p); return vreinterpretq_m128d_s64(vextq_s64(v, v, 1)); #endif } // Loads two double-precision from unaligned memory, floating-point values. // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_loadu_pd FORCE_INLINE __m128d _mm_loadu_pd(const double *p) { return _mm_load_pd(p); } // Loads 128-bit value. : // https://msdn.microsoft.com/zh-cn/library/f4k12ae8(v=vs.90).aspx FORCE_INLINE __m128i _mm_loadu_si128(const __m128i *p) { return vreinterpretq_m128i_s32(vld1q_s32((const int32_t *) p)); } // Load unaligned 32-bit integer from memory into the first element of dst. // // dst[31:0] := MEM[mem_addr+31:mem_addr] // dst[MAX:32] := 0 // // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_loadu_si32 FORCE_INLINE __m128i _mm_loadu_si32(const void *p) { return vreinterpretq_m128i_s32( vsetq_lane_s32(*(const int32_t *) p, vdupq_n_s32(0), 0)); } // Multiplies the 8 signed 16-bit integers from a by the 8 signed 16-bit // integers from b. // // r0 := (a0 * b0) + (a1 * b1) // r1 := (a2 * b2) + (a3 * b3) // r2 := (a4 * b4) + (a5 * b5) // r3 := (a6 * b6) + (a7 * b7) // https://msdn.microsoft.com/en-us/library/yht36sa6(v=vs.90).aspx FORCE_INLINE __m128i _mm_madd_epi16(__m128i a, __m128i b) { int32x4_t low = vmull_s16(vget_low_s16(vreinterpretq_s16_m128i(a)), vget_low_s16(vreinterpretq_s16_m128i(b))); int32x4_t high = vmull_s16(vget_high_s16(vreinterpretq_s16_m128i(a)), vget_high_s16(vreinterpretq_s16_m128i(b))); int32x2_t low_sum = vpadd_s32(vget_low_s32(low), vget_high_s32(low)); int32x2_t high_sum = vpadd_s32(vget_low_s32(high), vget_high_s32(high)); return vreinterpretq_m128i_s32(vcombine_s32(low_sum, high_sum)); } // Conditionally store 8-bit integer elements from a into memory using mask // (elements are not stored when the highest bit is not set in the corresponding // element) and a non-temporal memory hint. mem_addr does not need to be aligned // on any particular boundary. // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskmoveu_si128 FORCE_INLINE void _mm_maskmoveu_si128(__m128i a, __m128i mask, char *mem_addr) { int8x16_t shr_mask = vshrq_n_s8(vreinterpretq_s8_m128i(mask), 7); __m128 b = _mm_load_ps((const float *) mem_addr); int8x16_t masked = vbslq_s8(vreinterpretq_u8_s8(shr_mask), vreinterpretq_s8_m128i(a), vreinterpretq_s8_m128(b)); vst1q_s8((int8_t *) mem_addr, masked); } // Computes the pairwise maxima of the 8 signed 16-bit integers from a and the 8 // signed 16-bit integers from b. // https://msdn.microsoft.com/en-us/LIBRary/3x060h7c(v=vs.100).aspx FORCE_INLINE __m128i _mm_max_epi16(__m128i a, __m128i b) { return vreinterpretq_m128i_s16( vmaxq_s16(vreinterpretq_s16_m128i(a), vreinterpretq_s16_m128i(b))); } // Computes the pairwise maxima of the 16 unsigned 8-bit integers from a and the // 16 unsigned 8-bit integers from b. // https://msdn.microsoft.com/en-us/library/st6634za(v=vs.100).aspx FORCE_INLINE __m128i _mm_max_epu8(__m128i a, __m128i b) { return vreinterpretq_m128i_u8( vmaxq_u8(vreinterpretq_u8_m128i(a), vreinterpretq_u8_m128i(b))); } // Compare packed double-precision (64-bit) floating-point elements in a and b, // and store packed maximum values in dst. // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_max_pd FORCE_INLINE __m128d _mm_max_pd(__m128d a, __m128d b) { #if defined(__aarch64__) return vreinterpretq_m128d_f64( vmaxq_f64(vreinterpretq_f64_m128d(a), vreinterpretq_f64_m128d(b))); #else uint64_t a0 = (uint64_t) vget_low_u64(vreinterpretq_u64_m128d(a)); uint64_t a1 = (uint64_t) vget_high_u64(vreinterpretq_u64_m128d(a)); uint64_t b0 = (uint64_t) vget_low_u64(vreinterpretq_u64_m128d(b)); uint64_t b1 = (uint64_t) vget_high_u64(vreinterpretq_u64_m128d(b)); uint64_t d[2]; d[0] = (*(double *) &a0) > (*(double *) &b0) ? a0 : b0; d[1] = (*(double *) &a1) > (*(double *) &b1) ? a1 : b1; return vreinterpretq_m128d_u64(vld1q_u64(d)); #endif } // Compare the lower double-precision (64-bit) floating-point elements in a and // b, store the maximum value in the lower element of dst, and copy the upper // element from a to the upper element of dst. // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_max_sd FORCE_INLINE __m128d _mm_max_sd(__m128d a, __m128d b) { #if defined(__aarch64__) return _mm_move_sd(a, _mm_max_pd(a, b)); #else double *da = (double *) &a; double *db = (double *) &b; double c[2] = {fmax(da[0], db[0]), da[1]}; return vld1q_f32((float32_t *) c); #endif } // Computes the pairwise minima of the 8 signed 16-bit integers from a and the 8 // signed 16-bit integers from b. // https://msdn.microsoft.com/en-us/library/vstudio/6te997ew(v=vs.100).aspx FORCE_INLINE __m128i _mm_min_epi16(__m128i a, __m128i b) { return vreinterpretq_m128i_s16( vminq_s16(vreinterpretq_s16_m128i(a), vreinterpretq_s16_m128i(b))); } // Computes the pairwise minima of the 16 unsigned 8-bit integers from a and the // 16 unsigned 8-bit integers from b. // https://msdn.microsoft.com/ko-kr/library/17k8cf58(v=vs.100).aspxx FORCE_INLINE __m128i _mm_min_epu8(__m128i a, __m128i b) { return vreinterpretq_m128i_u8( vminq_u8(vreinterpretq_u8_m128i(a), vreinterpretq_u8_m128i(b))); } // Compare packed double-precision (64-bit) floating-point elements in a and b, // and store packed minimum values in dst. // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_min_pd FORCE_INLINE __m128d _mm_min_pd(__m128d a, __m128d b) { #if defined(__aarch64__) return vreinterpretq_m128d_f64( vminq_f64(vreinterpretq_f64_m128d(a), vreinterpretq_f64_m128d(b))); #else uint64_t a0 = (uint64_t) vget_low_u64(vreinterpretq_u64_m128d(a)); uint64_t a1 = (uint64_t) vget_high_u64(vreinterpretq_u64_m128d(a)); uint64_t b0 = (uint64_t) vget_low_u64(vreinterpretq_u64_m128d(b)); uint64_t b1 = (uint64_t) vget_high_u64(vreinterpretq_u64_m128d(b)); uint64_t d[2]; d[0] = (*(double *) &a0) < (*(double *) &b0) ? a0 : b0; d[1] = (*(double *) &a1) < (*(double *) &b1) ? a1 : b1; return vreinterpretq_m128d_u64(vld1q_u64(d)); #endif } // Compare the lower double-precision (64-bit) floating-point elements in a and // b, store the minimum value in the lower element of dst, and copy the upper // element from a to the upper element of dst. // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_min_sd FORCE_INLINE __m128d _mm_min_sd(__m128d a, __m128d b) { #if defined(__aarch64__) return _mm_move_sd(a, _mm_min_pd(a, b)); #else double *da = (double *) &a; double *db = (double *) &b; double c[2] = {fmin(da[0], db[0]), da[1]}; return vld1q_f32((float32_t *) c); #endif } // Copy the lower 64-bit integer in a to the lower element of dst, and zero the // upper element. // // dst[63:0] := a[63:0] // dst[127:64] := 0 // // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_move_epi64 FORCE_INLINE __m128i _mm_move_epi64(__m128i a) { return vreinterpretq_m128i_s64( vsetq_lane_s64(0, vreinterpretq_s64_m128i(a), 1)); } // Move the lower double-precision (64-bit) floating-point element from b to the // lower element of dst, and copy the upper element from a to the upper element // of dst. // // dst[63:0] := b[63:0] // dst[127:64] := a[127:64] // // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_move_sd FORCE_INLINE __m128d _mm_move_sd(__m128d a, __m128d b) { return vreinterpretq_m128d_f32( vcombine_f32(vget_low_f32(vreinterpretq_f32_m128d(b)), vget_high_f32(vreinterpretq_f32_m128d(a)))); } // NEON does not provide a version of this function. // Creates a 16-bit mask from the most significant bits of the 16 signed or // unsigned 8-bit integers in a and zero extends the upper bits. // https://msdn.microsoft.com/en-us/library/vstudio/s090c8fk(v=vs.100).aspx FORCE_INLINE int _mm_movemask_epi8(__m128i a) { // Use increasingly wide shifts+adds to collect the sign bits // together. // Since the widening shifts would be rather confusing to follow in little // endian, everything will be illustrated in big endian order instead. This // has a different result - the bits would actually be reversed on a big // endian machine. // Starting input (only half the elements are shown): // 89 ff 1d c0 00 10 99 33 uint8x16_t input = vreinterpretq_u8_m128i(a); // Shift out everything but the sign bits with an unsigned shift right. // // Bytes of the vector:: // 89 ff 1d c0 00 10 99 33 // \ \ \ \ \ \ \ \ high_bits = (uint16x4_t)(input >> 7) // | | | | | | | | // 01 01 00 01 00 00 01 00 // // Bits of first important lane(s): // 10001001 (89) // \______ // | // 00000001 (01) uint16x8_t high_bits = vreinterpretq_u16_u8(vshrq_n_u8(input, 7)); // Merge the even lanes together with a 16-bit unsigned shift right + add. // 'xx' represents garbage data which will be ignored in the final result. // In the important bytes, the add functions like a binary OR. // // 01 01 00 01 00 00 01 00 // \_ | \_ | \_ | \_ | paired16 = (uint32x4_t)(input + (input >> 7)) // \| \| \| \| // xx 03 xx 01 xx 00 xx 02 // // 00000001 00000001 (01 01) // \_______ | // \| // xxxxxxxx xxxxxx11 (xx 03) uint32x4_t paired16 = vreinterpretq_u32_u16(vsraq_n_u16(high_bits, high_bits, 7)); // Repeat with a wider 32-bit shift + add. // xx 03 xx 01 xx 00 xx 02 // \____ | \____ | paired32 = (uint64x1_t)(paired16 + (paired16 >> // 14)) // \| \| // xx xx xx 0d xx xx xx 02 // // 00000011 00000001 (03 01) // \\_____ || // '----.\|| // xxxxxxxx xxxx1101 (xx 0d) uint64x2_t paired32 = vreinterpretq_u64_u32(vsraq_n_u32(paired16, paired16, 14)); // Last, an even wider 64-bit shift + add to get our result in the low 8 bit // lanes. xx xx xx 0d xx xx xx 02 // \_________ | paired64 = (uint8x8_t)(paired32 + (paired32 >> // 28)) // \| // xx xx xx xx xx xx xx d2 // // 00001101 00000010 (0d 02) // \ \___ | | // '---. \| | // xxxxxxxx 11010010 (xx d2) uint8x16_t paired64 = vreinterpretq_u8_u64(vsraq_n_u64(paired32, paired32, 28)); // Extract the low 8 bits from each 64-bit lane with 2 8-bit extracts. // xx xx xx xx xx xx xx d2 // || return paired64[0] // d2 // Note: Little endian would return the correct value 4b (01001011) instead. return vgetq_lane_u8(paired64, 0) | ((int) vgetq_lane_u8(paired64, 8) << 8); } // Set each bit of mask dst based on the most significant bit of the // corresponding packed double-precision (64-bit) floating-point element in a. // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_movemask_pd FORCE_INLINE int _mm_movemask_pd(__m128d a) { uint64x2_t input = vreinterpretq_u64_m128d(a); uint64x2_t high_bits = vshrq_n_u64(input, 63); return vgetq_lane_u64(high_bits, 0) | (vgetq_lane_u64(high_bits, 1) << 1); } // Copy the lower 64-bit integer in a to dst. // // dst[63:0] := a[63:0] // // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_movepi64_pi64 FORCE_INLINE __m64 _mm_movepi64_pi64(__m128i a) { return vreinterpret_m64_s64(vget_low_s64(vreinterpretq_s64_m128i(a))); } // Copy the 64-bit integer a to the lower element of dst, and zero the upper // element. // // dst[63:0] := a[63:0] // dst[127:64] := 0 // // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_movpi64_epi64 FORCE_INLINE __m128i _mm_movpi64_epi64(__m64 a) { return vreinterpretq_m128i_s64( vcombine_s64(vreinterpret_s64_m64(a), vdup_n_s64(0))); } // Multiply the low unsigned 32-bit integers from each packed 64-bit element in // a and b, and store the unsigned 64-bit results in dst. // // r0 := (a0 & 0xFFFFFFFF) * (b0 & 0xFFFFFFFF) // r1 := (a2 & 0xFFFFFFFF) * (b2 & 0xFFFFFFFF) FORCE_INLINE __m128i _mm_mul_epu32(__m128i a, __m128i b) { // vmull_u32 upcasts instead of masking, so we downcast. uint32x2_t a_lo = vmovn_u64(vreinterpretq_u64_m128i(a)); uint32x2_t b_lo = vmovn_u64(vreinterpretq_u64_m128i(b)); return vreinterpretq_m128i_u64(vmull_u32(a_lo, b_lo)); } // Multiply packed double-precision (64-bit) floating-point elements in a and b, // and store the results in dst. // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mul_pd FORCE_INLINE __m128d _mm_mul_pd(__m128d a, __m128d b) { #if defined(__aarch64__) return vreinterpretq_m128d_f64( vmulq_f64(vreinterpretq_f64_m128d(a), vreinterpretq_f64_m128d(b))); #else double *da = (double *) &a; double *db = (double *) &b; double c[2]; c[0] = da[0] * db[0]; c[1] = da[1] * db[1]; return vld1q_f32((float32_t *) c); #endif } // Multiply the lower double-precision (64-bit) floating-point element in a and // b, store the result in the lower element of dst, and copy the upper element // from a to the upper element of dst. // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_mul_sd FORCE_INLINE __m128d _mm_mul_sd(__m128d a, __m128d b) { return _mm_move_sd(a, _mm_mul_pd(a, b)); } // Multiply the low unsigned 32-bit integers from a and b, and store the // unsigned 64-bit result in dst. // // dst[63:0] := a[31:0] * b[31:0] // // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mul_su32 FORCE_INLINE __m64 _mm_mul_su32(__m64 a, __m64 b) { return vreinterpret_m64_u64(vget_low_u64( vmull_u32(vreinterpret_u32_m64(a), vreinterpret_u32_m64(b)))); } // Multiplies the 8 signed 16-bit integers from a by the 8 signed 16-bit // integers from b. // // r0 := (a0 * b0)[31:16] // r1 := (a1 * b1)[31:16] // ... // r7 := (a7 * b7)[31:16] // // https://msdn.microsoft.com/en-us/library/vstudio/59hddw1d(v=vs.100).aspx FORCE_INLINE __m128i _mm_mulhi_epi16(__m128i a, __m128i b) { /* FIXME: issue with large values because of result saturation */ // int16x8_t ret = vqdmulhq_s16(vreinterpretq_s16_m128i(a), // vreinterpretq_s16_m128i(b)); /* =2*a*b */ return // vreinterpretq_m128i_s16(vshrq_n_s16(ret, 1)); int16x4_t a3210 = vget_low_s16(vreinterpretq_s16_m128i(a)); int16x4_t b3210 = vget_low_s16(vreinterpretq_s16_m128i(b)); int32x4_t ab3210 = vmull_s16(a3210, b3210); /* 3333222211110000 */ int16x4_t a7654 = vget_high_s16(vreinterpretq_s16_m128i(a)); int16x4_t b7654 = vget_high_s16(vreinterpretq_s16_m128i(b)); int32x4_t ab7654 = vmull_s16(a7654, b7654); /* 7777666655554444 */ uint16x8x2_t r = vuzpq_u16(vreinterpretq_u16_s32(ab3210), vreinterpretq_u16_s32(ab7654)); return vreinterpretq_m128i_u16(r.val[1]); } // Multiply the packed unsigned 16-bit integers in a and b, producing // intermediate 32-bit integers, and store the high 16 bits of the intermediate // integers in dst. // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mulhi_epu16 FORCE_INLINE __m128i _mm_mulhi_epu16(__m128i a, __m128i b) { uint16x4_t a3210 = vget_low_u16(vreinterpretq_u16_m128i(a)); uint16x4_t b3210 = vget_low_u16(vreinterpretq_u16_m128i(b)); uint32x4_t ab3210 = vmull_u16(a3210, b3210); #if defined(__aarch64__) uint32x4_t ab7654 = vmull_high_u16(vreinterpretq_u16_m128i(a), vreinterpretq_u16_m128i(b)); uint16x8_t r = vuzp2q_u16(vreinterpretq_u16_u32(ab3210), vreinterpretq_u16_u32(ab7654)); return vreinterpretq_m128i_u16(r); #else uint16x4_t a7654 = vget_high_u16(vreinterpretq_u16_m128i(a)); uint16x4_t b7654 = vget_high_u16(vreinterpretq_u16_m128i(b)); uint32x4_t ab7654 = vmull_u16(a7654, b7654); uint16x8x2_t r = vuzpq_u16(vreinterpretq_u16_u32(ab3210), vreinterpretq_u16_u32(ab7654)); return vreinterpretq_m128i_u16(r.val[1]); #endif } // Multiplies the 8 signed or unsigned 16-bit integers from a by the 8 signed or // unsigned 16-bit integers from b. // // r0 := (a0 * b0)[15:0] // r1 := (a1 * b1)[15:0] // ... // r7 := (a7 * b7)[15:0] // // https://msdn.microsoft.com/en-us/library/vstudio/9ks1472s(v=vs.100).aspx FORCE_INLINE __m128i _mm_mullo_epi16(__m128i a, __m128i b) { return vreinterpretq_m128i_s16( vmulq_s16(vreinterpretq_s16_m128i(a), vreinterpretq_s16_m128i(b))); } // Compute the bitwise OR of packed double-precision (64-bit) floating-point // elements in a and b, and store the results in dst. // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_or_pd FORCE_INLINE __m128d _mm_or_pd(__m128d a, __m128d b) { return vreinterpretq_m128d_s64( vorrq_s64(vreinterpretq_s64_m128d(a), vreinterpretq_s64_m128d(b))); } // Computes the bitwise OR of the 128-bit value in a and the 128-bit value in b. // // r := a | b // // https://msdn.microsoft.com/en-us/library/vstudio/ew8ty0db(v=vs.100).aspx FORCE_INLINE __m128i _mm_or_si128(__m128i a, __m128i b) { return vreinterpretq_m128i_s32( vorrq_s32(vreinterpretq_s32_m128i(a), vreinterpretq_s32_m128i(b))); } // Packs the 16 signed 16-bit integers from a and b into 8-bit integers and // saturates. // https://msdn.microsoft.com/en-us/library/k4y4f7w5%28v=vs.90%29.aspx FORCE_INLINE __m128i _mm_packs_epi16(__m128i a, __m128i b) { return vreinterpretq_m128i_s8( vcombine_s8(vqmovn_s16(vreinterpretq_s16_m128i(a)), vqmovn_s16(vreinterpretq_s16_m128i(b)))); } // Packs the 8 signed 32-bit integers from a and b into signed 16-bit integers // and saturates. // // r0 := SignedSaturate(a0) // r1 := SignedSaturate(a1) // r2 := SignedSaturate(a2) // r3 := SignedSaturate(a3) // r4 := SignedSaturate(b0) // r5 := SignedSaturate(b1) // r6 := SignedSaturate(b2) // r7 := SignedSaturate(b3) // // https://msdn.microsoft.com/en-us/library/393t56f9%28v=vs.90%29.aspx FORCE_INLINE __m128i _mm_packs_epi32(__m128i a, __m128i b) { return vreinterpretq_m128i_s16( vcombine_s16(vqmovn_s32(vreinterpretq_s32_m128i(a)), vqmovn_s32(vreinterpretq_s32_m128i(b)))); } // Packs the 16 signed 16 - bit integers from a and b into 8 - bit unsigned // integers and saturates. // // r0 := UnsignedSaturate(a0) // r1 := UnsignedSaturate(a1) // ... // r7 := UnsignedSaturate(a7) // r8 := UnsignedSaturate(b0) // r9 := UnsignedSaturate(b1) // ... // r15 := UnsignedSaturate(b7) // // https://msdn.microsoft.com/en-us/library/07ad1wx4(v=vs.100).aspx FORCE_INLINE __m128i _mm_packus_epi16(const __m128i a, const __m128i b) { return vreinterpretq_m128i_u8( vcombine_u8(vqmovun_s16(vreinterpretq_s16_m128i(a)), vqmovun_s16(vreinterpretq_s16_m128i(b)))); } // Pause the processor. This is typically used in spin-wait loops and depending // on the x86 processor typical values are in the 40-100 cycle range. The // 'yield' instruction isn't a good fit beacuse it's effectively a nop on most // Arm cores. Experience with several databases has shown has shown an 'isb' is // a reasonable approximation. FORCE_INLINE void _mm_pause() { __asm__ __volatile__("isb\n"); } // Compute the absolute differences of packed unsigned 8-bit integers in a and // b, then horizontally sum each consecutive 8 differences to produce two // unsigned 16-bit integers, and pack these unsigned 16-bit integers in the low // 16 bits of 64-bit elements in dst. // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_sad_epu8 FORCE_INLINE __m128i _mm_sad_epu8(__m128i a, __m128i b) { uint16x8_t t = vpaddlq_u8(vabdq_u8((uint8x16_t) a, (uint8x16_t) b)); return vreinterpretq_m128i_u64(vpaddlq_u32(vpaddlq_u16(t))); } // Sets the 8 signed 16-bit integer values. // https://msdn.microsoft.com/en-au/library/3e0fek84(v=vs.90).aspx FORCE_INLINE __m128i _mm_set_epi16(short i7, short i6, short i5, short i4, short i3, short i2, short i1, short i0) { int16_t ALIGN_STRUCT(16) data[8] = {i0, i1, i2, i3, i4, i5, i6, i7}; return vreinterpretq_m128i_s16(vld1q_s16(data)); } // Sets the 4 signed 32-bit integer values. // https://msdn.microsoft.com/en-us/library/vstudio/019beekt(v=vs.100).aspx FORCE_INLINE __m128i _mm_set_epi32(int i3, int i2, int i1, int i0) { int32_t ALIGN_STRUCT(16) data[4] = {i0, i1, i2, i3}; return vreinterpretq_m128i_s32(vld1q_s32(data)); } // Returns the __m128i structure with its two 64-bit integer values // initialized to the values of the two 64-bit integers passed in. // https://msdn.microsoft.com/en-us/library/dk2sdw0h(v=vs.120).aspx FORCE_INLINE __m128i _mm_set_epi64(__m64 i1, __m64 i2) { return _mm_set_epi64x((int64_t) i1, (int64_t) i2); } // Returns the __m128i structure with its two 64-bit integer values // initialized to the values of the two 64-bit integers passed in. // https://msdn.microsoft.com/en-us/library/dk2sdw0h(v=vs.120).aspx FORCE_INLINE __m128i _mm_set_epi64x(int64_t i1, int64_t i2) { return vreinterpretq_m128i_s64( vcombine_s64(vcreate_s64(i2), vcreate_s64(i1))); } // Sets the 16 signed 8-bit integer values. // https://msdn.microsoft.com/en-us/library/x0cx8zd3(v=vs.90).aspx FORCE_INLINE __m128i _mm_set_epi8(signed char b15, signed char b14, signed char b13, signed char b12, signed char b11, signed char b10, signed char b9, signed char b8, signed char b7, signed char b6, signed char b5, signed char b4, signed char b3, signed char b2, signed char b1, signed char b0) { int8_t ALIGN_STRUCT(16) data[16] = {(int8_t) b0, (int8_t) b1, (int8_t) b2, (int8_t) b3, (int8_t) b4, (int8_t) b5, (int8_t) b6, (int8_t) b7, (int8_t) b8, (int8_t) b9, (int8_t) b10, (int8_t) b11, (int8_t) b12, (int8_t) b13, (int8_t) b14, (int8_t) b15}; return (__m128i) vld1q_s8(data); } // Set packed double-precision (64-bit) floating-point elements in dst with the // supplied values. // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_set_pd FORCE_INLINE __m128d _mm_set_pd(double e1, double e0) { double ALIGN_STRUCT(16) data[2] = {e0, e1}; #if defined(__aarch64__) return vreinterpretq_m128d_f64(vld1q_f64((float64_t *) data)); #else return vreinterpretq_m128d_f32(vld1q_f32((float32_t *) data)); #endif } // Broadcast double-precision (64-bit) floating-point value a to all elements of // dst. // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_set_pd1 #define _mm_set_pd1 _mm_set1_pd // Copy double-precision (64-bit) floating-point element a to the lower element // of dst, and zero the upper element. // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_set_sd FORCE_INLINE __m128d _mm_set_sd(double a) { return _mm_set_pd(0, a); } // Sets the 8 signed 16-bit integer values to w. // // r0 := w // r1 := w // ... // r7 := w // // https://msdn.microsoft.com/en-us/library/k0ya3x0e(v=vs.90).aspx FORCE_INLINE __m128i _mm_set1_epi16(short w) { return vreinterpretq_m128i_s16(vdupq_n_s16(w)); } // Sets the 4 signed 32-bit integer values to i. // // r0 := i // r1 := i // r2 := i // r3 := I // // https://msdn.microsoft.com/en-us/library/vstudio/h4xscxat(v=vs.100).aspx FORCE_INLINE __m128i _mm_set1_epi32(int _i) { return vreinterpretq_m128i_s32(vdupq_n_s32(_i)); } // Sets the 2 signed 64-bit integer values to i. // https://docs.microsoft.com/en-us/previous-versions/visualstudio/visual-studio-2010/whtfzhzk(v=vs.100) FORCE_INLINE __m128i _mm_set1_epi64(__m64 _i) { return vreinterpretq_m128i_s64(vdupq_n_s64((int64_t) _i)); } // Sets the 2 signed 64-bit integer values to i. // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_set1_epi64x FORCE_INLINE __m128i _mm_set1_epi64x(int64_t _i) { return vreinterpretq_m128i_s64(vdupq_n_s64(_i)); } // Sets the 16 signed 8-bit integer values to b. // // r0 := b // r1 := b // ... // r15 := b // // https://msdn.microsoft.com/en-us/library/6e14xhyf(v=vs.100).aspx FORCE_INLINE __m128i _mm_set1_epi8(signed char w) { return vreinterpretq_m128i_s8(vdupq_n_s8(w)); } // Broadcast double-precision (64-bit) floating-point value a to all elements of // dst. // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_set1_pd FORCE_INLINE __m128d _mm_set1_pd(double d) { #if defined(__aarch64__) return vreinterpretq_m128d_f64(vdupq_n_f64(d)); #else return vreinterpretq_m128d_s64(vdupq_n_s64(*(int64_t *) &d)); #endif } // Sets the 8 signed 16-bit integer values in reverse order. // // Return Value // r0 := w0 // r1 := w1 // ... // r7 := w7 FORCE_INLINE __m128i _mm_setr_epi16(short w0, short w1, short w2, short w3, short w4, short w5, short w6, short w7) { int16_t ALIGN_STRUCT(16) data[8] = {w0, w1, w2, w3, w4, w5, w6, w7}; return vreinterpretq_m128i_s16(vld1q_s16((int16_t *) data)); } // Sets the 4 signed 32-bit integer values in reverse order // https://technet.microsoft.com/en-us/library/security/27yb3ee5(v=vs.90).aspx FORCE_INLINE __m128i _mm_setr_epi32(int i3, int i2, int i1, int i0) { int32_t ALIGN_STRUCT(16) data[4] = {i3, i2, i1, i0}; return vreinterpretq_m128i_s32(vld1q_s32(data)); } // Set packed 64-bit integers in dst with the supplied values in reverse order. // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_setr_epi64 FORCE_INLINE __m128i _mm_setr_epi64(__m64 e1, __m64 e0) { return vreinterpretq_m128i_s64(vcombine_s64(e1, e0)); } // Sets the 16 signed 8-bit integer values in reverse order. // https://msdn.microsoft.com/en-us/library/2khb9c7k(v=vs.90).aspx FORCE_INLINE __m128i _mm_setr_epi8(signed char b0, signed char b1, signed char b2, signed char b3, signed char b4, signed char b5, signed char b6, signed char b7, signed char b8, signed char b9, signed char b10, signed char b11, signed char b12, signed char b13, signed char b14, signed char b15) { int8_t ALIGN_STRUCT(16) data[16] = {(int8_t) b0, (int8_t) b1, (int8_t) b2, (int8_t) b3, (int8_t) b4, (int8_t) b5, (int8_t) b6, (int8_t) b7, (int8_t) b8, (int8_t) b9, (int8_t) b10, (int8_t) b11, (int8_t) b12, (int8_t) b13, (int8_t) b14, (int8_t) b15}; return (__m128i) vld1q_s8(data); } // Set packed double-precision (64-bit) floating-point elements in dst with the // supplied values in reverse order. // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_setr_pd FORCE_INLINE __m128d _mm_setr_pd(double e1, double e0) { return _mm_set_pd(e0, e1); } // Return vector of type __m128d with all elements set to zero. // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_setzero_pd FORCE_INLINE __m128d _mm_setzero_pd(void) { #if defined(__aarch64__) return vreinterpretq_m128d_f64(vdupq_n_f64(0)); #else return vreinterpretq_m128d_f32(vdupq_n_f32(0)); #endif } // Sets the 128-bit value to zero // https://msdn.microsoft.com/en-us/library/vstudio/ys7dw0kh(v=vs.100).aspx FORCE_INLINE __m128i _mm_setzero_si128(void) { return vreinterpretq_m128i_s32(vdupq_n_s32(0)); } // Shuffles the 4 signed or unsigned 32-bit integers in a as specified by imm. // https://msdn.microsoft.com/en-us/library/56f67xbk%28v=vs.90%29.aspx // FORCE_INLINE __m128i _mm_shuffle_epi32(__m128i a, // __constrange(0,255) int imm) #if __has_builtin(__builtin_shufflevector) #define _mm_shuffle_epi32(a, imm) \ __extension__({ \ int32x4_t _input = vreinterpretq_s32_m128i(a); \ int32x4_t _shuf = __builtin_shufflevector( \ _input, _input, (imm) & (0x3), ((imm) >> 2) & 0x3, \ ((imm) >> 4) & 0x3, ((imm) >> 6) & 0x3); \ vreinterpretq_m128i_s32(_shuf); \ }) #else // generic #define _mm_shuffle_epi32(a, imm) \ __extension__({ \ __m128i ret; \ switch (imm) { \ case _MM_SHUFFLE(1, 0, 3, 2): \ ret = _mm_shuffle_epi_1032((a)); \ break; \ case _MM_SHUFFLE(2, 3, 0, 1): \ ret = _mm_shuffle_epi_2301((a)); \ break; \ case _MM_SHUFFLE(0, 3, 2, 1): \ ret = _mm_shuffle_epi_0321((a)); \ break; \ case _MM_SHUFFLE(2, 1, 0, 3): \ ret = _mm_shuffle_epi_2103((a)); \ break; \ case _MM_SHUFFLE(1, 0, 1, 0): \ ret = _mm_shuffle_epi_1010((a)); \ break; \ case _MM_SHUFFLE(1, 0, 0, 1): \ ret = _mm_shuffle_epi_1001((a)); \ break; \ case _MM_SHUFFLE(0, 1, 0, 1): \ ret = _mm_shuffle_epi_0101((a)); \ break; \ case _MM_SHUFFLE(2, 2, 1, 1): \ ret = _mm_shuffle_epi_2211((a)); \ break; \ case _MM_SHUFFLE(0, 1, 2, 2): \ ret = _mm_shuffle_epi_0122((a)); \ break; \ case _MM_SHUFFLE(3, 3, 3, 2): \ ret = _mm_shuffle_epi_3332((a)); \ break; \ case _MM_SHUFFLE(0, 0, 0, 0): \ ret = _mm_shuffle_epi32_splat((a), 0); \ break; \ case _MM_SHUFFLE(1, 1, 1, 1): \ ret = _mm_shuffle_epi32_splat((a), 1); \ break; \ case _MM_SHUFFLE(2, 2, 2, 2): \ ret = _mm_shuffle_epi32_splat((a), 2); \ break; \ case _MM_SHUFFLE(3, 3, 3, 3): \ ret = _mm_shuffle_epi32_splat((a), 3); \ break; \ default: \ ret = _mm_shuffle_epi32_default((a), (imm)); \ break; \ } \ ret; \ }) #endif // Shuffle double-precision (64-bit) floating-point elements using the control // in imm8, and store the results in dst. // // dst[63:0] := (imm8[0] == 0) ? a[63:0] : a[127:64] // dst[127:64] := (imm8[1] == 0) ? b[63:0] : b[127:64] // // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_shuffle_pd #if __has_builtin(__builtin_shufflevector) #define _mm_shuffle_pd(a, b, imm8) \ vreinterpretq_m128d_s64(__builtin_shufflevector( \ vreinterpretq_s64_m128d(a), vreinterpretq_s64_m128d(b), imm8 & 0x1, \ ((imm8 & 0x2) >> 1) + 2)) #else #define _mm_shuffle_pd(a, b, imm8) \ _mm_castsi128_pd(_mm_set_epi64x( \ vgetq_lane_s64(vreinterpretq_s64_m128d(b), (imm8 & 0x2) >> 1), \ vgetq_lane_s64(vreinterpretq_s64_m128d(a), imm8 & 0x1))) #endif // FORCE_INLINE __m128i _mm_shufflehi_epi16(__m128i a, // __constrange(0,255) int imm) #if __has_builtin(__builtin_shufflevector) #define _mm_shufflehi_epi16(a, imm) \ __extension__({ \ int16x8_t _input = vreinterpretq_s16_m128i(a); \ int16x8_t _shuf = __builtin_shufflevector( \ _input, _input, 0, 1, 2, 3, ((imm) & (0x3)) + 4, \ (((imm) >> 2) & 0x3) + 4, (((imm) >> 4) & 0x3) + 4, \ (((imm) >> 6) & 0x3) + 4); \ vreinterpretq_m128i_s16(_shuf); \ }) #else // generic #define _mm_shufflehi_epi16(a, imm) _mm_shufflehi_epi16_function((a), (imm)) #endif // FORCE_INLINE __m128i _mm_shufflelo_epi16(__m128i a, // __constrange(0,255) int imm) #if __has_builtin(__builtin_shufflevector) #define _mm_shufflelo_epi16(a, imm) \ __extension__({ \ int16x8_t _input = vreinterpretq_s16_m128i(a); \ int16x8_t _shuf = __builtin_shufflevector( \ _input, _input, ((imm) & (0x3)), (((imm) >> 2) & 0x3), \ (((imm) >> 4) & 0x3), (((imm) >> 6) & 0x3), 4, 5, 6, 7); \ vreinterpretq_m128i_s16(_shuf); \ }) #else // generic #define _mm_shufflelo_epi16(a, imm) _mm_shufflelo_epi16_function((a), (imm)) #endif // Shifts the 8 signed or unsigned 16-bit integers in a left by count bits while // shifting in zeros. // // r0 := a0 << count // r1 := a1 << count // ... // r7 := a7 << count // // https://msdn.microsoft.com/en-us/library/c79w388h(v%3dvs.90).aspx FORCE_INLINE __m128i _mm_sll_epi16(__m128i a, __m128i count) { uint64_t c = vreinterpretq_nth_u64_m128i(count, 0); if (unlikely(c > 15)) return _mm_setzero_si128(); int16x8_t vc = vdupq_n_s16((int16_t) c); return vreinterpretq_m128i_s16(vshlq_s16(vreinterpretq_s16_m128i(a), vc)); } // Shifts the 4 signed or unsigned 32-bit integers in a left by count bits while // shifting in zeros. // // r0 := a0 << count // r1 := a1 << count // r2 := a2 << count // r3 := a3 << count // // https://msdn.microsoft.com/en-us/library/6fe5a6s9(v%3dvs.90).aspx FORCE_INLINE __m128i _mm_sll_epi32(__m128i a, __m128i count) { uint64_t c = vreinterpretq_nth_u64_m128i(count, 0); if (unlikely(c > 31)) return _mm_setzero_si128(); int32x4_t vc = vdupq_n_s32((int32_t) c); return vreinterpretq_m128i_s32(vshlq_s32(vreinterpretq_s32_m128i(a), vc)); } // Shifts the 2 signed or unsigned 64-bit integers in a left by count bits while // shifting in zeros. // // r0 := a0 << count // r1 := a1 << count // // https://msdn.microsoft.com/en-us/library/6ta9dffd(v%3dvs.90).aspx FORCE_INLINE __m128i _mm_sll_epi64(__m128i a, __m128i count) { uint64_t c = vreinterpretq_nth_u64_m128i(count, 0); if (unlikely(c > 63)) return _mm_setzero_si128(); int64x2_t vc = vdupq_n_s64((int64_t) c); return vreinterpretq_m128i_s64(vshlq_s64(vreinterpretq_s64_m128i(a), vc)); } // Shifts the 8 signed or unsigned 16-bit integers in a left by count bits while // shifting in zeros. // // r0 := a0 << count // r1 := a1 << count // ... // r7 := a7 << count // // https://msdn.microsoft.com/en-us/library/es73bcsy(v=vs.90).aspx #define _mm_slli_epi16(a, imm) \ __extension__({ \ __m128i ret; \ if (unlikely((imm)) <= 0) { \ ret = a; \ } \ if (unlikely((imm) > 15)) { \ ret = _mm_setzero_si128(); \ } else { \ ret = vreinterpretq_m128i_s16( \ vshlq_n_s16(vreinterpretq_s16_m128i(a), (imm))); \ } \ ret; \ }) // Shifts the 4 signed or unsigned 32-bit integers in a left by count bits while // shifting in zeros. : // https://msdn.microsoft.com/en-us/library/z2k3bbtb%28v=vs.90%29.aspx // FORCE_INLINE __m128i _mm_slli_epi32(__m128i a, __constrange(0,255) int imm) FORCE_INLINE __m128i _mm_slli_epi32(__m128i a, int imm) { if (unlikely(imm <= 0)) /* TODO: add constant range macro: [0, 255] */ return a; if (unlikely(imm > 31)) return _mm_setzero_si128(); return vreinterpretq_m128i_s32( vshlq_s32(vreinterpretq_s32_m128i(a), vdupq_n_s32(imm))); } // Shift packed 64-bit integers in a left by imm8 while shifting in zeros, and // store the results in dst. FORCE_INLINE __m128i _mm_slli_epi64(__m128i a, int imm) { if (unlikely(imm <= 0)) /* TODO: add constant range macro: [0, 255] */ return a; if (unlikely(imm > 63)) return _mm_setzero_si128(); return vreinterpretq_m128i_s64( vshlq_s64(vreinterpretq_s64_m128i(a), vdupq_n_s64(imm))); } // Shifts the 128-bit value in a left by imm bytes while shifting in zeros. imm // must be an immediate. // // r := a << (imm * 8) // // https://msdn.microsoft.com/en-us/library/34d3k2kt(v=vs.100).aspx // FORCE_INLINE __m128i _mm_slli_si128(__m128i a, __constrange(0,255) int imm) #define _mm_slli_si128(a, imm) \ __extension__({ \ __m128i ret; \ if (unlikely((imm) <= 0)) { \ ret = a; \ } \ if (unlikely((imm) > 15)) { \ ret = _mm_setzero_si128(); \ } else { \ ret = vreinterpretq_m128i_s8(vextq_s8( \ vdupq_n_s8(0), vreinterpretq_s8_m128i(a), 16 - (imm))); \ } \ ret; \ }) // Compute the square root of packed double-precision (64-bit) floating-point // elements in a, and store the results in dst. // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_sqrt_pd FORCE_INLINE __m128d _mm_sqrt_pd(__m128d a) { #if defined(__aarch64__) return vreinterpretq_m128d_f64(vsqrtq_f64(vreinterpretq_f64_m128d(a))); #else double a0 = sqrt(((double *) &a)[0]); double a1 = sqrt(((double *) &a)[1]); return _mm_set_pd(a1, a0); #endif } // Compute the square root of the lower double-precision (64-bit) floating-point // element in b, store the result in the lower element of dst, and copy the // upper element from a to the upper element of dst. // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_sqrt_sd FORCE_INLINE __m128d _mm_sqrt_sd(__m128d a, __m128d b) { #if defined(__aarch64__) return _mm_move_sd(a, _mm_sqrt_pd(b)); #else return _mm_set_pd(((double *) &a)[1], sqrt(((double *) &b)[0])); #endif } // Shifts the 8 signed 16-bit integers in a right by count bits while shifting // in the sign bit. // // r0 := a0 >> count // r1 := a1 >> count // ... // r7 := a7 >> count // // https://msdn.microsoft.com/en-us/library/3c9997dk(v%3dvs.90).aspx FORCE_INLINE __m128i _mm_sra_epi16(__m128i a, __m128i count) { int64_t c = (int64_t) vget_low_s64((int64x2_t) count); if (unlikely(c > 15)) return _mm_cmplt_epi16(a, _mm_setzero_si128()); return vreinterpretq_m128i_s16(vshlq_s16((int16x8_t) a, vdupq_n_s16(-c))); } // Shifts the 4 signed 32-bit integers in a right by count bits while shifting // in the sign bit. // // r0 := a0 >> count // r1 := a1 >> count // r2 := a2 >> count // r3 := a3 >> count // // https://msdn.microsoft.com/en-us/library/ce40009e(v%3dvs.100).aspx FORCE_INLINE __m128i _mm_sra_epi32(__m128i a, __m128i count) { int64_t c = (int64_t) vget_low_s64((int64x2_t) count); if (unlikely(c > 31)) return _mm_cmplt_epi32(a, _mm_setzero_si128()); return vreinterpretq_m128i_s32(vshlq_s32((int32x4_t) a, vdupq_n_s32(-c))); } // Shift packed 16-bit integers in a right by imm while shifting in sign // bits, and store the results in dst. // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_srai_epi16 FORCE_INLINE __m128i _mm_srai_epi16(__m128i a, int imm) { const int count = (imm & ~15) ? 15 : imm; return (__m128i) vshlq_s16((int16x8_t) a, vdupq_n_s16(-count)); } // Shift packed 32-bit integers in a right by imm8 while shifting in sign bits, // and store the results in dst. // // FOR j := 0 to 3 // i := j*32 // IF imm8[7:0] > 31 // dst[i+31:i] := (a[i+31] ? 0xFFFFFFFF : 0x0) // ELSE // dst[i+31:i] := SignExtend32(a[i+31:i] >> imm8[7:0]) // FI // ENDFOR // // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_srai_epi32 // FORCE_INLINE __m128i _mm_srai_epi32(__m128i a, __constrange(0,255) int imm) #define _mm_srai_epi32(a, imm) \ __extension__({ \ __m128i ret; \ if (unlikely((imm) == 0)) { \ ret = a; \ } else if (likely(0 < (imm) && (imm) < 32)) { \ ret = vreinterpretq_m128i_s32( \ vshlq_s32(vreinterpretq_s32_m128i(a), vdupq_n_s32(-imm))); \ } else { \ ret = vreinterpretq_m128i_s32( \ vshrq_n_s32(vreinterpretq_s32_m128i(a), 31)); \ } \ ret; \ }) // Shifts the 8 signed or unsigned 16-bit integers in a right by count bits // while shifting in zeros. // // r0 := srl(a0, count) // r1 := srl(a1, count) // ... // r7 := srl(a7, count) // // https://msdn.microsoft.com/en-us/library/wd5ax830(v%3dvs.90).aspx FORCE_INLINE __m128i _mm_srl_epi16(__m128i a, __m128i count) { uint64_t c = vreinterpretq_nth_u64_m128i(count, 0); if (unlikely(c > 15)) return _mm_setzero_si128(); int16x8_t vc = vdupq_n_s16(-(int16_t) c); return vreinterpretq_m128i_u16(vshlq_u16(vreinterpretq_u16_m128i(a), vc)); } // Shifts the 4 signed or unsigned 32-bit integers in a right by count bits // while shifting in zeros. // // r0 := srl(a0, count) // r1 := srl(a1, count) // r2 := srl(a2, count) // r3 := srl(a3, count) // // https://msdn.microsoft.com/en-us/library/a9cbttf4(v%3dvs.90).aspx FORCE_INLINE __m128i _mm_srl_epi32(__m128i a, __m128i count) { uint64_t c = vreinterpretq_nth_u64_m128i(count, 0); if (unlikely(c > 31)) return _mm_setzero_si128(); int32x4_t vc = vdupq_n_s32(-(int32_t) c); return vreinterpretq_m128i_u32(vshlq_u32(vreinterpretq_u32_m128i(a), vc)); } // Shifts the 2 signed or unsigned 64-bit integers in a right by count bits // while shifting in zeros. // // r0 := srl(a0, count) // r1 := srl(a1, count) // // https://msdn.microsoft.com/en-us/library/yf6cf9k8(v%3dvs.90).aspx FORCE_INLINE __m128i _mm_srl_epi64(__m128i a, __m128i count) { uint64_t c = vreinterpretq_nth_u64_m128i(count, 0); if (unlikely(c > 63)) return _mm_setzero_si128(); int64x2_t vc = vdupq_n_s64(-(int64_t) c); return vreinterpretq_m128i_u64(vshlq_u64(vreinterpretq_u64_m128i(a), vc)); } // Shift packed 16-bit integers in a right by imm8 while shifting in zeros, and // store the results in dst. // // FOR j := 0 to 7 // i := j*16 // IF imm8[7:0] > 15 // dst[i+15:i] := 0 // ELSE // dst[i+15:i] := ZeroExtend16(a[i+15:i] >> imm8[7:0]) // FI // ENDFOR // // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_srli_epi16 #define _mm_srli_epi16(a, imm) \ __extension__({ \ __m128i ret; \ if (unlikely(imm) == 0) { \ ret = a; \ } else if (likely(0 < (imm) && (imm) < 16)) { \ ret = vreinterpretq_m128i_u16( \ vshlq_u16(vreinterpretq_u16_m128i(a), vdupq_n_s16(-imm))); \ } else { \ ret = _mm_setzero_si128(); \ } \ ret; \ }) // Shift packed 32-bit integers in a right by imm8 while shifting in zeros, and // store the results in dst. // // FOR j := 0 to 3 // i := j*32 // IF imm8[7:0] > 31 // dst[i+31:i] := 0 // ELSE // dst[i+31:i] := ZeroExtend32(a[i+31:i] >> imm8[7:0]) // FI // ENDFOR // // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_srli_epi32 // FORCE_INLINE __m128i _mm_srli_epi32(__m128i a, __constrange(0,255) int imm) #define _mm_srli_epi32(a, imm) \ __extension__({ \ __m128i ret; \ if (unlikely((imm) == 0)) { \ ret = a; \ } else if (likely(0 < (imm) && (imm) < 32)) { \ ret = vreinterpretq_m128i_u32( \ vshlq_u32(vreinterpretq_u32_m128i(a), vdupq_n_s32(-imm))); \ } else { \ ret = _mm_setzero_si128(); \ } \ ret; \ }) // Shift packed 64-bit integers in a right by imm8 while shifting in zeros, and // store the results in dst. // // FOR j := 0 to 1 // i := j*64 // IF imm8[7:0] > 63 // dst[i+63:i] := 0 // ELSE // dst[i+63:i] := ZeroExtend64(a[i+63:i] >> imm8[7:0]) // FI // ENDFOR // // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_srli_epi64 #define _mm_srli_epi64(a, imm) \ __extension__({ \ __m128i ret; \ if (unlikely((imm) == 0)) { \ ret = a; \ } else if (likely(0 < (imm) && (imm) < 64)) { \ ret = vreinterpretq_m128i_u64( \ vshlq_u64(vreinterpretq_u64_m128i(a), vdupq_n_s64(-imm))); \ } else { \ ret = _mm_setzero_si128(); \ } \ ret; \ }) // Shifts the 128 - bit value in a right by imm bytes while shifting in // zeros.imm must be an immediate. // // r := srl(a, imm*8) // // https://msdn.microsoft.com/en-us/library/305w28yz(v=vs.100).aspx // FORCE_INLINE _mm_srli_si128(__m128i a, __constrange(0,255) int imm) #define _mm_srli_si128(a, imm) \ __extension__({ \ __m128i ret; \ if (unlikely((imm) <= 0)) { \ ret = a; \ } \ if (unlikely((imm) > 15)) { \ ret = _mm_setzero_si128(); \ } else { \ ret = vreinterpretq_m128i_s8( \ vextq_s8(vreinterpretq_s8_m128i(a), vdupq_n_s8(0), (imm))); \ } \ ret; \ }) // Store 128-bits (composed of 2 packed double-precision (64-bit) floating-point // elements) from a into memory. mem_addr must be aligned on a 16-byte boundary // or a general-protection exception may be generated. // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_store_pd FORCE_INLINE void _mm_store_pd(double *mem_addr, __m128d a) { #if defined(__aarch64__) vst1q_f64((float64_t *) mem_addr, vreinterpretq_f64_m128d(a)); #else vst1q_f32((float32_t *) mem_addr, vreinterpretq_f32_m128d(a)); #endif } // Store the lower double-precision (64-bit) floating-point element from a into // 2 contiguous elements in memory. mem_addr must be aligned on a 16-byte // boundary or a general-protection exception may be generated. // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_store_pd1 FORCE_INLINE void _mm_store_pd1(double *mem_addr, __m128d a) { #if defined(__aarch64__) float64x1_t a_low = vget_low_f64(vreinterpretq_f64_m128d(a)); vst1q_f64((float64_t *) mem_addr, vreinterpretq_f64_m128d(vcombine_f64(a_low, a_low))); #else float32x2_t a_low = vget_low_f32(vreinterpretq_f32_m128d(a)); vst1q_f32((float32_t *) mem_addr, vreinterpretq_f32_m128d(vcombine_f32(a_low, a_low))); #endif } // Store the lower double-precision (64-bit) floating-point element from a into // memory. mem_addr does not need to be aligned on any particular boundary. // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_store_sd FORCE_INLINE void _mm_store_sd(double *mem_addr, __m128d a) { #if defined(__aarch64__) vst1_f64((float64_t *) mem_addr, vget_low_f64(vreinterpretq_f64_m128d(a))); #else vst1_u64((uint64_t *) mem_addr, vget_low_u64(vreinterpretq_u64_m128d(a))); #endif } // Stores four 32-bit integer values as (as a __m128i value) at the address p. // https://msdn.microsoft.com/en-us/library/vstudio/edk11s13(v=vs.100).aspx FORCE_INLINE void _mm_store_si128(__m128i *p, __m128i a) { vst1q_s32((int32_t *) p, vreinterpretq_s32_m128i(a)); } // Store the lower double-precision (64-bit) floating-point element from a into // 2 contiguous elements in memory. mem_addr must be aligned on a 16-byte // boundary or a general-protection exception may be generated. // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=9,526,5601&text=_mm_store1_pd #define _mm_store1_pd _mm_store_pd1 // Store the upper double-precision (64-bit) floating-point element from a into // memory. // // MEM[mem_addr+63:mem_addr] := a[127:64] // // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_storeh_pd FORCE_INLINE void _mm_storeh_pd(double *mem_addr, __m128d a) { #if defined(__aarch64__) vst1_f64((float64_t *) mem_addr, vget_high_f64(vreinterpretq_f64_m128d(a))); #else vst1_f32((float32_t *) mem_addr, vget_high_f32(vreinterpretq_f32_m128d(a))); #endif } // Reads the lower 64 bits of b and stores them into the lower 64 bits of a. // https://msdn.microsoft.com/en-us/library/hhwf428f%28v=vs.90%29.aspx FORCE_INLINE void _mm_storel_epi64(__m128i *a, __m128i b) { uint64x1_t hi = vget_high_u64(vreinterpretq_u64_m128i(*a)); uint64x1_t lo = vget_low_u64(vreinterpretq_u64_m128i(b)); *a = vreinterpretq_m128i_u64(vcombine_u64(lo, hi)); } // Store the lower double-precision (64-bit) floating-point element from a into // memory. // // MEM[mem_addr+63:mem_addr] := a[63:0] // // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_storel_pd FORCE_INLINE void _mm_storel_pd(double *mem_addr, __m128d a) { #if defined(__aarch64__) vst1_f64((float64_t *) mem_addr, vget_low_f64(vreinterpretq_f64_m128d(a))); #else vst1_f32((float32_t *) mem_addr, vget_low_f32(vreinterpretq_f32_m128d(a))); #endif } // Store 2 double-precision (64-bit) floating-point elements from a into memory // in reverse order. mem_addr must be aligned on a 16-byte boundary or a // general-protection exception may be generated. // // MEM[mem_addr+63:mem_addr] := a[127:64] // MEM[mem_addr+127:mem_addr+64] := a[63:0] // // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_storer_pd FORCE_INLINE void _mm_storer_pd(double *mem_addr, __m128d a) { float32x4_t f = vreinterpretq_f32_m128d(a); _mm_store_pd(mem_addr, vreinterpretq_m128d_f32(vextq_f32(f, f, 2))); } // Store 128-bits (composed of 2 packed double-precision (64-bit) floating-point // elements) from a into memory. mem_addr does not need to be aligned on any // particular boundary. // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_storeu_pd FORCE_INLINE void _mm_storeu_pd(double *mem_addr, __m128d a) { _mm_store_pd(mem_addr, a); } // Stores 128-bits of integer data a at the address p. // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_storeu_si128 FORCE_INLINE void _mm_storeu_si128(__m128i *p, __m128i a) { vst1q_s32((int32_t *) p, vreinterpretq_s32_m128i(a)); } // Stores 32-bits of integer data a at the address p. // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_storeu_si32 FORCE_INLINE void _mm_storeu_si32(void *p, __m128i a) { vst1q_lane_s32((int32_t *) p, vreinterpretq_s32_m128i(a), 0); } // Store 128-bits (composed of 2 packed double-precision (64-bit) floating-point // elements) from a into memory using a non-temporal memory hint. mem_addr must // be aligned on a 16-byte boundary or a general-protection exception may be // generated. // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_stream_pd FORCE_INLINE void _mm_stream_pd(double *p, __m128d a) { #if __has_builtin(__builtin_nontemporal_store) __builtin_nontemporal_store(a, (float32x4_t *) p); #elif defined(__aarch64__) vst1q_f64(p, vreinterpretq_f64_m128d(a)); #else vst1q_s64((int64_t *) p, vreinterpretq_s64_m128d(a)); #endif } // Stores the data in a to the address p without polluting the caches. If the // cache line containing address p is already in the cache, the cache will be // updated. // https://msdn.microsoft.com/en-us/library/ba08y07y%28v=vs.90%29.aspx FORCE_INLINE void _mm_stream_si128(__m128i *p, __m128i a) { #if __has_builtin(__builtin_nontemporal_store) __builtin_nontemporal_store(a, p); #else vst1q_s64((int64_t *) p, vreinterpretq_s64_m128i(a)); #endif } // Store 32-bit integer a into memory using a non-temporal hint to minimize // cache pollution. If the cache line containing address mem_addr is already in // the cache, the cache will be updated. // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_stream_si32 FORCE_INLINE void _mm_stream_si32(int *p, int a) { vst1q_lane_s32((int32_t *) p, vdupq_n_s32(a), 0); } // Subtract packed 16-bit integers in b from packed 16-bit integers in a, and // store the results in dst. // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_sub_epi16 FORCE_INLINE __m128i _mm_sub_epi16(__m128i a, __m128i b) { return vreinterpretq_m128i_s16( vsubq_s16(vreinterpretq_s16_m128i(a), vreinterpretq_s16_m128i(b))); } // Subtracts the 4 signed or unsigned 32-bit integers of b from the 4 signed or // unsigned 32-bit integers of a. // // r0 := a0 - b0 // r1 := a1 - b1 // r2 := a2 - b2 // r3 := a3 - b3 // // https://msdn.microsoft.com/en-us/library/vstudio/fhh866h0(v=vs.100).aspx FORCE_INLINE __m128i _mm_sub_epi32(__m128i a, __m128i b) { return vreinterpretq_m128i_s32( vsubq_s32(vreinterpretq_s32_m128i(a), vreinterpretq_s32_m128i(b))); } // Subtract 2 packed 64-bit integers in b from 2 packed 64-bit integers in a, // and store the results in dst. // r0 := a0 - b0 // r1 := a1 - b1 FORCE_INLINE __m128i _mm_sub_epi64(__m128i a, __m128i b) { return vreinterpretq_m128i_s64( vsubq_s64(vreinterpretq_s64_m128i(a), vreinterpretq_s64_m128i(b))); } // Subtract packed 8-bit integers in b from packed 8-bit integers in a, and // store the results in dst. // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_sub_epi8 FORCE_INLINE __m128i _mm_sub_epi8(__m128i a, __m128i b) { return vreinterpretq_m128i_s8( vsubq_s8(vreinterpretq_s8_m128i(a), vreinterpretq_s8_m128i(b))); } // Subtract packed double-precision (64-bit) floating-point elements in b from // packed double-precision (64-bit) floating-point elements in a, and store the // results in dst. // // FOR j := 0 to 1 // i := j*64 // dst[i+63:i] := a[i+63:i] - b[i+63:i] // ENDFOR // // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_sub_pd FORCE_INLINE __m128d _mm_sub_pd(__m128d a, __m128d b) { #if defined(__aarch64__) return vreinterpretq_m128d_f64( vsubq_f64(vreinterpretq_f64_m128d(a), vreinterpretq_f64_m128d(b))); #else double *da = (double *) &a; double *db = (double *) &b; double c[2]; c[0] = da[0] - db[0]; c[1] = da[1] - db[1]; return vld1q_f32((float32_t *) c); #endif } // Subtract the lower double-precision (64-bit) floating-point element in b from // the lower double-precision (64-bit) floating-point element in a, store the // result in the lower element of dst, and copy the upper element from a to the // upper element of dst. // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_sub_sd FORCE_INLINE __m128d _mm_sub_sd(__m128d a, __m128d b) { return _mm_move_sd(a, _mm_sub_pd(a, b)); } // Subtract 64-bit integer b from 64-bit integer a, and store the result in dst. // // dst[63:0] := a[63:0] - b[63:0] // // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_sub_si64 FORCE_INLINE __m64 _mm_sub_si64(__m64 a, __m64 b) { return vreinterpret_m64_s64( vsub_s64(vreinterpret_s64_m64(a), vreinterpret_s64_m64(b))); } // Subtracts the 8 signed 16-bit integers of b from the 8 signed 16-bit integers // of a and saturates. // // r0 := SignedSaturate(a0 - b0) // r1 := SignedSaturate(a1 - b1) // ... // r7 := SignedSaturate(a7 - b7) // // https://technet.microsoft.com/en-us/subscriptions/3247z5b8(v=vs.90) FORCE_INLINE __m128i _mm_subs_epi16(__m128i a, __m128i b) { return vreinterpretq_m128i_s16( vqsubq_s16(vreinterpretq_s16_m128i(a), vreinterpretq_s16_m128i(b))); } // Subtracts the 16 signed 8-bit integers of b from the 16 signed 8-bit integers // of a and saturates. // // r0 := SignedSaturate(a0 - b0) // r1 := SignedSaturate(a1 - b1) // ... // r15 := SignedSaturate(a15 - b15) // // https://technet.microsoft.com/en-us/subscriptions/by7kzks1(v=vs.90) FORCE_INLINE __m128i _mm_subs_epi8(__m128i a, __m128i b) { return vreinterpretq_m128i_s8( vqsubq_s8(vreinterpretq_s8_m128i(a), vreinterpretq_s8_m128i(b))); } // Subtracts the 8 unsigned 16-bit integers of bfrom the 8 unsigned 16-bit // integers of a and saturates.. // https://technet.microsoft.com/en-us/subscriptions/index/f44y0s19(v=vs.90).aspx FORCE_INLINE __m128i _mm_subs_epu16(__m128i a, __m128i b) { return vreinterpretq_m128i_u16( vqsubq_u16(vreinterpretq_u16_m128i(a), vreinterpretq_u16_m128i(b))); } // Subtracts the 16 unsigned 8-bit integers of b from the 16 unsigned 8-bit // integers of a and saturates. // // r0 := UnsignedSaturate(a0 - b0) // r1 := UnsignedSaturate(a1 - b1) // ... // r15 := UnsignedSaturate(a15 - b15) // // https://technet.microsoft.com/en-us/subscriptions/yadkxc18(v=vs.90) FORCE_INLINE __m128i _mm_subs_epu8(__m128i a, __m128i b) { return vreinterpretq_m128i_u8( vqsubq_u8(vreinterpretq_u8_m128i(a), vreinterpretq_u8_m128i(b))); } #define _mm_ucomieq_sd _mm_comieq_sd #define _mm_ucomige_sd _mm_comige_sd #define _mm_ucomigt_sd _mm_comigt_sd #define _mm_ucomile_sd _mm_comile_sd #define _mm_ucomilt_sd _mm_comilt_sd #define _mm_ucomineq_sd _mm_comineq_sd // Return vector of type __m128d with undefined elements. // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_undefined_pd FORCE_INLINE __m128d _mm_undefined_pd(void) { #if defined(__GNUC__) || defined(__clang__) #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wuninitialized" #endif __m128d a; return a; #if defined(__GNUC__) || defined(__clang__) #pragma GCC diagnostic pop #endif } // Interleaves the upper 4 signed or unsigned 16-bit integers in a with the // upper 4 signed or unsigned 16-bit integers in b. // // r0 := a4 // r1 := b4 // r2 := a5 // r3 := b5 // r4 := a6 // r5 := b6 // r6 := a7 // r7 := b7 // // https://msdn.microsoft.com/en-us/library/03196cz7(v=vs.100).aspx FORCE_INLINE __m128i _mm_unpackhi_epi16(__m128i a, __m128i b) { #if defined(__aarch64__) return vreinterpretq_m128i_s16( vzip2q_s16(vreinterpretq_s16_m128i(a), vreinterpretq_s16_m128i(b))); #else int16x4_t a1 = vget_high_s16(vreinterpretq_s16_m128i(a)); int16x4_t b1 = vget_high_s16(vreinterpretq_s16_m128i(b)); int16x4x2_t result = vzip_s16(a1, b1); return vreinterpretq_m128i_s16(vcombine_s16(result.val[0], result.val[1])); #endif } // Interleaves the upper 2 signed or unsigned 32-bit integers in a with the // upper 2 signed or unsigned 32-bit integers in b. // https://msdn.microsoft.com/en-us/library/65sa7cbs(v=vs.100).aspx FORCE_INLINE __m128i _mm_unpackhi_epi32(__m128i a, __m128i b) { #if defined(__aarch64__) return vreinterpretq_m128i_s32( vzip2q_s32(vreinterpretq_s32_m128i(a), vreinterpretq_s32_m128i(b))); #else int32x2_t a1 = vget_high_s32(vreinterpretq_s32_m128i(a)); int32x2_t b1 = vget_high_s32(vreinterpretq_s32_m128i(b)); int32x2x2_t result = vzip_s32(a1, b1); return vreinterpretq_m128i_s32(vcombine_s32(result.val[0], result.val[1])); #endif } // Interleaves the upper signed or unsigned 64-bit integer in a with the // upper signed or unsigned 64-bit integer in b. // // r0 := a1 // r1 := b1 FORCE_INLINE __m128i _mm_unpackhi_epi64(__m128i a, __m128i b) { int64x1_t a_h = vget_high_s64(vreinterpretq_s64_m128i(a)); int64x1_t b_h = vget_high_s64(vreinterpretq_s64_m128i(b)); return vreinterpretq_m128i_s64(vcombine_s64(a_h, b_h)); } // Interleaves the upper 8 signed or unsigned 8-bit integers in a with the upper // 8 signed or unsigned 8-bit integers in b. // // r0 := a8 // r1 := b8 // r2 := a9 // r3 := b9 // ... // r14 := a15 // r15 := b15 // // https://msdn.microsoft.com/en-us/library/t5h7783k(v=vs.100).aspx FORCE_INLINE __m128i _mm_unpackhi_epi8(__m128i a, __m128i b) { #if defined(__aarch64__) return vreinterpretq_m128i_s8( vzip2q_s8(vreinterpretq_s8_m128i(a), vreinterpretq_s8_m128i(b))); #else int8x8_t a1 = vreinterpret_s8_s16(vget_high_s16(vreinterpretq_s16_m128i(a))); int8x8_t b1 = vreinterpret_s8_s16(vget_high_s16(vreinterpretq_s16_m128i(b))); int8x8x2_t result = vzip_s8(a1, b1); return vreinterpretq_m128i_s8(vcombine_s8(result.val[0], result.val[1])); #endif } // Unpack and interleave double-precision (64-bit) floating-point elements from // the high half of a and b, and store the results in dst. // // DEFINE INTERLEAVE_HIGH_QWORDS(src1[127:0], src2[127:0]) { // dst[63:0] := src1[127:64] // dst[127:64] := src2[127:64] // RETURN dst[127:0] // } // dst[127:0] := INTERLEAVE_HIGH_QWORDS(a[127:0], b[127:0]) // // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_unpackhi_pd FORCE_INLINE __m128d _mm_unpackhi_pd(__m128d a, __m128d b) { #if defined(__aarch64__) return vreinterpretq_m128d_f64( vzip2q_f64(vreinterpretq_f64_m128d(a), vreinterpretq_f64_m128d(b))); #else return vreinterpretq_m128d_s64( vcombine_s64(vget_high_s64(vreinterpretq_s64_m128d(a)), vget_high_s64(vreinterpretq_s64_m128d(b)))); #endif } // Interleaves the lower 4 signed or unsigned 16-bit integers in a with the // lower 4 signed or unsigned 16-bit integers in b. // // r0 := a0 // r1 := b0 // r2 := a1 // r3 := b1 // r4 := a2 // r5 := b2 // r6 := a3 // r7 := b3 // // https://msdn.microsoft.com/en-us/library/btxb17bw%28v=vs.90%29.aspx FORCE_INLINE __m128i _mm_unpacklo_epi16(__m128i a, __m128i b) { #if defined(__aarch64__) return vreinterpretq_m128i_s16( vzip1q_s16(vreinterpretq_s16_m128i(a), vreinterpretq_s16_m128i(b))); #else int16x4_t a1 = vget_low_s16(vreinterpretq_s16_m128i(a)); int16x4_t b1 = vget_low_s16(vreinterpretq_s16_m128i(b)); int16x4x2_t result = vzip_s16(a1, b1); return vreinterpretq_m128i_s16(vcombine_s16(result.val[0], result.val[1])); #endif } // Interleaves the lower 2 signed or unsigned 32 - bit integers in a with the // lower 2 signed or unsigned 32 - bit integers in b. // // r0 := a0 // r1 := b0 // r2 := a1 // r3 := b1 // // https://msdn.microsoft.com/en-us/library/x8atst9d(v=vs.100).aspx FORCE_INLINE __m128i _mm_unpacklo_epi32(__m128i a, __m128i b) { #if defined(__aarch64__) return vreinterpretq_m128i_s32( vzip1q_s32(vreinterpretq_s32_m128i(a), vreinterpretq_s32_m128i(b))); #else int32x2_t a1 = vget_low_s32(vreinterpretq_s32_m128i(a)); int32x2_t b1 = vget_low_s32(vreinterpretq_s32_m128i(b)); int32x2x2_t result = vzip_s32(a1, b1); return vreinterpretq_m128i_s32(vcombine_s32(result.val[0], result.val[1])); #endif } FORCE_INLINE __m128i _mm_unpacklo_epi64(__m128i a, __m128i b) { int64x1_t a_l = vget_low_s64(vreinterpretq_s64_m128i(a)); int64x1_t b_l = vget_low_s64(vreinterpretq_s64_m128i(b)); return vreinterpretq_m128i_s64(vcombine_s64(a_l, b_l)); } // Interleaves the lower 8 signed or unsigned 8-bit integers in a with the lower // 8 signed or unsigned 8-bit integers in b. // // r0 := a0 // r1 := b0 // r2 := a1 // r3 := b1 // ... // r14 := a7 // r15 := b7 // // https://msdn.microsoft.com/en-us/library/xf7k860c%28v=vs.90%29.aspx FORCE_INLINE __m128i _mm_unpacklo_epi8(__m128i a, __m128i b) { #if defined(__aarch64__) return vreinterpretq_m128i_s8( vzip1q_s8(vreinterpretq_s8_m128i(a), vreinterpretq_s8_m128i(b))); #else int8x8_t a1 = vreinterpret_s8_s16(vget_low_s16(vreinterpretq_s16_m128i(a))); int8x8_t b1 = vreinterpret_s8_s16(vget_low_s16(vreinterpretq_s16_m128i(b))); int8x8x2_t result = vzip_s8(a1, b1); return vreinterpretq_m128i_s8(vcombine_s8(result.val[0], result.val[1])); #endif } // Unpack and interleave double-precision (64-bit) floating-point elements from // the low half of a and b, and store the results in dst. // // DEFINE INTERLEAVE_QWORDS(src1[127:0], src2[127:0]) { // dst[63:0] := src1[63:0] // dst[127:64] := src2[63:0] // RETURN dst[127:0] // } // dst[127:0] := INTERLEAVE_QWORDS(a[127:0], b[127:0]) // // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_unpacklo_pd FORCE_INLINE __m128d _mm_unpacklo_pd(__m128d a, __m128d b) { #if defined(__aarch64__) return vreinterpretq_m128d_f64( vzip1q_f64(vreinterpretq_f64_m128d(a), vreinterpretq_f64_m128d(b))); #else return vreinterpretq_m128d_s64( vcombine_s64(vget_low_s64(vreinterpretq_s64_m128d(a)), vget_low_s64(vreinterpretq_s64_m128d(b)))); #endif } // Compute the bitwise XOR of packed double-precision (64-bit) floating-point // elements in a and b, and store the results in dst. // // FOR j := 0 to 1 // i := j*64 // dst[i+63:i] := a[i+63:i] XOR b[i+63:i] // ENDFOR // // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_xor_pd FORCE_INLINE __m128d _mm_xor_pd(__m128d a, __m128d b) { return vreinterpretq_m128d_s64( veorq_s64(vreinterpretq_s64_m128d(a), vreinterpretq_s64_m128d(b))); } // Computes the bitwise XOR of the 128-bit value in a and the 128-bit value in // b. https://msdn.microsoft.com/en-us/library/fzt08www(v=vs.100).aspx FORCE_INLINE __m128i _mm_xor_si128(__m128i a, __m128i b) { return vreinterpretq_m128i_s32( veorq_s32(vreinterpretq_s32_m128i(a), vreinterpretq_s32_m128i(b))); } /* SSE3 */ // Alternatively add and subtract packed double-precision (64-bit) // floating-point elements in a to/from packed elements in b, and store the // results in dst. // // FOR j := 0 to 1 // i := j*64 // IF ((j & 1) == 0) // dst[i+63:i] := a[i+63:i] - b[i+63:i] // ELSE // dst[i+63:i] := a[i+63:i] + b[i+63:i] // FI // ENDFOR // // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_addsub_pd FORCE_INLINE __m128d _mm_addsub_pd(__m128d a, __m128d b) { __m128d mask = _mm_set_pd(1.0f, -1.0f); #if defined(__aarch64__) return vreinterpretq_m128d_f64(vfmaq_f64(vreinterpretq_f64_m128d(a), vreinterpretq_f64_m128d(b), vreinterpretq_f64_m128d(mask))); #else return _mm_add_pd(_mm_mul_pd(b, mask), a); #endif } // Alternatively add and subtract packed single-precision (32-bit) // floating-point elements in a to/from packed elements in b, and store the // results in dst. // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=addsub_ps FORCE_INLINE __m128 _mm_addsub_ps(__m128 a, __m128 b) { __m128 mask = {-1.0f, 1.0f, -1.0f, 1.0f}; #if defined(__aarch64__) || defined(__ARM_FEATURE_FMA) /* VFPv4+ */ return vreinterpretq_m128_f32(vfmaq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(mask), vreinterpretq_f32_m128(b))); #else return _mm_add_ps(_mm_mul_ps(b, mask), a); #endif } // Horizontally add adjacent pairs of double-precision (64-bit) floating-point // elements in a and b, and pack the results in dst. // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_hadd_pd FORCE_INLINE __m128d _mm_hadd_pd(__m128d a, __m128d b) { #if defined(__aarch64__) return vreinterpretq_m128d_f64( vpaddq_f64(vreinterpretq_f64_m128d(a), vreinterpretq_f64_m128d(b))); #else double *da = (double *) &a; double *db = (double *) &b; double c[] = {da[0] + da[1], db[0] + db[1]}; return vreinterpretq_m128d_u64(vld1q_u64((uint64_t *) c)); #endif } // Computes pairwise add of each argument as single-precision, floating-point // values a and b. // https://msdn.microsoft.com/en-us/library/yd9wecaa.aspx FORCE_INLINE __m128 _mm_hadd_ps(__m128 a, __m128 b) { #if defined(__aarch64__) return vreinterpretq_m128_f32( vpaddq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(b))); #else float32x2_t a10 = vget_low_f32(vreinterpretq_f32_m128(a)); float32x2_t a32 = vget_high_f32(vreinterpretq_f32_m128(a)); float32x2_t b10 = vget_low_f32(vreinterpretq_f32_m128(b)); float32x2_t b32 = vget_high_f32(vreinterpretq_f32_m128(b)); return vreinterpretq_m128_f32( vcombine_f32(vpadd_f32(a10, a32), vpadd_f32(b10, b32))); #endif } // Horizontally subtract adjacent pairs of double-precision (64-bit) // floating-point elements in a and b, and pack the results in dst. // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_hsub_pd FORCE_INLINE __m128d _mm_hsub_pd(__m128d _a, __m128d _b) { #if defined(__aarch64__) return vreinterpretq_m128d_f64(vsubq_f64( vuzp1q_f64(vreinterpretq_f64_m128d(_a), vreinterpretq_f64_m128d(_b)), vuzp2q_f64(vreinterpretq_f64_m128d(_a), vreinterpretq_f64_m128d(_b)))); #else double *da = (double *) &_a; double *db = (double *) &_b; double c[] = {da[0] - da[1], db[0] - db[1]}; return vreinterpretq_m128d_u64(vld1q_u64((uint64_t *) c)); #endif } // Horizontally substract adjacent pairs of single-precision (32-bit) // floating-point elements in a and b, and pack the results in dst. // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_hsub_ps FORCE_INLINE __m128 _mm_hsub_ps(__m128 _a, __m128 _b) { #if defined(__aarch64__) return vreinterpretq_m128_f32(vsubq_f32( vuzp1q_f32(vreinterpretq_f32_m128(_a), vreinterpretq_f32_m128(_b)), vuzp2q_f32(vreinterpretq_f32_m128(_a), vreinterpretq_f32_m128(_b)))); #else float32x4x2_t c = vuzpq_f32(vreinterpretq_f32_m128(_a), vreinterpretq_f32_m128(_b)); return vreinterpretq_m128_f32(vsubq_f32(c.val[0], c.val[1])); #endif } // Load 128-bits of integer data from unaligned memory into dst. This intrinsic // may perform better than _mm_loadu_si128 when the data crosses a cache line // boundary. // // dst[127:0] := MEM[mem_addr+127:mem_addr] // // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_lddqu_si128 #define _mm_lddqu_si128 _mm_loadu_si128 // Load a double-precision (64-bit) floating-point element from memory into both // elements of dst. // // dst[63:0] := MEM[mem_addr+63:mem_addr] // dst[127:64] := MEM[mem_addr+63:mem_addr] // // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_loaddup_pd #define _mm_loaddup_pd _mm_load1_pd // Duplicate the low double-precision (64-bit) floating-point element from a, // and store the results in dst. // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_movedup_pd FORCE_INLINE __m128d _mm_movedup_pd(__m128d a) { #if (__aarch64__) return vreinterpretq_m128d_f64( vdupq_laneq_f64(vreinterpretq_f64_m128d(a), 0)); #else return vreinterpretq_m128d_u64( vdupq_n_u64(vgetq_lane_u64(vreinterpretq_u64_m128d(a), 0))); #endif } // Duplicate odd-indexed single-precision (32-bit) floating-point elements // from a, and store the results in dst. // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_movehdup_ps FORCE_INLINE __m128 _mm_movehdup_ps(__m128 a) { #if __has_builtin(__builtin_shufflevector) return vreinterpretq_m128_f32(__builtin_shufflevector( vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(a), 1, 1, 3, 3)); #else float32_t a1 = vgetq_lane_f32(vreinterpretq_f32_m128(a), 1); float32_t a3 = vgetq_lane_f32(vreinterpretq_f32_m128(a), 3); float ALIGN_STRUCT(16) data[4] = {a1, a1, a3, a3}; return vreinterpretq_m128_f32(vld1q_f32(data)); #endif } // Duplicate even-indexed single-precision (32-bit) floating-point elements // from a, and store the results in dst. // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_moveldup_ps FORCE_INLINE __m128 _mm_moveldup_ps(__m128 a) { #if __has_builtin(__builtin_shufflevector) return vreinterpretq_m128_f32(__builtin_shufflevector( vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(a), 0, 0, 2, 2)); #else float32_t a0 = vgetq_lane_f32(vreinterpretq_f32_m128(a), 0); float32_t a2 = vgetq_lane_f32(vreinterpretq_f32_m128(a), 2); float ALIGN_STRUCT(16) data[4] = {a0, a0, a2, a2}; return vreinterpretq_m128_f32(vld1q_f32(data)); #endif } /* SSSE3 */ // Compute the absolute value of packed signed 16-bit integers in a, and store // the unsigned results in dst. // // FOR j := 0 to 7 // i := j*16 // dst[i+15:i] := ABS(a[i+15:i]) // ENDFOR // // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_abs_epi16 FORCE_INLINE __m128i _mm_abs_epi16(__m128i a) { return vreinterpretq_m128i_s16(vabsq_s16(vreinterpretq_s16_m128i(a))); } // Compute the absolute value of packed signed 32-bit integers in a, and store // the unsigned results in dst. // // FOR j := 0 to 3 // i := j*32 // dst[i+31:i] := ABS(a[i+31:i]) // ENDFOR // // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_abs_epi32 FORCE_INLINE __m128i _mm_abs_epi32(__m128i a) { return vreinterpretq_m128i_s32(vabsq_s32(vreinterpretq_s32_m128i(a))); } // Compute the absolute value of packed signed 8-bit integers in a, and store // the unsigned results in dst. // // FOR j := 0 to 15 // i := j*8 // dst[i+7:i] := ABS(a[i+7:i]) // ENDFOR // // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_abs_epi8 FORCE_INLINE __m128i _mm_abs_epi8(__m128i a) { return vreinterpretq_m128i_s8(vabsq_s8(vreinterpretq_s8_m128i(a))); } // Compute the absolute value of packed signed 16-bit integers in a, and store // the unsigned results in dst. // // FOR j := 0 to 3 // i := j*16 // dst[i+15:i] := ABS(a[i+15:i]) // ENDFOR // // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_abs_pi16 FORCE_INLINE __m64 _mm_abs_pi16(__m64 a) { return vreinterpret_m64_s16(vabs_s16(vreinterpret_s16_m64(a))); } // Compute the absolute value of packed signed 32-bit integers in a, and store // the unsigned results in dst. // // FOR j := 0 to 1 // i := j*32 // dst[i+31:i] := ABS(a[i+31:i]) // ENDFOR // // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_abs_pi32 FORCE_INLINE __m64 _mm_abs_pi32(__m64 a) { return vreinterpret_m64_s32(vabs_s32(vreinterpret_s32_m64(a))); } // Compute the absolute value of packed signed 8-bit integers in a, and store // the unsigned results in dst. // // FOR j := 0 to 7 // i := j*8 // dst[i+7:i] := ABS(a[i+7:i]) // ENDFOR // // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_abs_pi8 FORCE_INLINE __m64 _mm_abs_pi8(__m64 a) { return vreinterpret_m64_s8(vabs_s8(vreinterpret_s8_m64(a))); } // Concatenate 16-byte blocks in a and b into a 32-byte temporary result, shift // the result right by imm8 bytes, and store the low 16 bytes in dst. // // tmp[255:0] := ((a[127:0] << 128)[255:0] OR b[127:0]) >> (imm8*8) // dst[127:0] := tmp[127:0] // // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_alignr_epi8 #define _mm_alignr_epi8(a, b, imm) \ __extension__({ \ __m128i ret; \ if (unlikely((imm) >= 32)) { \ ret = _mm_setzero_si128(); \ } else { \ uint8x16_t tmp_low, tmp_high; \ if (imm >= 16) { \ const int idx = imm - 16; \ tmp_low = vreinterpretq_u8_m128i(a); \ tmp_high = vdupq_n_u8(0); \ ret = \ vreinterpretq_m128i_u8(vextq_u8(tmp_low, tmp_high, idx)); \ } else { \ const int idx = imm; \ tmp_low = vreinterpretq_u8_m128i(b); \ tmp_high = vreinterpretq_u8_m128i(a); \ ret = \ vreinterpretq_m128i_u8(vextq_u8(tmp_low, tmp_high, idx)); \ } \ } \ ret; \ }) // Concatenate 8-byte blocks in a and b into a 16-byte temporary result, shift // the result right by imm8 bytes, and store the low 8 bytes in dst. // // tmp[127:0] := ((a[63:0] << 64)[127:0] OR b[63:0]) >> (imm8*8) // dst[63:0] := tmp[63:0] // // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_alignr_pi8 #define _mm_alignr_pi8(a, b, imm) \ __extension__({ \ __m64 ret; \ if (unlikely((imm) >= 16)) { \ ret = vreinterpret_m64_s8(vdup_n_s8(0)); \ } else { \ uint8x8_t tmp_low, tmp_high; \ if (imm >= 8) { \ const int idx = imm - 8; \ tmp_low = vreinterpret_u8_m64(a); \ tmp_high = vdup_n_u8(0); \ ret = vreinterpret_m64_u8(vext_u8(tmp_low, tmp_high, idx)); \ } else { \ const int idx = imm; \ tmp_low = vreinterpret_u8_m64(b); \ tmp_high = vreinterpret_u8_m64(a); \ ret = vreinterpret_m64_u8(vext_u8(tmp_low, tmp_high, idx)); \ } \ } \ ret; \ }) // Computes pairwise add of each argument as a 16-bit signed or unsigned integer // values a and b. FORCE_INLINE __m128i _mm_hadd_epi16(__m128i _a, __m128i _b) { int16x8_t a = vreinterpretq_s16_m128i(_a); int16x8_t b = vreinterpretq_s16_m128i(_b); #if defined(__aarch64__) return vreinterpretq_m128i_s16(vpaddq_s16(a, b)); #else return vreinterpretq_m128i_s16( vcombine_s16(vpadd_s16(vget_low_s16(a), vget_high_s16(a)), vpadd_s16(vget_low_s16(b), vget_high_s16(b)))); #endif } // Computes pairwise add of each argument as a 32-bit signed or unsigned integer // values a and b. FORCE_INLINE __m128i _mm_hadd_epi32(__m128i _a, __m128i _b) { int32x4_t a = vreinterpretq_s32_m128i(_a); int32x4_t b = vreinterpretq_s32_m128i(_b); return vreinterpretq_m128i_s32( vcombine_s32(vpadd_s32(vget_low_s32(a), vget_high_s32(a)), vpadd_s32(vget_low_s32(b), vget_high_s32(b)))); } // Horizontally add adjacent pairs of 16-bit integers in a and b, and pack the // signed 16-bit results in dst. // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_hadd_pi16 FORCE_INLINE __m64 _mm_hadd_pi16(__m64 a, __m64 b) { return vreinterpret_m64_s16( vpadd_s16(vreinterpret_s16_m64(a), vreinterpret_s16_m64(b))); } // Horizontally add adjacent pairs of 32-bit integers in a and b, and pack the // signed 32-bit results in dst. // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_hadd_pi32 FORCE_INLINE __m64 _mm_hadd_pi32(__m64 a, __m64 b) { return vreinterpret_m64_s32( vpadd_s32(vreinterpret_s32_m64(a), vreinterpret_s32_m64(b))); } // Computes saturated pairwise sub of each argument as a 16-bit signed // integer values a and b. FORCE_INLINE __m128i _mm_hadds_epi16(__m128i _a, __m128i _b) { #if defined(__aarch64__) int16x8_t a = vreinterpretq_s16_m128i(_a); int16x8_t b = vreinterpretq_s16_m128i(_b); return vreinterpretq_s64_s16( vqaddq_s16(vuzp1q_s16(a, b), vuzp2q_s16(a, b))); #else int32x4_t a = vreinterpretq_s32_m128i(_a); int32x4_t b = vreinterpretq_s32_m128i(_b); // Interleave using vshrn/vmovn // [a0|a2|a4|a6|b0|b2|b4|b6] // [a1|a3|a5|a7|b1|b3|b5|b7] int16x8_t ab0246 = vcombine_s16(vmovn_s32(a), vmovn_s32(b)); int16x8_t ab1357 = vcombine_s16(vshrn_n_s32(a, 16), vshrn_n_s32(b, 16)); // Saturated add return vreinterpretq_m128i_s16(vqaddq_s16(ab0246, ab1357)); #endif } // Horizontally add adjacent pairs of signed 16-bit integers in a and b using // saturation, and pack the signed 16-bit results in dst. // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_hadds_pi16 FORCE_INLINE __m64 _mm_hadds_pi16(__m64 _a, __m64 _b) { int16x4_t a = vreinterpret_s16_m64(_a); int16x4_t b = vreinterpret_s16_m64(_b); #if defined(__aarch64__) return vreinterpret_s64_s16(vqadd_s16(vuzp1_s16(a, b), vuzp2_s16(a, b))); #else int16x4x2_t res = vuzp_s16(a, b); return vreinterpret_s64_s16(vqadd_s16(res.val[0], res.val[1])); #endif } // Computes pairwise difference of each argument as a 16-bit signed or unsigned // integer values a and b. FORCE_INLINE __m128i _mm_hsub_epi16(__m128i _a, __m128i _b) { int32x4_t a = vreinterpretq_s32_m128i(_a); int32x4_t b = vreinterpretq_s32_m128i(_b); // Interleave using vshrn/vmovn // [a0|a2|a4|a6|b0|b2|b4|b6] // [a1|a3|a5|a7|b1|b3|b5|b7] int16x8_t ab0246 = vcombine_s16(vmovn_s32(a), vmovn_s32(b)); int16x8_t ab1357 = vcombine_s16(vshrn_n_s32(a, 16), vshrn_n_s32(b, 16)); // Subtract return vreinterpretq_m128i_s16(vsubq_s16(ab0246, ab1357)); } // Computes pairwise difference of each argument as a 32-bit signed or unsigned // integer values a and b. FORCE_INLINE __m128i _mm_hsub_epi32(__m128i _a, __m128i _b) { int64x2_t a = vreinterpretq_s64_m128i(_a); int64x2_t b = vreinterpretq_s64_m128i(_b); // Interleave using vshrn/vmovn // [a0|a2|b0|b2] // [a1|a2|b1|b3] int32x4_t ab02 = vcombine_s32(vmovn_s64(a), vmovn_s64(b)); int32x4_t ab13 = vcombine_s32(vshrn_n_s64(a, 32), vshrn_n_s64(b, 32)); // Subtract return vreinterpretq_m128i_s32(vsubq_s32(ab02, ab13)); } // Horizontally subtract adjacent pairs of 16-bit integers in a and b, and pack // the signed 16-bit results in dst. // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_hsub_pi16 FORCE_INLINE __m64 _mm_hsub_pi16(__m64 _a, __m64 _b) { int32x4_t ab = vcombine_s32(vreinterpret_s32_m64(_a), vreinterpret_s32_m64(_b)); int16x4_t ab_low_bits = vmovn_s32(ab); int16x4_t ab_high_bits = vshrn_n_s32(ab, 16); return vreinterpret_m64_s16(vsub_s16(ab_low_bits, ab_high_bits)); } // Horizontally subtract adjacent pairs of 32-bit integers in a and b, and pack // the signed 32-bit results in dst. // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_hsub_pi32 FORCE_INLINE __m64 _mm_hsub_pi32(__m64 _a, __m64 _b) { #if defined(__aarch64__) int32x2_t a = vreinterpret_s32_m64(_a); int32x2_t b = vreinterpret_s32_m64(_b); return vreinterpret_m64_s32(vsub_s32(vtrn1_s32(a, b), vtrn2_s32(a, b))); #else int32x2x2_t trn_ab = vtrn_s32(vreinterpret_s32_m64(_a), vreinterpret_s32_m64(_b)); return vreinterpret_m64_s32(vsub_s32(trn_ab.val[0], trn_ab.val[1])); #endif } // Computes saturated pairwise difference of each argument as a 16-bit signed // integer values a and b. // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_hsubs_epi16 FORCE_INLINE __m128i _mm_hsubs_epi16(__m128i _a, __m128i _b) { #if defined(__aarch64__) int16x8_t a = vreinterpretq_s16_m128i(_a); int16x8_t b = vreinterpretq_s16_m128i(_b); return vreinterpretq_s64_s16( vqsubq_s16(vuzp1q_s16(a, b), vuzp2q_s16(a, b))); #else int32x4_t a = vreinterpretq_s32_m128i(_a); int32x4_t b = vreinterpretq_s32_m128i(_b); // Interleave using vshrn/vmovn // [a0|a2|a4|a6|b0|b2|b4|b6] // [a1|a3|a5|a7|b1|b3|b5|b7] int16x8_t ab0246 = vcombine_s16(vmovn_s32(a), vmovn_s32(b)); int16x8_t ab1357 = vcombine_s16(vshrn_n_s32(a, 16), vshrn_n_s32(b, 16)); // Saturated subtract return vreinterpretq_m128i_s16(vqsubq_s16(ab0246, ab1357)); #endif } // Horizontally subtract adjacent pairs of signed 16-bit integers in a and b // using saturation, and pack the signed 16-bit results in dst. // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_hsubs_pi16 FORCE_INLINE __m64 _mm_hsubs_pi16(__m64 _a, __m64 _b) { int16x4_t a = vreinterpret_s16_m64(_a); int16x4_t b = vreinterpret_s16_m64(_b); #if defined(__aarch64__) return vreinterpret_s64_s16(vqsub_s16(vuzp1_s16(a, b), vuzp2_s16(a, b))); #else int16x4x2_t res = vuzp_s16(a, b); return vreinterpret_s64_s16(vqsub_s16(res.val[0], res.val[1])); #endif } // Vertically multiply each unsigned 8-bit integer from a with the corresponding // signed 8-bit integer from b, producing intermediate signed 16-bit integers. // Horizontally add adjacent pairs of intermediate signed 16-bit integers, // and pack the saturated results in dst. // // FOR j := 0 to 7 // i := j*16 // dst[i+15:i] := Saturate_To_Int16( a[i+15:i+8]*b[i+15:i+8] + // a[i+7:i]*b[i+7:i] ) // ENDFOR FORCE_INLINE __m128i _mm_maddubs_epi16(__m128i _a, __m128i _b) { #if defined(__aarch64__) uint8x16_t a = vreinterpretq_u8_m128i(_a); int8x16_t b = vreinterpretq_s8_m128i(_b); int16x8_t tl = vmulq_s16(vreinterpretq_s16_u16(vmovl_u8(vget_low_u8(a))), vmovl_s8(vget_low_s8(b))); int16x8_t th = vmulq_s16(vreinterpretq_s16_u16(vmovl_u8(vget_high_u8(a))), vmovl_s8(vget_high_s8(b))); return vreinterpretq_m128i_s16( vqaddq_s16(vuzp1q_s16(tl, th), vuzp2q_s16(tl, th))); #else // This would be much simpler if x86 would choose to zero extend OR sign // extend, not both. This could probably be optimized better. uint16x8_t a = vreinterpretq_u16_m128i(_a); int16x8_t b = vreinterpretq_s16_m128i(_b); // Zero extend a int16x8_t a_odd = vreinterpretq_s16_u16(vshrq_n_u16(a, 8)); int16x8_t a_even = vreinterpretq_s16_u16(vbicq_u16(a, vdupq_n_u16(0xff00))); // Sign extend by shifting left then shifting right. int16x8_t b_even = vshrq_n_s16(vshlq_n_s16(b, 8), 8); int16x8_t b_odd = vshrq_n_s16(b, 8); // multiply int16x8_t prod1 = vmulq_s16(a_even, b_even); int16x8_t prod2 = vmulq_s16(a_odd, b_odd); // saturated add return vreinterpretq_m128i_s16(vqaddq_s16(prod1, prod2)); #endif } // Vertically multiply each unsigned 8-bit integer from a with the corresponding // signed 8-bit integer from b, producing intermediate signed 16-bit integers. // Horizontally add adjacent pairs of intermediate signed 16-bit integers, and // pack the saturated results in dst. // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maddubs_pi16 FORCE_INLINE __m64 _mm_maddubs_pi16(__m64 _a, __m64 _b) { uint16x4_t a = vreinterpret_u16_m64(_a); int16x4_t b = vreinterpret_s16_m64(_b); // Zero extend a int16x4_t a_odd = vreinterpret_s16_u16(vshr_n_u16(a, 8)); int16x4_t a_even = vreinterpret_s16_u16(vand_u16(a, vdup_n_u16(0xff))); // Sign extend by shifting left then shifting right. int16x4_t b_even = vshr_n_s16(vshl_n_s16(b, 8), 8); int16x4_t b_odd = vshr_n_s16(b, 8); // multiply int16x4_t prod1 = vmul_s16(a_even, b_even); int16x4_t prod2 = vmul_s16(a_odd, b_odd); // saturated add return vreinterpret_m64_s16(vqadd_s16(prod1, prod2)); } // Multiply packed signed 16-bit integers in a and b, producing intermediate // signed 32-bit integers. Shift right by 15 bits while rounding up, and store // the packed 16-bit integers in dst. // // r0 := Round(((int32_t)a0 * (int32_t)b0) >> 15) // r1 := Round(((int32_t)a1 * (int32_t)b1) >> 15) // r2 := Round(((int32_t)a2 * (int32_t)b2) >> 15) // ... // r7 := Round(((int32_t)a7 * (int32_t)b7) >> 15) FORCE_INLINE __m128i _mm_mulhrs_epi16(__m128i a, __m128i b) { // Has issues due to saturation // return vreinterpretq_m128i_s16(vqrdmulhq_s16(a, b)); // Multiply int32x4_t mul_lo = vmull_s16(vget_low_s16(vreinterpretq_s16_m128i(a)), vget_low_s16(vreinterpretq_s16_m128i(b))); int32x4_t mul_hi = vmull_s16(vget_high_s16(vreinterpretq_s16_m128i(a)), vget_high_s16(vreinterpretq_s16_m128i(b))); // Rounding narrowing shift right // narrow = (int16_t)((mul + 16384) >> 15); int16x4_t narrow_lo = vrshrn_n_s32(mul_lo, 15); int16x4_t narrow_hi = vrshrn_n_s32(mul_hi, 15); // Join together return vreinterpretq_m128i_s16(vcombine_s16(narrow_lo, narrow_hi)); } // Multiply packed signed 16-bit integers in a and b, producing intermediate // signed 32-bit integers. Truncate each intermediate integer to the 18 most // significant bits, round by adding 1, and store bits [16:1] to dst. // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mulhrs_pi16 FORCE_INLINE __m64 _mm_mulhrs_pi16(__m64 a, __m64 b) { int32x4_t mul_extend = vmull_s16((vreinterpret_s16_m64(a)), (vreinterpret_s16_m64(b))); // Rounding narrowing shift right return vreinterpret_m64_s16(vrshrn_n_s32(mul_extend, 15)); } // Shuffle packed 8-bit integers in a according to shuffle control mask in the // corresponding 8-bit element of b, and store the results in dst. // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_shuffle_epi8 FORCE_INLINE __m128i _mm_shuffle_epi8(__m128i a, __m128i b) { int8x16_t tbl = vreinterpretq_s8_m128i(a); // input a uint8x16_t idx = vreinterpretq_u8_m128i(b); // input b uint8x16_t idx_masked = vandq_u8(idx, vdupq_n_u8(0x8F)); // avoid using meaningless bits #if defined(__aarch64__) return vreinterpretq_m128i_s8(vqtbl1q_s8(tbl, idx_masked)); #elif defined(__GNUC__) int8x16_t ret; // %e and %f represent the even and odd D registers // respectively. __asm__ __volatile__( "vtbl.8 %e[ret], {%e[tbl], %f[tbl]}, %e[idx]\n" "vtbl.8 %f[ret], {%e[tbl], %f[tbl]}, %f[idx]\n" : [ret] "=&w"(ret) : [tbl] "w"(tbl), [idx] "w"(idx_masked)); return vreinterpretq_m128i_s8(ret); #else // use this line if testing on aarch64 int8x8x2_t a_split = {vget_low_s8(tbl), vget_high_s8(tbl)}; return vreinterpretq_m128i_s8( vcombine_s8(vtbl2_s8(a_split, vget_low_u8(idx_masked)), vtbl2_s8(a_split, vget_high_u8(idx_masked)))); #endif } // Negate packed 16-bit integers in a when the corresponding signed // 16-bit integer in b is negative, and store the results in dst. // Element in dst are zeroed out when the corresponding element // in b is zero. // // for i in 0..7 // if b[i] < 0 // r[i] := -a[i] // else if b[i] == 0 // r[i] := 0 // else // r[i] := a[i] // fi // done FORCE_INLINE __m128i _mm_sign_epi16(__m128i _a, __m128i _b) { int16x8_t a = vreinterpretq_s16_m128i(_a); int16x8_t b = vreinterpretq_s16_m128i(_b); // signed shift right: faster than vclt // (b < 0) ? 0xFFFF : 0 uint16x8_t ltMask = vreinterpretq_u16_s16(vshrq_n_s16(b, 15)); // (b == 0) ? 0xFFFF : 0 #if defined(__aarch64__) int16x8_t zeroMask = vreinterpretq_s16_u16(vceqzq_s16(b)); #else int16x8_t zeroMask = vreinterpretq_s16_u16(vceqq_s16(b, vdupq_n_s16(0))); #endif // bitwise select either a or negative 'a' (vnegq_s16(a) equals to negative // 'a') based on ltMask int16x8_t masked = vbslq_s16(ltMask, vnegq_s16(a), a); // res = masked & (~zeroMask) int16x8_t res = vbicq_s16(masked, zeroMask); return vreinterpretq_m128i_s16(res); } // Negate packed 32-bit integers in a when the corresponding signed // 32-bit integer in b is negative, and store the results in dst. // Element in dst are zeroed out when the corresponding element // in b is zero. // // for i in 0..3 // if b[i] < 0 // r[i] := -a[i] // else if b[i] == 0 // r[i] := 0 // else // r[i] := a[i] // fi // done FORCE_INLINE __m128i _mm_sign_epi32(__m128i _a, __m128i _b) { int32x4_t a = vreinterpretq_s32_m128i(_a); int32x4_t b = vreinterpretq_s32_m128i(_b); // signed shift right: faster than vclt // (b < 0) ? 0xFFFFFFFF : 0 uint32x4_t ltMask = vreinterpretq_u32_s32(vshrq_n_s32(b, 31)); // (b == 0) ? 0xFFFFFFFF : 0 #if defined(__aarch64__) int32x4_t zeroMask = vreinterpretq_s32_u32(vceqzq_s32(b)); #else int32x4_t zeroMask = vreinterpretq_s32_u32(vceqq_s32(b, vdupq_n_s32(0))); #endif // bitwise select either a or negative 'a' (vnegq_s32(a) equals to negative // 'a') based on ltMask int32x4_t masked = vbslq_s32(ltMask, vnegq_s32(a), a); // res = masked & (~zeroMask) int32x4_t res = vbicq_s32(masked, zeroMask); return vreinterpretq_m128i_s32(res); } // Negate packed 8-bit integers in a when the corresponding signed // 8-bit integer in b is negative, and store the results in dst. // Element in dst are zeroed out when the corresponding element // in b is zero. // // for i in 0..15 // if b[i] < 0 // r[i] := -a[i] // else if b[i] == 0 // r[i] := 0 // else // r[i] := a[i] // fi // done FORCE_INLINE __m128i _mm_sign_epi8(__m128i _a, __m128i _b) { int8x16_t a = vreinterpretq_s8_m128i(_a); int8x16_t b = vreinterpretq_s8_m128i(_b); // signed shift right: faster than vclt // (b < 0) ? 0xFF : 0 uint8x16_t ltMask = vreinterpretq_u8_s8(vshrq_n_s8(b, 7)); // (b == 0) ? 0xFF : 0 #if defined(__aarch64__) int8x16_t zeroMask = vreinterpretq_s8_u8(vceqzq_s8(b)); #else int8x16_t zeroMask = vreinterpretq_s8_u8(vceqq_s8(b, vdupq_n_s8(0))); #endif // bitwise select either a or nagative 'a' (vnegq_s8(a) return nagative 'a') // based on ltMask int8x16_t masked = vbslq_s8(ltMask, vnegq_s8(a), a); // res = masked & (~zeroMask) int8x16_t res = vbicq_s8(masked, zeroMask); return vreinterpretq_m128i_s8(res); } // Negate packed 16-bit integers in a when the corresponding signed 16-bit // integer in b is negative, and store the results in dst. Element in dst are // zeroed out when the corresponding element in b is zero. // // FOR j := 0 to 3 // i := j*16 // IF b[i+15:i] < 0 // dst[i+15:i] := -(a[i+15:i]) // ELSE IF b[i+15:i] == 0 // dst[i+15:i] := 0 // ELSE // dst[i+15:i] := a[i+15:i] // FI // ENDFOR // // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_sign_pi16 FORCE_INLINE __m64 _mm_sign_pi16(__m64 _a, __m64 _b) { int16x4_t a = vreinterpret_s16_m64(_a); int16x4_t b = vreinterpret_s16_m64(_b); // signed shift right: faster than vclt // (b < 0) ? 0xFFFF : 0 uint16x4_t ltMask = vreinterpret_u16_s16(vshr_n_s16(b, 15)); // (b == 0) ? 0xFFFF : 0 #if defined(__aarch64__) int16x4_t zeroMask = vreinterpret_s16_u16(vceqz_s16(b)); #else int16x4_t zeroMask = vreinterpret_s16_u16(vceq_s16(b, vdup_n_s16(0))); #endif // bitwise select either a or nagative 'a' (vneg_s16(a) return nagative 'a') // based on ltMask int16x4_t masked = vbsl_s16(ltMask, vneg_s16(a), a); // res = masked & (~zeroMask) int16x4_t res = vbic_s16(masked, zeroMask); return vreinterpret_m64_s16(res); } // Negate packed 32-bit integers in a when the corresponding signed 32-bit // integer in b is negative, and store the results in dst. Element in dst are // zeroed out when the corresponding element in b is zero. // // FOR j := 0 to 1 // i := j*32 // IF b[i+31:i] < 0 // dst[i+31:i] := -(a[i+31:i]) // ELSE IF b[i+31:i] == 0 // dst[i+31:i] := 0 // ELSE // dst[i+31:i] := a[i+31:i] // FI // ENDFOR // // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_sign_pi32 FORCE_INLINE __m64 _mm_sign_pi32(__m64 _a, __m64 _b) { int32x2_t a = vreinterpret_s32_m64(_a); int32x2_t b = vreinterpret_s32_m64(_b); // signed shift right: faster than vclt // (b < 0) ? 0xFFFFFFFF : 0 uint32x2_t ltMask = vreinterpret_u32_s32(vshr_n_s32(b, 31)); // (b == 0) ? 0xFFFFFFFF : 0 #if defined(__aarch64__) int32x2_t zeroMask = vreinterpret_s32_u32(vceqz_s32(b)); #else int32x2_t zeroMask = vreinterpret_s32_u32(vceq_s32(b, vdup_n_s32(0))); #endif // bitwise select either a or nagative 'a' (vneg_s32(a) return nagative 'a') // based on ltMask int32x2_t masked = vbsl_s32(ltMask, vneg_s32(a), a); // res = masked & (~zeroMask) int32x2_t res = vbic_s32(masked, zeroMask); return vreinterpret_m64_s32(res); } // Negate packed 8-bit integers in a when the corresponding signed 8-bit integer // in b is negative, and store the results in dst. Element in dst are zeroed out // when the corresponding element in b is zero. // // FOR j := 0 to 7 // i := j*8 // IF b[i+7:i] < 0 // dst[i+7:i] := -(a[i+7:i]) // ELSE IF b[i+7:i] == 0 // dst[i+7:i] := 0 // ELSE // dst[i+7:i] := a[i+7:i] // FI // ENDFOR // // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_sign_pi8 FORCE_INLINE __m64 _mm_sign_pi8(__m64 _a, __m64 _b) { int8x8_t a = vreinterpret_s8_m64(_a); int8x8_t b = vreinterpret_s8_m64(_b); // signed shift right: faster than vclt // (b < 0) ? 0xFF : 0 uint8x8_t ltMask = vreinterpret_u8_s8(vshr_n_s8(b, 7)); // (b == 0) ? 0xFF : 0 #if defined(__aarch64__) int8x8_t zeroMask = vreinterpret_s8_u8(vceqz_s8(b)); #else int8x8_t zeroMask = vreinterpret_s8_u8(vceq_s8(b, vdup_n_s8(0))); #endif // bitwise select either a or nagative 'a' (vneg_s8(a) return nagative 'a') // based on ltMask int8x8_t masked = vbsl_s8(ltMask, vneg_s8(a), a); // res = masked & (~zeroMask) int8x8_t res = vbic_s8(masked, zeroMask); return vreinterpret_m64_s8(res); } /* SSE4.1 */ // Blend packed 16-bit integers from a and b using control mask imm8, and store // the results in dst. // // FOR j := 0 to 7 // i := j*16 // IF imm8[j] // dst[i+15:i] := b[i+15:i] // ELSE // dst[i+15:i] := a[i+15:i] // FI // ENDFOR // FORCE_INLINE __m128i _mm_blend_epi16(__m128i a, __m128i b, // __constrange(0,255) int imm) #define _mm_blend_epi16(a, b, imm) \ __extension__({ \ const uint16_t _mask[8] = {((imm) & (1 << 0)) ? (uint16_t) -1 : 0x0, \ ((imm) & (1 << 1)) ? (uint16_t) -1 : 0x0, \ ((imm) & (1 << 2)) ? (uint16_t) -1 : 0x0, \ ((imm) & (1 << 3)) ? (uint16_t) -1 : 0x0, \ ((imm) & (1 << 4)) ? (uint16_t) -1 : 0x0, \ ((imm) & (1 << 5)) ? (uint16_t) -1 : 0x0, \ ((imm) & (1 << 6)) ? (uint16_t) -1 : 0x0, \ ((imm) & (1 << 7)) ? (uint16_t) -1 : 0x0}; \ uint16x8_t _mask_vec = vld1q_u16(_mask); \ uint16x8_t _a = vreinterpretq_u16_m128i(a); \ uint16x8_t _b = vreinterpretq_u16_m128i(b); \ vreinterpretq_m128i_u16(vbslq_u16(_mask_vec, _b, _a)); \ }) // Blend packed double-precision (64-bit) floating-point elements from a and b // using control mask imm8, and store the results in dst. // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_blend_pd #define _mm_blend_pd(a, b, imm) \ __extension__({ \ const uint64_t _mask[2] = { \ ((imm) & (1 << 0)) ? ~UINT64_C(0) : UINT64_C(0), \ ((imm) & (1 << 1)) ? ~UINT64_C(0) : UINT64_C(0)}; \ uint64x2_t _mask_vec = vld1q_u64(_mask); \ uint64x2_t _a = vreinterpretq_u64_m128d(a); \ uint64x2_t _b = vreinterpretq_u64_m128d(b); \ vreinterpretq_m128d_u64(vbslq_u64(_mask_vec, _b, _a)); \ }) // Blend packed single-precision (32-bit) floating-point elements from a and b // using mask, and store the results in dst. // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_blend_ps FORCE_INLINE __m128 _mm_blend_ps(__m128 _a, __m128 _b, const char imm8) { const uint32_t ALIGN_STRUCT(16) data[4] = {((imm8) & (1 << 0)) ? UINT32_MAX : 0, ((imm8) & (1 << 1)) ? UINT32_MAX : 0, ((imm8) & (1 << 2)) ? UINT32_MAX : 0, ((imm8) & (1 << 3)) ? UINT32_MAX : 0}; uint32x4_t mask = vld1q_u32(data); float32x4_t a = vreinterpretq_f32_m128(_a); float32x4_t b = vreinterpretq_f32_m128(_b); return vreinterpretq_m128_f32(vbslq_f32(mask, b, a)); } // Blend packed 8-bit integers from a and b using mask, and store the results in // dst. // // FOR j := 0 to 15 // i := j*8 // IF mask[i+7] // dst[i+7:i] := b[i+7:i] // ELSE // dst[i+7:i] := a[i+7:i] // FI // ENDFOR FORCE_INLINE __m128i _mm_blendv_epi8(__m128i _a, __m128i _b, __m128i _mask) { // Use a signed shift right to create a mask with the sign bit uint8x16_t mask = vreinterpretq_u8_s8(vshrq_n_s8(vreinterpretq_s8_m128i(_mask), 7)); uint8x16_t a = vreinterpretq_u8_m128i(_a); uint8x16_t b = vreinterpretq_u8_m128i(_b); return vreinterpretq_m128i_u8(vbslq_u8(mask, b, a)); } // Blend packed double-precision (64-bit) floating-point elements from a and b // using mask, and store the results in dst. // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_blendv_pd FORCE_INLINE __m128d _mm_blendv_pd(__m128d _a, __m128d _b, __m128d _mask) { uint64x2_t mask = vreinterpretq_u64_s64(vshrq_n_s64(vreinterpretq_s64_m128d(_mask), 63)); #if defined(__aarch64__) float64x2_t a = vreinterpretq_f64_m128d(_a); float64x2_t b = vreinterpretq_f64_m128d(_b); return vreinterpretq_m128d_f64(vbslq_f64(mask, b, a)); #else uint64x2_t a = vreinterpretq_u64_m128d(_a); uint64x2_t b = vreinterpretq_u64_m128d(_b); return vreinterpretq_m128d_u64(vbslq_u64(mask, b, a)); #endif } // Blend packed single-precision (32-bit) floating-point elements from a and b // using mask, and store the results in dst. // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_blendv_ps FORCE_INLINE __m128 _mm_blendv_ps(__m128 _a, __m128 _b, __m128 _mask) { // Use a signed shift right to create a mask with the sign bit uint32x4_t mask = vreinterpretq_u32_s32(vshrq_n_s32(vreinterpretq_s32_m128(_mask), 31)); float32x4_t a = vreinterpretq_f32_m128(_a); float32x4_t b = vreinterpretq_f32_m128(_b); return vreinterpretq_m128_f32(vbslq_f32(mask, b, a)); } // Round the packed double-precision (64-bit) floating-point elements in a up // to an integer value, and store the results as packed double-precision // floating-point elements in dst. // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_ceil_pd FORCE_INLINE __m128d _mm_ceil_pd(__m128d a) { #if defined(__aarch64__) return vreinterpretq_m128d_f64(vrndpq_f64(vreinterpretq_f64_m128d(a))); #else double *f = (double *) &a; return _mm_set_pd(ceil(f[1]), ceil(f[0])); #endif } // Round the packed single-precision (32-bit) floating-point elements in a up to // an integer value, and store the results as packed single-precision // floating-point elements in dst. // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_ceil_ps FORCE_INLINE __m128 _mm_ceil_ps(__m128 a) { #if defined(__aarch64__) return vreinterpretq_m128_f32(vrndpq_f32(vreinterpretq_f32_m128(a))); #else float *f = (float *) &a; return _mm_set_ps(ceilf(f[3]), ceilf(f[2]), ceilf(f[1]), ceilf(f[0])); #endif } // Round the lower double-precision (64-bit) floating-point element in b up to // an integer value, store the result as a double-precision floating-point // element in the lower element of dst, and copy the upper element from a to the // upper element of dst. // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_ceil_sd FORCE_INLINE __m128d _mm_ceil_sd(__m128d a, __m128d b) { return _mm_move_sd(a, _mm_ceil_pd(b)); } // Round the lower single-precision (32-bit) floating-point element in b up to // an integer value, store the result as a single-precision floating-point // element in the lower element of dst, and copy the upper 3 packed elements // from a to the upper elements of dst. // // dst[31:0] := CEIL(b[31:0]) // dst[127:32] := a[127:32] // // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_ceil_ss FORCE_INLINE __m128 _mm_ceil_ss(__m128 a, __m128 b) { return _mm_move_ss(a, _mm_ceil_ps(b)); } // Compare packed 64-bit integers in a and b for equality, and store the results // in dst FORCE_INLINE __m128i _mm_cmpeq_epi64(__m128i a, __m128i b) { #if defined(__aarch64__) return vreinterpretq_m128i_u64( vceqq_u64(vreinterpretq_u64_m128i(a), vreinterpretq_u64_m128i(b))); #else // ARMv7 lacks vceqq_u64 // (a == b) -> (a_lo == b_lo) && (a_hi == b_hi) uint32x4_t cmp = vceqq_u32(vreinterpretq_u32_m128i(a), vreinterpretq_u32_m128i(b)); uint32x4_t swapped = vrev64q_u32(cmp); return vreinterpretq_m128i_u32(vandq_u32(cmp, swapped)); #endif } // Converts the four signed 16-bit integers in the lower 64 bits to four signed // 32-bit integers. FORCE_INLINE __m128i _mm_cvtepi16_epi32(__m128i a) { return vreinterpretq_m128i_s32( vmovl_s16(vget_low_s16(vreinterpretq_s16_m128i(a)))); } // Converts the two signed 16-bit integers in the lower 32 bits two signed // 32-bit integers. FORCE_INLINE __m128i _mm_cvtepi16_epi64(__m128i a) { int16x8_t s16x8 = vreinterpretq_s16_m128i(a); /* xxxx xxxx xxxx 0B0A */ int32x4_t s32x4 = vmovl_s16(vget_low_s16(s16x8)); /* 000x 000x 000B 000A */ int64x2_t s64x2 = vmovl_s32(vget_low_s32(s32x4)); /* 0000 000B 0000 000A */ return vreinterpretq_m128i_s64(s64x2); } // Converts the two signed 32-bit integers in the lower 64 bits to two signed // 64-bit integers. FORCE_INLINE __m128i _mm_cvtepi32_epi64(__m128i a) { return vreinterpretq_m128i_s64( vmovl_s32(vget_low_s32(vreinterpretq_s32_m128i(a)))); } // Converts the four unsigned 8-bit integers in the lower 16 bits to four // unsigned 32-bit integers. FORCE_INLINE __m128i _mm_cvtepi8_epi16(__m128i a) { int8x16_t s8x16 = vreinterpretq_s8_m128i(a); /* xxxx xxxx xxxx DCBA */ int16x8_t s16x8 = vmovl_s8(vget_low_s8(s8x16)); /* 0x0x 0x0x 0D0C 0B0A */ return vreinterpretq_m128i_s16(s16x8); } // Converts the four unsigned 8-bit integers in the lower 32 bits to four // unsigned 32-bit integers. FORCE_INLINE __m128i _mm_cvtepi8_epi32(__m128i a) { int8x16_t s8x16 = vreinterpretq_s8_m128i(a); /* xxxx xxxx xxxx DCBA */ int16x8_t s16x8 = vmovl_s8(vget_low_s8(s8x16)); /* 0x0x 0x0x 0D0C 0B0A */ int32x4_t s32x4 = vmovl_s16(vget_low_s16(s16x8)); /* 000D 000C 000B 000A */ return vreinterpretq_m128i_s32(s32x4); } // Converts the two signed 8-bit integers in the lower 32 bits to four // signed 64-bit integers. FORCE_INLINE __m128i _mm_cvtepi8_epi64(__m128i a) { int8x16_t s8x16 = vreinterpretq_s8_m128i(a); /* xxxx xxxx xxxx xxBA */ int16x8_t s16x8 = vmovl_s8(vget_low_s8(s8x16)); /* 0x0x 0x0x 0x0x 0B0A */ int32x4_t s32x4 = vmovl_s16(vget_low_s16(s16x8)); /* 000x 000x 000B 000A */ int64x2_t s64x2 = vmovl_s32(vget_low_s32(s32x4)); /* 0000 000B 0000 000A */ return vreinterpretq_m128i_s64(s64x2); } // Converts the four unsigned 16-bit integers in the lower 64 bits to four // unsigned 32-bit integers. FORCE_INLINE __m128i _mm_cvtepu16_epi32(__m128i a) { return vreinterpretq_m128i_u32( vmovl_u16(vget_low_u16(vreinterpretq_u16_m128i(a)))); } // Converts the two unsigned 16-bit integers in the lower 32 bits to two // unsigned 64-bit integers. FORCE_INLINE __m128i _mm_cvtepu16_epi64(__m128i a) { uint16x8_t u16x8 = vreinterpretq_u16_m128i(a); /* xxxx xxxx xxxx 0B0A */ uint32x4_t u32x4 = vmovl_u16(vget_low_u16(u16x8)); /* 000x 000x 000B 000A */ uint64x2_t u64x2 = vmovl_u32(vget_low_u32(u32x4)); /* 0000 000B 0000 000A */ return vreinterpretq_m128i_u64(u64x2); } // Converts the two unsigned 32-bit integers in the lower 64 bits to two // unsigned 64-bit integers. FORCE_INLINE __m128i _mm_cvtepu32_epi64(__m128i a) { return vreinterpretq_m128i_u64( vmovl_u32(vget_low_u32(vreinterpretq_u32_m128i(a)))); } // Zero extend packed unsigned 8-bit integers in a to packed 16-bit integers, // and store the results in dst. // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtepu8_epi16 FORCE_INLINE __m128i _mm_cvtepu8_epi16(__m128i a) { uint8x16_t u8x16 = vreinterpretq_u8_m128i(a); /* xxxx xxxx HGFE DCBA */ uint16x8_t u16x8 = vmovl_u8(vget_low_u8(u8x16)); /* 0H0G 0F0E 0D0C 0B0A */ return vreinterpretq_m128i_u16(u16x8); } // Converts the four unsigned 8-bit integers in the lower 32 bits to four // unsigned 32-bit integers. // https://msdn.microsoft.com/en-us/library/bb531467%28v=vs.100%29.aspx FORCE_INLINE __m128i _mm_cvtepu8_epi32(__m128i a) { uint8x16_t u8x16 = vreinterpretq_u8_m128i(a); /* xxxx xxxx xxxx DCBA */ uint16x8_t u16x8 = vmovl_u8(vget_low_u8(u8x16)); /* 0x0x 0x0x 0D0C 0B0A */ uint32x4_t u32x4 = vmovl_u16(vget_low_u16(u16x8)); /* 000D 000C 000B 000A */ return vreinterpretq_m128i_u32(u32x4); } // Converts the two unsigned 8-bit integers in the lower 16 bits to two // unsigned 64-bit integers. FORCE_INLINE __m128i _mm_cvtepu8_epi64(__m128i a) { uint8x16_t u8x16 = vreinterpretq_u8_m128i(a); /* xxxx xxxx xxxx xxBA */ uint16x8_t u16x8 = vmovl_u8(vget_low_u8(u8x16)); /* 0x0x 0x0x 0x0x 0B0A */ uint32x4_t u32x4 = vmovl_u16(vget_low_u16(u16x8)); /* 000x 000x 000B 000A */ uint64x2_t u64x2 = vmovl_u32(vget_low_u32(u32x4)); /* 0000 000B 0000 000A */ return vreinterpretq_m128i_u64(u64x2); } // Conditionally multiply the packed single-precision (32-bit) floating-point // elements in a and b using the high 4 bits in imm8, sum the four products, // and conditionally store the sum in dst using the low 4 bits of imm. // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_dp_ps FORCE_INLINE __m128 _mm_dp_ps(__m128 a, __m128 b, const int imm) { #if defined(__aarch64__) /* shortcuts */ if (imm == 0xFF) { return _mm_set1_ps(vaddvq_f32(_mm_mul_ps(a, b))); } if (imm == 0x7F) { float32x4_t m = _mm_mul_ps(a, b); m[3] = 0; return _mm_set1_ps(vaddvq_f32(m)); } #endif float s = 0, c = 0; float32x4_t f32a = vreinterpretq_f32_m128(a); float32x4_t f32b = vreinterpretq_f32_m128(b); /* To improve the accuracy of floating-point summation, Kahan algorithm * is used for each operation. */ if (imm & (1 << 4)) _sse2neon_kadd_f32(&s, &c, f32a[0] * f32b[0]); if (imm & (1 << 5)) _sse2neon_kadd_f32(&s, &c, f32a[1] * f32b[1]); if (imm & (1 << 6)) _sse2neon_kadd_f32(&s, &c, f32a[2] * f32b[2]); if (imm & (1 << 7)) _sse2neon_kadd_f32(&s, &c, f32a[3] * f32b[3]); s += c; float32x4_t res = { (imm & 0x1) ? s : 0, (imm & 0x2) ? s : 0, (imm & 0x4) ? s : 0, (imm & 0x8) ? s : 0, }; return vreinterpretq_m128_f32(res); } // Extracts the selected signed or unsigned 32-bit integer from a and zero // extends. // FORCE_INLINE int _mm_extract_epi32(__m128i a, __constrange(0,4) int imm) #define _mm_extract_epi32(a, imm) \ vgetq_lane_s32(vreinterpretq_s32_m128i(a), (imm)) // Extracts the selected signed or unsigned 64-bit integer from a and zero // extends. // FORCE_INLINE __int64 _mm_extract_epi64(__m128i a, __constrange(0,2) int imm) #define _mm_extract_epi64(a, imm) \ vgetq_lane_s64(vreinterpretq_s64_m128i(a), (imm)) // Extracts the selected signed or unsigned 8-bit integer from a and zero // extends. // FORCE_INLINE int _mm_extract_epi8(__m128i a, __constrange(0,16) int imm) // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_extract_epi8 #define _mm_extract_epi8(a, imm) vgetq_lane_u8(vreinterpretq_u8_m128i(a), (imm)) // Extracts the selected single-precision (32-bit) floating-point from a. // FORCE_INLINE int _mm_extract_ps(__m128 a, __constrange(0,4) int imm) #define _mm_extract_ps(a, imm) vgetq_lane_s32(vreinterpretq_s32_m128(a), (imm)) // Round the packed double-precision (64-bit) floating-point elements in a down // to an integer value, and store the results as packed double-precision // floating-point elements in dst. // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_floor_pd FORCE_INLINE __m128d _mm_floor_pd(__m128d a) { #if defined(__aarch64__) return vreinterpretq_m128d_f64(vrndmq_f64(vreinterpretq_f64_m128d(a))); #else double *f = (double *) &a; return _mm_set_pd(floor(f[1]), floor(f[0])); #endif } // Round the packed single-precision (32-bit) floating-point elements in a down // to an integer value, and store the results as packed single-precision // floating-point elements in dst. // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_floor_ps FORCE_INLINE __m128 _mm_floor_ps(__m128 a) { #if defined(__aarch64__) return vreinterpretq_m128_f32(vrndmq_f32(vreinterpretq_f32_m128(a))); #else float *f = (float *) &a; return _mm_set_ps(floorf(f[3]), floorf(f[2]), floorf(f[1]), floorf(f[0])); #endif } // Round the lower double-precision (64-bit) floating-point element in b down to // an integer value, store the result as a double-precision floating-point // element in the lower element of dst, and copy the upper element from a to the // upper element of dst. // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_floor_sd FORCE_INLINE __m128d _mm_floor_sd(__m128d a, __m128d b) { return _mm_move_sd(a, _mm_floor_pd(b)); } // Round the lower single-precision (32-bit) floating-point element in b down to // an integer value, store the result as a single-precision floating-point // element in the lower element of dst, and copy the upper 3 packed elements // from a to the upper elements of dst. // // dst[31:0] := FLOOR(b[31:0]) // dst[127:32] := a[127:32] // // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_floor_ss FORCE_INLINE __m128 _mm_floor_ss(__m128 a, __m128 b) { return _mm_move_ss(a, _mm_floor_ps(b)); } // Inserts the least significant 32 bits of b into the selected 32-bit integer // of a. // FORCE_INLINE __m128i _mm_insert_epi32(__m128i a, int b, // __constrange(0,4) int imm) #define _mm_insert_epi32(a, b, imm) \ __extension__({ \ vreinterpretq_m128i_s32( \ vsetq_lane_s32((b), vreinterpretq_s32_m128i(a), (imm))); \ }) // Inserts the least significant 64 bits of b into the selected 64-bit integer // of a. // FORCE_INLINE __m128i _mm_insert_epi64(__m128i a, __int64 b, // __constrange(0,2) int imm) #define _mm_insert_epi64(a, b, imm) \ __extension__({ \ vreinterpretq_m128i_s64( \ vsetq_lane_s64((b), vreinterpretq_s64_m128i(a), (imm))); \ }) // Inserts the least significant 8 bits of b into the selected 8-bit integer // of a. // FORCE_INLINE __m128i _mm_insert_epi8(__m128i a, int b, // __constrange(0,16) int imm) #define _mm_insert_epi8(a, b, imm) \ __extension__({ \ vreinterpretq_m128i_s8( \ vsetq_lane_s8((b), vreinterpretq_s8_m128i(a), (imm))); \ }) // Copy a to tmp, then insert a single-precision (32-bit) floating-point // element from b into tmp using the control in imm8. Store tmp to dst using // the mask in imm8 (elements are zeroed out when the corresponding bit is set). // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=insert_ps #define _mm_insert_ps(a, b, imm8) \ __extension__({ \ float32x4_t tmp1 = vsetq_lane_f32(vgetq_lane_f32(b, (imm >> 6) & 0x3), \ vreinterpretq_f32_m128(a), 0); \ float32x4_t tmp2 = \ vsetq_lane_f32(vgetq_lane_f32(tmp1, 0), vreinterpretq_f32_m128(a), \ ((imm >> 4) & 0x3)); \ const uint32_t data[4] = {((imm8) & (1 << 0)) ? UINT32_MAX : 0, \ ((imm8) & (1 << 1)) ? UINT32_MAX : 0, \ ((imm8) & (1 << 2)) ? UINT32_MAX : 0, \ ((imm8) & (1 << 3)) ? UINT32_MAX : 0}; \ uint32x4_t mask = vld1q_u32(data); \ float32x4_t all_zeros = vdupq_n_f32(0); \ \ vreinterpretq_m128_f32( \ vbslq_f32(mask, all_zeros, vreinterpretq_f32_m128(tmp2))); \ }) // epi versions of min/max // Computes the pariwise maximums of the four signed 32-bit integer values of a // and b. // // A 128-bit parameter that can be defined with the following equations: // r0 := (a0 > b0) ? a0 : b0 // r1 := (a1 > b1) ? a1 : b1 // r2 := (a2 > b2) ? a2 : b2 // r3 := (a3 > b3) ? a3 : b3 // // https://msdn.microsoft.com/en-us/library/vstudio/bb514055(v=vs.100).aspx FORCE_INLINE __m128i _mm_max_epi32(__m128i a, __m128i b) { return vreinterpretq_m128i_s32( vmaxq_s32(vreinterpretq_s32_m128i(a), vreinterpretq_s32_m128i(b))); } // Compare packed signed 8-bit integers in a and b, and store packed maximum // values in dst. // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_max_epi8 FORCE_INLINE __m128i _mm_max_epi8(__m128i a, __m128i b) { return vreinterpretq_m128i_s8( vmaxq_s8(vreinterpretq_s8_m128i(a), vreinterpretq_s8_m128i(b))); } // Compare packed unsigned 16-bit integers in a and b, and store packed maximum // values in dst. // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_max_epu16 FORCE_INLINE __m128i _mm_max_epu16(__m128i a, __m128i b) { return vreinterpretq_m128i_u16( vmaxq_u16(vreinterpretq_u16_m128i(a), vreinterpretq_u16_m128i(b))); } // Compare packed unsigned 32-bit integers in a and b, and store packed maximum // values in dst. // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_max_epu32 FORCE_INLINE __m128i _mm_max_epu32(__m128i a, __m128i b) { return vreinterpretq_m128i_u32( vmaxq_u32(vreinterpretq_u32_m128i(a), vreinterpretq_u32_m128i(b))); } // Computes the pariwise minima of the four signed 32-bit integer values of a // and b. // // A 128-bit parameter that can be defined with the following equations: // r0 := (a0 < b0) ? a0 : b0 // r1 := (a1 < b1) ? a1 : b1 // r2 := (a2 < b2) ? a2 : b2 // r3 := (a3 < b3) ? a3 : b3 // // https://msdn.microsoft.com/en-us/library/vstudio/bb531476(v=vs.100).aspx FORCE_INLINE __m128i _mm_min_epi32(__m128i a, __m128i b) { return vreinterpretq_m128i_s32( vminq_s32(vreinterpretq_s32_m128i(a), vreinterpretq_s32_m128i(b))); } // Compare packed signed 8-bit integers in a and b, and store packed minimum // values in dst. // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_min_epi8 FORCE_INLINE __m128i _mm_min_epi8(__m128i a, __m128i b) { return vreinterpretq_m128i_s8( vminq_s8(vreinterpretq_s8_m128i(a), vreinterpretq_s8_m128i(b))); } // Compare packed unsigned 16-bit integers in a and b, and store packed minimum // values in dst. // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_min_epu16 FORCE_INLINE __m128i _mm_min_epu16(__m128i a, __m128i b) { return vreinterpretq_m128i_u16( vminq_u16(vreinterpretq_u16_m128i(a), vreinterpretq_u16_m128i(b))); } // Compare packed unsigned 32-bit integers in a and b, and store packed minimum // values in dst. // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_max_epu32 FORCE_INLINE __m128i _mm_min_epu32(__m128i a, __m128i b) { return vreinterpretq_m128i_u32( vminq_u32(vreinterpretq_u32_m128i(a), vreinterpretq_u32_m128i(b))); } // Horizontally compute the minimum amongst the packed unsigned 16-bit integers // in a, store the minimum and index in dst, and zero the remaining bits in dst. // // index[2:0] := 0 // min[15:0] := a[15:0] // FOR j := 0 to 7 // i := j*16 // IF a[i+15:i] < min[15:0] // index[2:0] := j // min[15:0] := a[i+15:i] // FI // ENDFOR // dst[15:0] := min[15:0] // dst[18:16] := index[2:0] // dst[127:19] := 0 // // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_minpos_epu16 FORCE_INLINE __m128i _mm_minpos_epu16(__m128i a) { __m128i dst; uint16_t min, idx = 0; // Find the minimum value #if defined(__aarch64__) min = vminvq_u16(vreinterpretq_u16_m128i(a)); #else __m64 tmp; tmp = vreinterpret_m64_u16( vmin_u16(vget_low_u16(vreinterpretq_u16_m128i(a)), vget_high_u16(vreinterpretq_u16_m128i(a)))); tmp = vreinterpret_m64_u16( vpmin_u16(vreinterpret_u16_m64(tmp), vreinterpret_u16_m64(tmp))); tmp = vreinterpret_m64_u16( vpmin_u16(vreinterpret_u16_m64(tmp), vreinterpret_u16_m64(tmp))); min = vget_lane_u16(vreinterpret_u16_m64(tmp), 0); #endif // Get the index of the minimum value int i; for (i = 0; i < 8; i++) { if (min == vgetq_lane_u16(vreinterpretq_u16_m128i(a), 0)) { idx = (uint16_t) i; break; } a = _mm_srli_si128(a, 2); } // Generate result dst = _mm_setzero_si128(); dst = vreinterpretq_m128i_u16( vsetq_lane_u16(min, vreinterpretq_u16_m128i(dst), 0)); dst = vreinterpretq_m128i_u16( vsetq_lane_u16(idx, vreinterpretq_u16_m128i(dst), 1)); return dst; } // Multiply the low signed 32-bit integers from each packed 64-bit element in // a and b, and store the signed 64-bit results in dst. // // r0 := (int64_t)(int32_t)a0 * (int64_t)(int32_t)b0 // r1 := (int64_t)(int32_t)a2 * (int64_t)(int32_t)b2 FORCE_INLINE __m128i _mm_mul_epi32(__m128i a, __m128i b) { // vmull_s32 upcasts instead of masking, so we downcast. int32x2_t a_lo = vmovn_s64(vreinterpretq_s64_m128i(a)); int32x2_t b_lo = vmovn_s64(vreinterpretq_s64_m128i(b)); return vreinterpretq_m128i_s64(vmull_s32(a_lo, b_lo)); } // Multiplies the 4 signed or unsigned 32-bit integers from a by the 4 signed or // unsigned 32-bit integers from b. // https://msdn.microsoft.com/en-us/library/vstudio/bb531409(v=vs.100).aspx FORCE_INLINE __m128i _mm_mullo_epi32(__m128i a, __m128i b) { return vreinterpretq_m128i_s32( vmulq_s32(vreinterpretq_s32_m128i(a), vreinterpretq_s32_m128i(b))); } // Packs the 8 unsigned 32-bit integers from a and b into unsigned 16-bit // integers and saturates. // // r0 := UnsignedSaturate(a0) // r1 := UnsignedSaturate(a1) // r2 := UnsignedSaturate(a2) // r3 := UnsignedSaturate(a3) // r4 := UnsignedSaturate(b0) // r5 := UnsignedSaturate(b1) // r6 := UnsignedSaturate(b2) // r7 := UnsignedSaturate(b3) FORCE_INLINE __m128i _mm_packus_epi32(__m128i a, __m128i b) { return vreinterpretq_m128i_u16( vcombine_u16(vqmovun_s32(vreinterpretq_s32_m128i(a)), vqmovun_s32(vreinterpretq_s32_m128i(b)))); } // Round the packed double-precision (64-bit) floating-point elements in a using // the rounding parameter, and store the results as packed double-precision // floating-point elements in dst. // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_round_pd FORCE_INLINE __m128d _mm_round_pd(__m128d a, int rounding) { #if defined(__aarch64__) switch (rounding) { case (_MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC): return vreinterpretq_m128d_f64(vrndnq_f64(vreinterpretq_f64_m128d(a))); case (_MM_FROUND_TO_NEG_INF | _MM_FROUND_NO_EXC): return _mm_floor_pd(a); case (_MM_FROUND_TO_POS_INF | _MM_FROUND_NO_EXC): return _mm_ceil_pd(a); case (_MM_FROUND_TO_ZERO | _MM_FROUND_NO_EXC): return vreinterpretq_m128d_f64(vrndq_f64(vreinterpretq_f64_m128d(a))); default: //_MM_FROUND_CUR_DIRECTION return vreinterpretq_m128d_f64(vrndiq_f64(vreinterpretq_f64_m128d(a))); } #else double *v_double = (double *) &a; if (rounding == (_MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC) || (rounding == _MM_FROUND_CUR_DIRECTION && _MM_GET_ROUNDING_MODE() == _MM_ROUND_NEAREST)) { double res[2], tmp; for (int i = 0; i < 2; i++) { tmp = (v_double[i] < 0) ? -v_double[i] : v_double[i]; double roundDown = floor(tmp); // Round down value double roundUp = ceil(tmp); // Round up value double diffDown = tmp - roundDown; double diffUp = roundUp - tmp; if (diffDown < diffUp) { /* If it's closer to the round down value, then use it */ res[i] = roundDown; } else if (diffDown > diffUp) { /* If it's closer to the round up value, then use it */ res[i] = roundUp; } else { /* If it's equidistant between round up and round down value, * pick the one which is an even number */ double half = roundDown / 2; if (half != floor(half)) { /* If the round down value is odd, return the round up value */ res[i] = roundUp; } else { /* If the round up value is odd, return the round down value */ res[i] = roundDown; } } res[i] = (v_double[i] < 0) ? -res[i] : res[i]; } return _mm_set_pd(res[1], res[0]); } else if (rounding == (_MM_FROUND_TO_NEG_INF | _MM_FROUND_NO_EXC) || (rounding == _MM_FROUND_CUR_DIRECTION && _MM_GET_ROUNDING_MODE() == _MM_ROUND_DOWN)) { return _mm_floor_pd(a); } else if (rounding == (_MM_FROUND_TO_POS_INF | _MM_FROUND_NO_EXC) || (rounding == _MM_FROUND_CUR_DIRECTION && _MM_GET_ROUNDING_MODE() == _MM_ROUND_UP)) { return _mm_ceil_pd(a); } return _mm_set_pd(v_double[1] > 0 ? floor(v_double[1]) : ceil(v_double[1]), v_double[0] > 0 ? floor(v_double[0]) : ceil(v_double[0])); #endif } // Round the packed single-precision (32-bit) floating-point elements in a using // the rounding parameter, and store the results as packed single-precision // floating-point elements in dst. // software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_round_ps FORCE_INLINE __m128 _mm_round_ps(__m128 a, int rounding) { #if defined(__aarch64__) switch (rounding) { case (_MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC): return vreinterpretq_m128_f32(vrndnq_f32(vreinterpretq_f32_m128(a))); case (_MM_FROUND_TO_NEG_INF | _MM_FROUND_NO_EXC): return _mm_floor_ps(a); case (_MM_FROUND_TO_POS_INF | _MM_FROUND_NO_EXC): return _mm_ceil_ps(a); case (_MM_FROUND_TO_ZERO | _MM_FROUND_NO_EXC): return vreinterpretq_m128_f32(vrndq_f32(vreinterpretq_f32_m128(a))); default: //_MM_FROUND_CUR_DIRECTION return vreinterpretq_m128_f32(vrndiq_f32(vreinterpretq_f32_m128(a))); } #else float *v_float = (float *) &a; if (rounding == (_MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC) || (rounding == _MM_FROUND_CUR_DIRECTION && _MM_GET_ROUNDING_MODE() == _MM_ROUND_NEAREST)) { uint32x4_t signmask = vdupq_n_u32(0x80000000); float32x4_t half = vbslq_f32(signmask, vreinterpretq_f32_m128(a), vdupq_n_f32(0.5f)); /* +/- 0.5 */ int32x4_t r_normal = vcvtq_s32_f32(vaddq_f32( vreinterpretq_f32_m128(a), half)); /* round to integer: [a + 0.5]*/ int32x4_t r_trunc = vcvtq_s32_f32( vreinterpretq_f32_m128(a)); /* truncate to integer: [a] */ int32x4_t plusone = vreinterpretq_s32_u32(vshrq_n_u32( vreinterpretq_u32_s32(vnegq_s32(r_trunc)), 31)); /* 1 or 0 */ int32x4_t r_even = vbicq_s32(vaddq_s32(r_trunc, plusone), vdupq_n_s32(1)); /* ([a] + {0,1}) & ~1 */ float32x4_t delta = vsubq_f32( vreinterpretq_f32_m128(a), vcvtq_f32_s32(r_trunc)); /* compute delta: delta = (a - [a]) */ uint32x4_t is_delta_half = vceqq_f32(delta, half); /* delta == +/- 0.5 */ return vreinterpretq_m128_f32( vcvtq_f32_s32(vbslq_s32(is_delta_half, r_even, r_normal))); } else if (rounding == (_MM_FROUND_TO_NEG_INF | _MM_FROUND_NO_EXC) || (rounding == _MM_FROUND_CUR_DIRECTION && _MM_GET_ROUNDING_MODE() == _MM_ROUND_DOWN)) { return _mm_floor_ps(a); } else if (rounding == (_MM_FROUND_TO_POS_INF | _MM_FROUND_NO_EXC) || (rounding == _MM_FROUND_CUR_DIRECTION && _MM_GET_ROUNDING_MODE() == _MM_ROUND_UP)) { return _mm_ceil_ps(a); } return _mm_set_ps(v_float[3] > 0 ? floorf(v_float[3]) : ceilf(v_float[3]), v_float[2] > 0 ? floorf(v_float[2]) : ceilf(v_float[2]), v_float[1] > 0 ? floorf(v_float[1]) : ceilf(v_float[1]), v_float[0] > 0 ? floorf(v_float[0]) : ceilf(v_float[0])); #endif } // Round the lower double-precision (64-bit) floating-point element in b using // the rounding parameter, store the result as a double-precision floating-point // element in the lower element of dst, and copy the upper element from a to the // upper element of dst. // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_round_sd FORCE_INLINE __m128d _mm_round_sd(__m128d a, __m128d b, int rounding) { return _mm_move_sd(a, _mm_round_pd(b, rounding)); } // Round the lower single-precision (32-bit) floating-point element in b using // the rounding parameter, store the result as a single-precision floating-point // element in the lower element of dst, and copy the upper 3 packed elements // from a to the upper elements of dst. Rounding is done according to the // rounding[3:0] parameter, which can be one of: // (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and // suppress exceptions // (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and // suppress exceptions // (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress // exceptions // (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress // exceptions _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see // _MM_SET_ROUNDING_MODE // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_round_ss FORCE_INLINE __m128 _mm_round_ss(__m128 a, __m128 b, int rounding) { return _mm_move_ss(a, _mm_round_ps(b, rounding)); } // Load 128-bits of integer data from memory into dst using a non-temporal // memory hint. mem_addr must be aligned on a 16-byte boundary or a // general-protection exception may be generated. // // dst[127:0] := MEM[mem_addr+127:mem_addr] // // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_stream_load_si128 FORCE_INLINE __m128i _mm_stream_load_si128(__m128i *p) { #if __has_builtin(__builtin_nontemporal_store) return __builtin_nontemporal_load(p); #else return vreinterpretq_m128i_s64(vld1q_s64((int64_t *) p)); #endif } // Compute the bitwise NOT of a and then AND with a 128-bit vector containing // all 1's, and return 1 if the result is zero, otherwise return 0. // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_test_all_ones FORCE_INLINE int _mm_test_all_ones(__m128i a) { return (uint64_t)(vgetq_lane_s64(a, 0) & vgetq_lane_s64(a, 1)) == ~(uint64_t) 0; } // Compute the bitwise AND of 128 bits (representing integer data) in a and // mask, and return 1 if the result is zero, otherwise return 0. // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_test_all_zeros FORCE_INLINE int _mm_test_all_zeros(__m128i a, __m128i mask) { int64x2_t a_and_mask = vandq_s64(vreinterpretq_s64_m128i(a), vreinterpretq_s64_m128i(mask)); return !(vgetq_lane_s64(a_and_mask, 0) | vgetq_lane_s64(a_and_mask, 1)); } // Compute the bitwise AND of 128 bits (representing integer data) in a and // mask, and set ZF to 1 if the result is zero, otherwise set ZF to 0. Compute // the bitwise NOT of a and then AND with mask, and set CF to 1 if the result is // zero, otherwise set CF to 0. Return 1 if both the ZF and CF values are zero, // otherwise return 0. // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_test_mix_ones_zero FORCE_INLINE int _mm_test_mix_ones_zeros(__m128i a, __m128i mask) { uint64x2_t zf = vandq_u64(vreinterpretq_u64_m128i(mask), vreinterpretq_u64_m128i(a)); uint64x2_t cf = vbicq_u64(vreinterpretq_u64_m128i(mask), vreinterpretq_u64_m128i(a)); uint64x2_t result = vandq_u64(zf, cf); return !(vgetq_lane_u64(result, 0) | vgetq_lane_u64(result, 1)); } // Compute the bitwise AND of 128 bits (representing integer data) in a and b, // and set ZF to 1 if the result is zero, otherwise set ZF to 0. Compute the // bitwise NOT of a and then AND with b, and set CF to 1 if the result is zero, // otherwise set CF to 0. Return the CF value. // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_testc_si128 FORCE_INLINE int _mm_testc_si128(__m128i a, __m128i b) { int64x2_t s64 = vandq_s64(vreinterpretq_s64_s32(vmvnq_s32(vreinterpretq_s32_m128i(a))), vreinterpretq_s64_m128i(b)); return !(vgetq_lane_s64(s64, 0) | vgetq_lane_s64(s64, 1)); } // Compute the bitwise AND of 128 bits (representing integer data) in a and b, // and set ZF to 1 if the result is zero, otherwise set ZF to 0. Compute the // bitwise NOT of a and then AND with b, and set CF to 1 if the result is zero, // otherwise set CF to 0. Return 1 if both the ZF and CF values are zero, // otherwise return 0. // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_testnzc_si128 #define _mm_testnzc_si128(a, b) _mm_test_mix_ones_zeros(a, b) // Compute the bitwise AND of 128 bits (representing integer data) in a and b, // and set ZF to 1 if the result is zero, otherwise set ZF to 0. Compute the // bitwise NOT of a and then AND with b, and set CF to 1 if the result is zero, // otherwise set CF to 0. Return the ZF value. // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_testz_si128 FORCE_INLINE int _mm_testz_si128(__m128i a, __m128i b) { int64x2_t s64 = vandq_s64(vreinterpretq_s64_m128i(a), vreinterpretq_s64_m128i(b)); return !(vgetq_lane_s64(s64, 0) | vgetq_lane_s64(s64, 1)); } /* SSE4.2 */ // Compares the 2 signed 64-bit integers in a and the 2 signed 64-bit integers // in b for greater than. FORCE_INLINE __m128i _mm_cmpgt_epi64(__m128i a, __m128i b) { #if defined(__aarch64__) return vreinterpretq_m128i_u64( vcgtq_s64(vreinterpretq_s64_m128i(a), vreinterpretq_s64_m128i(b))); #else return vreinterpretq_m128i_s64(vshrq_n_s64( vqsubq_s64(vreinterpretq_s64_m128i(b), vreinterpretq_s64_m128i(a)), 63)); #endif } // Starting with the initial value in crc, accumulates a CRC32 value for // unsigned 16-bit integer v. // https://msdn.microsoft.com/en-us/library/bb531411(v=vs.100) FORCE_INLINE uint32_t _mm_crc32_u16(uint32_t crc, uint16_t v) { #if defined(__aarch64__) && defined(__ARM_FEATURE_CRC32) __asm__ __volatile__("crc32ch %w[c], %w[c], %w[v]\n\t" : [c] "+r"(crc) : [v] "r"(v)); #else crc = _mm_crc32_u8(crc, v & 0xff); crc = _mm_crc32_u8(crc, (v >> 8) & 0xff); #endif return crc; } // Starting with the initial value in crc, accumulates a CRC32 value for // unsigned 32-bit integer v. // https://msdn.microsoft.com/en-us/library/bb531394(v=vs.100) FORCE_INLINE uint32_t _mm_crc32_u32(uint32_t crc, uint32_t v) { #if defined(__aarch64__) && defined(__ARM_FEATURE_CRC32) __asm__ __volatile__("crc32cw %w[c], %w[c], %w[v]\n\t" : [c] "+r"(crc) : [v] "r"(v)); #else crc = _mm_crc32_u16(crc, v & 0xffff); crc = _mm_crc32_u16(crc, (v >> 16) & 0xffff); #endif return crc; } // Starting with the initial value in crc, accumulates a CRC32 value for // unsigned 64-bit integer v. // https://msdn.microsoft.com/en-us/library/bb514033(v=vs.100) FORCE_INLINE uint64_t _mm_crc32_u64(uint64_t crc, uint64_t v) { #if defined(__aarch64__) && defined(__ARM_FEATURE_CRC32) __asm__ __volatile__("crc32cx %w[c], %w[c], %x[v]\n\t" : [c] "+r"(crc) : [v] "r"(v)); #else crc = _mm_crc32_u32((uint32_t)(crc), v & 0xffffffff); crc = _mm_crc32_u32((uint32_t)(crc), (v >> 32) & 0xffffffff); #endif return crc; } // Starting with the initial value in crc, accumulates a CRC32 value for // unsigned 8-bit integer v. // https://msdn.microsoft.com/en-us/library/bb514036(v=vs.100) FORCE_INLINE uint32_t _mm_crc32_u8(uint32_t crc, uint8_t v) { #if defined(__aarch64__) && defined(__ARM_FEATURE_CRC32) __asm__ __volatile__("crc32cb %w[c], %w[c], %w[v]\n\t" : [c] "+r"(crc) : [v] "r"(v)); #else crc ^= v; for (int bit = 0; bit < 8; bit++) { if (crc & 1) crc = (crc >> 1) ^ UINT32_C(0x82f63b78); else crc = (crc >> 1); } #endif return crc; } /* AES */ #if !defined(__ARM_FEATURE_CRYPTO) /* clang-format off */ #define SSE2NEON_AES_DATA(w) \ { \ w(0x63), w(0x7c), w(0x77), w(0x7b), w(0xf2), w(0x6b), w(0x6f), \ w(0xc5), w(0x30), w(0x01), w(0x67), w(0x2b), w(0xfe), w(0xd7), \ w(0xab), w(0x76), w(0xca), w(0x82), w(0xc9), w(0x7d), w(0xfa), \ w(0x59), w(0x47), w(0xf0), w(0xad), w(0xd4), w(0xa2), w(0xaf), \ w(0x9c), w(0xa4), w(0x72), w(0xc0), w(0xb7), w(0xfd), w(0x93), \ w(0x26), w(0x36), w(0x3f), w(0xf7), w(0xcc), w(0x34), w(0xa5), \ w(0xe5), w(0xf1), w(0x71), w(0xd8), w(0x31), w(0x15), w(0x04), \ w(0xc7), w(0x23), w(0xc3), w(0x18), w(0x96), w(0x05), w(0x9a), \ w(0x07), w(0x12), w(0x80), w(0xe2), w(0xeb), w(0x27), w(0xb2), \ w(0x75), w(0x09), w(0x83), w(0x2c), w(0x1a), w(0x1b), w(0x6e), \ w(0x5a), w(0xa0), w(0x52), w(0x3b), w(0xd6), w(0xb3), w(0x29), \ w(0xe3), w(0x2f), w(0x84), w(0x53), w(0xd1), w(0x00), w(0xed), \ w(0x20), w(0xfc), w(0xb1), w(0x5b), w(0x6a), w(0xcb), w(0xbe), \ w(0x39), w(0x4a), w(0x4c), w(0x58), w(0xcf), w(0xd0), w(0xef), \ w(0xaa), w(0xfb), w(0x43), w(0x4d), w(0x33), w(0x85), w(0x45), \ w(0xf9), w(0x02), w(0x7f), w(0x50), w(0x3c), w(0x9f), w(0xa8), \ w(0x51), w(0xa3), w(0x40), w(0x8f), w(0x92), w(0x9d), w(0x38), \ w(0xf5), w(0xbc), w(0xb6), w(0xda), w(0x21), w(0x10), w(0xff), \ w(0xf3), w(0xd2), w(0xcd), w(0x0c), w(0x13), w(0xec), w(0x5f), \ w(0x97), w(0x44), w(0x17), w(0xc4), w(0xa7), w(0x7e), w(0x3d), \ w(0x64), w(0x5d), w(0x19), w(0x73), w(0x60), w(0x81), w(0x4f), \ w(0xdc), w(0x22), w(0x2a), w(0x90), w(0x88), w(0x46), w(0xee), \ w(0xb8), w(0x14), w(0xde), w(0x5e), w(0x0b), w(0xdb), w(0xe0), \ w(0x32), w(0x3a), w(0x0a), w(0x49), w(0x06), w(0x24), w(0x5c), \ w(0xc2), w(0xd3), w(0xac), w(0x62), w(0x91), w(0x95), w(0xe4), \ w(0x79), w(0xe7), w(0xc8), w(0x37), w(0x6d), w(0x8d), w(0xd5), \ w(0x4e), w(0xa9), w(0x6c), w(0x56), w(0xf4), w(0xea), w(0x65), \ w(0x7a), w(0xae), w(0x08), w(0xba), w(0x78), w(0x25), w(0x2e), \ w(0x1c), w(0xa6), w(0xb4), w(0xc6), w(0xe8), w(0xdd), w(0x74), \ w(0x1f), w(0x4b), w(0xbd), w(0x8b), w(0x8a), w(0x70), w(0x3e), \ w(0xb5), w(0x66), w(0x48), w(0x03), w(0xf6), w(0x0e), w(0x61), \ w(0x35), w(0x57), w(0xb9), w(0x86), w(0xc1), w(0x1d), w(0x9e), \ w(0xe1), w(0xf8), w(0x98), w(0x11), w(0x69), w(0xd9), w(0x8e), \ w(0x94), w(0x9b), w(0x1e), w(0x87), w(0xe9), w(0xce), w(0x55), \ w(0x28), w(0xdf), w(0x8c), w(0xa1), w(0x89), w(0x0d), w(0xbf), \ w(0xe6), w(0x42), w(0x68), w(0x41), w(0x99), w(0x2d), w(0x0f), \ w(0xb0), w(0x54), w(0xbb), w(0x16) \ } /* clang-format on */ /* X Macro trick. See https://en.wikipedia.org/wiki/X_Macro */ #define SSE2NEON_AES_H0(x) (x) static const uint8_t SSE2NEON_sbox[256] = SSE2NEON_AES_DATA(SSE2NEON_AES_H0); #undef SSE2NEON_AES_H0 // In the absence of crypto extensions, implement aesenc using regular neon // intrinsics instead. See: // https://www.workofard.com/2017/01/accelerated-aes-for-the-arm64-linux-kernel/ // https://www.workofard.com/2017/07/ghash-for-low-end-cores/ and // https://github.com/ColinIanKing/linux-next-mirror/blob/b5f466091e130caaf0735976648f72bd5e09aa84/crypto/aegis128-neon-inner.c#L52 // for more information Reproduced with permission of the author. FORCE_INLINE __m128i _mm_aesenc_si128(__m128i EncBlock, __m128i RoundKey) { #if defined(__aarch64__) static const uint8_t shift_rows[] = {0x0, 0x5, 0xa, 0xf, 0x4, 0x9, 0xe, 0x3, 0x8, 0xd, 0x2, 0x7, 0xc, 0x1, 0x6, 0xb}; static const uint8_t ror32by8[] = {0x1, 0x2, 0x3, 0x0, 0x5, 0x6, 0x7, 0x4, 0x9, 0xa, 0xb, 0x8, 0xd, 0xe, 0xf, 0xc}; uint8x16_t v; uint8x16_t w = vreinterpretq_u8_m128i(EncBlock); // shift rows w = vqtbl1q_u8(w, vld1q_u8(shift_rows)); // sub bytes v = vqtbl4q_u8(_sse2neon_vld1q_u8_x4(SSE2NEON_sbox), w); v = vqtbx4q_u8(v, _sse2neon_vld1q_u8_x4(SSE2NEON_sbox + 0x40), w - 0x40); v = vqtbx4q_u8(v, _sse2neon_vld1q_u8_x4(SSE2NEON_sbox + 0x80), w - 0x80); v = vqtbx4q_u8(v, _sse2neon_vld1q_u8_x4(SSE2NEON_sbox + 0xc0), w - 0xc0); // mix columns w = (v << 1) ^ (uint8x16_t)(((int8x16_t) v >> 7) & 0x1b); w ^= (uint8x16_t) vrev32q_u16((uint16x8_t) v); w ^= vqtbl1q_u8(v ^ w, vld1q_u8(ror32by8)); // add round key return vreinterpretq_m128i_u8(w) ^ RoundKey; #else /* ARMv7-A NEON implementation */ #define SSE2NEON_AES_B2W(b0, b1, b2, b3) \ (((uint32_t)(b3) << 24) | ((uint32_t)(b2) << 16) | ((uint32_t)(b1) << 8) | \ (b0)) #define SSE2NEON_AES_F2(x) ((x << 1) ^ (((x >> 7) & 1) * 0x011b /* WPOLY */)) #define SSE2NEON_AES_F3(x) (SSE2NEON_AES_F2(x) ^ x) #define SSE2NEON_AES_U0(p) \ SSE2NEON_AES_B2W(SSE2NEON_AES_F2(p), p, p, SSE2NEON_AES_F3(p)) #define SSE2NEON_AES_U1(p) \ SSE2NEON_AES_B2W(SSE2NEON_AES_F3(p), SSE2NEON_AES_F2(p), p, p) #define SSE2NEON_AES_U2(p) \ SSE2NEON_AES_B2W(p, SSE2NEON_AES_F3(p), SSE2NEON_AES_F2(p), p) #define SSE2NEON_AES_U3(p) \ SSE2NEON_AES_B2W(p, p, SSE2NEON_AES_F3(p), SSE2NEON_AES_F2(p)) static const uint32_t ALIGN_STRUCT(16) aes_table[4][256] = { SSE2NEON_AES_DATA(SSE2NEON_AES_U0), SSE2NEON_AES_DATA(SSE2NEON_AES_U1), SSE2NEON_AES_DATA(SSE2NEON_AES_U2), SSE2NEON_AES_DATA(SSE2NEON_AES_U3), }; #undef SSE2NEON_AES_B2W #undef SSE2NEON_AES_F2 #undef SSE2NEON_AES_F3 #undef SSE2NEON_AES_U0 #undef SSE2NEON_AES_U1 #undef SSE2NEON_AES_U2 #undef SSE2NEON_AES_U3 uint32_t x0 = _mm_cvtsi128_si32(EncBlock); uint32_t x1 = _mm_cvtsi128_si32(_mm_shuffle_epi32(EncBlock, 0x55)); uint32_t x2 = _mm_cvtsi128_si32(_mm_shuffle_epi32(EncBlock, 0xAA)); uint32_t x3 = _mm_cvtsi128_si32(_mm_shuffle_epi32(EncBlock, 0xFF)); __m128i out = _mm_set_epi32( (aes_table[0][x3 & 0xff] ^ aes_table[1][(x0 >> 8) & 0xff] ^ aes_table[2][(x1 >> 16) & 0xff] ^ aes_table[3][x2 >> 24]), (aes_table[0][x2 & 0xff] ^ aes_table[1][(x3 >> 8) & 0xff] ^ aes_table[2][(x0 >> 16) & 0xff] ^ aes_table[3][x1 >> 24]), (aes_table[0][x1 & 0xff] ^ aes_table[1][(x2 >> 8) & 0xff] ^ aes_table[2][(x3 >> 16) & 0xff] ^ aes_table[3][x0 >> 24]), (aes_table[0][x0 & 0xff] ^ aes_table[1][(x1 >> 8) & 0xff] ^ aes_table[2][(x2 >> 16) & 0xff] ^ aes_table[3][x3 >> 24])); return _mm_xor_si128(out, RoundKey); #endif } // Perform the last round of an AES encryption flow on data (state) in a using // the round key in RoundKey, and store the result in dst. // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_aesenclast_si128 FORCE_INLINE __m128i _mm_aesenclast_si128(__m128i a, __m128i RoundKey) { /* FIXME: optimized for NEON */ uint8_t v[4][4] = { {SSE2NEON_sbox[vreinterpretq_nth_u8_m128i(a, 0)], SSE2NEON_sbox[vreinterpretq_nth_u8_m128i(a, 5)], SSE2NEON_sbox[vreinterpretq_nth_u8_m128i(a, 10)], SSE2NEON_sbox[vreinterpretq_nth_u8_m128i(a, 15)]}, {SSE2NEON_sbox[vreinterpretq_nth_u8_m128i(a, 4)], SSE2NEON_sbox[vreinterpretq_nth_u8_m128i(a, 9)], SSE2NEON_sbox[vreinterpretq_nth_u8_m128i(a, 14)], SSE2NEON_sbox[vreinterpretq_nth_u8_m128i(a, 3)]}, {SSE2NEON_sbox[vreinterpretq_nth_u8_m128i(a, 8)], SSE2NEON_sbox[vreinterpretq_nth_u8_m128i(a, 13)], SSE2NEON_sbox[vreinterpretq_nth_u8_m128i(a, 2)], SSE2NEON_sbox[vreinterpretq_nth_u8_m128i(a, 7)]}, {SSE2NEON_sbox[vreinterpretq_nth_u8_m128i(a, 12)], SSE2NEON_sbox[vreinterpretq_nth_u8_m128i(a, 1)], SSE2NEON_sbox[vreinterpretq_nth_u8_m128i(a, 6)], SSE2NEON_sbox[vreinterpretq_nth_u8_m128i(a, 11)]}, }; for (int i = 0; i < 16; i++) vreinterpretq_nth_u8_m128i(a, i) = v[i / 4][i % 4] ^ vreinterpretq_nth_u8_m128i(RoundKey, i); return a; } // Emits the Advanced Encryption Standard (AES) instruction aeskeygenassist. // This instruction generates a round key for AES encryption. See // https://kazakov.life/2017/11/01/cryptocurrency-mining-on-ios-devices/ // for details. // // https://msdn.microsoft.com/en-us/library/cc714138(v=vs.120).aspx FORCE_INLINE __m128i _mm_aeskeygenassist_si128(__m128i key, const int rcon) { uint32_t X1 = _mm_cvtsi128_si32(_mm_shuffle_epi32(key, 0x55)); uint32_t X3 = _mm_cvtsi128_si32(_mm_shuffle_epi32(key, 0xFF)); for (int i = 0; i < 4; ++i) { ((uint8_t *) &X1)[i] = SSE2NEON_sbox[((uint8_t *) &X1)[i]]; ((uint8_t *) &X3)[i] = SSE2NEON_sbox[((uint8_t *) &X3)[i]]; } return _mm_set_epi32(((X3 >> 8) | (X3 << 24)) ^ rcon, X3, ((X1 >> 8) | (X1 << 24)) ^ rcon, X1); } #undef SSE2NEON_AES_DATA #else /* __ARM_FEATURE_CRYPTO */ // Implements equivalent of 'aesenc' by combining AESE (with an empty key) and // AESMC and then manually applying the real key as an xor operation. This // unfortunately means an additional xor op; the compiler should be able to // optimize this away for repeated calls however. See // https://blog.michaelbrase.com/2018/05/08/emulating-x86-aes-intrinsics-on-armv8-a // for more details. FORCE_INLINE __m128i _mm_aesenc_si128(__m128i a, __m128i b) { return vreinterpretq_m128i_u8( vaesmcq_u8(vaeseq_u8(vreinterpretq_u8_m128i(a), vdupq_n_u8(0))) ^ vreinterpretq_u8_m128i(b)); } // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_aesenclast_si128 FORCE_INLINE __m128i _mm_aesenclast_si128(__m128i a, __m128i RoundKey) { return _mm_xor_si128(vreinterpretq_m128i_u8(vaeseq_u8( vreinterpretq_u8_m128i(a), vdupq_n_u8(0))), RoundKey); } FORCE_INLINE __m128i _mm_aeskeygenassist_si128(__m128i a, const int rcon) { // AESE does ShiftRows and SubBytes on A uint8x16_t u8 = vaeseq_u8(vreinterpretq_u8_m128i(a), vdupq_n_u8(0)); uint8x16_t dest = { // Undo ShiftRows step from AESE and extract X1 and X3 u8[0x4], u8[0x1], u8[0xE], u8[0xB], // SubBytes(X1) u8[0x1], u8[0xE], u8[0xB], u8[0x4], // ROT(SubBytes(X1)) u8[0xC], u8[0x9], u8[0x6], u8[0x3], // SubBytes(X3) u8[0x9], u8[0x6], u8[0x3], u8[0xC], // ROT(SubBytes(X3)) }; uint32x4_t r = {0, (unsigned) rcon, 0, (unsigned) rcon}; return vreinterpretq_m128i_u8(dest) ^ vreinterpretq_m128i_u32(r); } #endif /* Others */ // Perform a carry-less multiplication of two 64-bit integers, selected from a // and b according to imm8, and store the results in dst. // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_clmulepi64_si128 FORCE_INLINE __m128i _mm_clmulepi64_si128(__m128i _a, __m128i _b, const int imm) { uint64x2_t a = vreinterpretq_u64_m128i(_a); uint64x2_t b = vreinterpretq_u64_m128i(_b); switch (imm & 0x11) { case 0x00: return vreinterpretq_m128i_u64( _sse2neon_vmull_p64(vget_low_u64(a), vget_low_u64(b))); case 0x01: return vreinterpretq_m128i_u64( _sse2neon_vmull_p64(vget_high_u64(a), vget_low_u64(b))); case 0x10: return vreinterpretq_m128i_u64( _sse2neon_vmull_p64(vget_low_u64(a), vget_high_u64(b))); case 0x11: return vreinterpretq_m128i_u64( _sse2neon_vmull_p64(vget_high_u64(a), vget_high_u64(b))); default: abort(); } } // Count the number of bits set to 1 in unsigned 32-bit integer a, and // return that count in dst. // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_popcnt_u32 FORCE_INLINE int _mm_popcnt_u32(unsigned int a) { #if defined(__aarch64__) #if __has_builtin(__builtin_popcount) return __builtin_popcount(a); #else return (int) vaddlv_u8(vcnt_u8(vcreate_u8((uint64_t) a))); #endif #else uint32_t count = 0; uint8x8_t input_val, count8x8_val; uint16x4_t count16x4_val; uint32x2_t count32x2_val; input_val = vld1_u8((uint8_t *) &a); count8x8_val = vcnt_u8(input_val); count16x4_val = vpaddl_u8(count8x8_val); count32x2_val = vpaddl_u16(count16x4_val); vst1_u32(&count, count32x2_val); return count; #endif } // Count the number of bits set to 1 in unsigned 64-bit integer a, and // return that count in dst. // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_popcnt_u64 FORCE_INLINE int64_t _mm_popcnt_u64(uint64_t a) { #if defined(__aarch64__) #if __has_builtin(__builtin_popcountll) return __builtin_popcountll(a); #else return (int64_t) vaddlv_u8(vcnt_u8(vcreate_u8(a))); #endif #else uint64_t count = 0; uint8x8_t input_val, count8x8_val; uint16x4_t count16x4_val; uint32x2_t count32x2_val; uint64x1_t count64x1_val; input_val = vld1_u8((uint8_t *) &a); count8x8_val = vcnt_u8(input_val); count16x4_val = vpaddl_u8(count8x8_val); count32x2_val = vpaddl_u16(count16x4_val); count64x1_val = vpaddl_u32(count32x2_val); vst1_u64(&count, count64x1_val); return count; #endif } #if defined(__GNUC__) || defined(__clang__) #pragma pop_macro("ALIGN_STRUCT") #pragma pop_macro("FORCE_INLINE") #endif #if defined(__GNUC__) && !defined(__clang__) #pragma GCC pop_options #endif #endif