VK-GL-CTS 初步了解

VK-GL-CTS 初步了解

下载

地址:https://github.com/KhronosGroup/VK-GL-CTS

概要说明

VK-GL-CTS提供针对:Volkan,OpenGL的一致性验证。意思是对这些图形库提供的API严重其在不同的平台的实现是否一致。所以概括起来就是VK-GL-CTS提供对不同平台的图形库的一致性验证框架。


源码获取

git clone https://github.com/KhronosGroup/VK-GL-CTS.git

  1. 目录结构

    .
    ├── Android.mk
    ├── AndroidGen.mk
    ├── CMakeLists.txt
    ├── CODE_OF_CONDUCT.md
    ├── LICENSE
    ├── MODULE_LICENSE_APACHE2
    ├── NOTICE
    ├── OWNERS
    ├── README.md
    ├── android
    ├── data
    ├── doc
    ├── execserver
    ├── executor
    ├── external
    ├── framework
    ├── modules
    ├── scripts
    └── targets
    
  1. 主要内容介绍

    • data:测试数据,提供测试图片和测试shader参数;
    • execserver:测试服务程序,主要为android和ios平台测试框架提供;
    • executor:测试基础程序,测试框架的基础实现,可视作自定义测试框架基础。
    • external:依赖的外部库源码和测试case
    • framework[^移植]:测试框架,包括测试套装和case的实现框架,wrapper。
    • modules:测试目标模块的case
    • scrpits:针对不同平台的编译脚本
    • targets[^移植]:编译脚本目录
  2. 测试框架概览

    • 通用main入口:framework/platform/tcuMain.cpp
    // Implement this in your platform port.
    tcu::Platform* createPlatform (void);
    int main (int argc, char** argv) {
     ……
     try {
         tcu::CommandLine                cmdLine     (argc, argv);
         tcu::DirArchive                 archive     (cmdLine.getArchiveDir());
         tcu::TestLog                    log         (cmdLine.getLogFileName(), cmdLine.getLogFlags());
         de::UniquePtr<tcu::Platform>    platform    (createPlatform());
         de::UniquePtr<tcu::App>         app         (new tcu::App(*platform, archive, log, cmdLine));
    
         // Main loop.
         ……
     }
     catch (const std::exception& e) {
         tcu::die("%s", e.what());
     }
     return exitStatus;
    }
    
    • 测试包注册:externl/openglcts/modules/glcTestPackageRegistry.cpp
    void registerPackages(void)
    {
     tcu::TestPackageRegistry* registry = tcu::TestPackageRegistry::getSingleton();
    
     registry->registerPackage("CTS-Configs", createConfigPackage);
    
    #if DE_OS != DE_OS_ANDROID
     registry->registerPackage("dEQP-EGL", createdEQPEGLPackage);
    #endif
     registry->registerPackage("KHR-GLES2", createES2Package);
    #if DE_OS != DE_OS_ANDROID
     registry->registerPackage("dEQP-GLES2", createdEQPES2Package);
    #endif
    
    #if defined(DEQP_GTF_AVAILABLE)
     registry->registerPackage("GTF-GLES2", createES2GTFPackage);
    #endif
    
     registry->registerPackage("KHR-GLES3", createES30Package);
    #if DE_OS != DE_OS_ANDROID
     registry->registerPackage("dEQP-GLES3", createdEQPES30Package);
    #endif
    
    #if defined(DEQP_GTF_AVAILABLE)
     registry->registerPackage("GTF-GLES3", createES30GTFPackage);
    #endif
    
    #if DE_OS != DE_OS_ANDROID
     registry->registerPackage("dEQP-GLES31", createdEQPES31Package);
    #endif
     registry->registerPackage("dEQP-GL45-GLES31", createdEQPGL45ES31Package);
     registry->registerPackage("dEQP-GL45-GLES3", createdEQPGL45ES3Package);
     registry->registerPackage("KHR-GLES31", createES31Package);
     registry->registerPackage("KHR-GLESEXT", createESEXTPackage);
    
    #if defined(DEQP_GTF_AVAILABLE)
     registry->registerPackage("GTF-GLES31", createES31GTFPackage);
    #endif
    
     registry->registerPackage("KHR-GLES32", createES32Package);
    
     registry->registerPackage("KHR-NoContext", createNoDefaultCustomContextPackage);
     registry->registerPackage("KHR-Single-GL43", createSingleConfigGL43TestPackage);
     registry->registerPackage("KHR-Single-GL44", createSingleConfigGL44TestPackage);
     registry->registerPackage("KHR-Single-GL45", createSingleConfigGL45TestPackage);
     registry->registerPackage("KHR-Single-GL46", createSingleConfigGL46TestPackage);
     registry->registerPackage("KHR-Single-GLES32", createSingleConfigES32TestPackage);
    
     registry->registerPackage("KHR-GL30", createGL30Package);
     registry->registerPackage("KHR-GL31", createGL31Package);
     registry->registerPackage("KHR-GL32", createGL32Package);
     registry->registerPackage("KHR-GL33", createGL33Package);
    
     registry->registerPackage("KHR-GL40", createGL40Package);
     registry->registerPackage("KHR-GL41", createGL41Package);
     registry->registerPackage("KHR-GL42", createGL42Package);
     registry->registerPackage("KHR-COMPAT-GL42", createGL42CompatPackage);
     registry->registerPackage("KHR-GL43", createGL43Package);
     registry->registerPackage("KHR-GL44", createGL44Package);
     registry->registerPackage("KHR-GL45", createGL45Package);
     registry->registerPackage("KHR-GL46", createGL46Package);
    
    #if defined(DEQP_GTF_AVAILABLE)
     registry->registerPackage("GTF-GL30", createGL30GTFPackage);
     registry->registerPackage("GTF-GL31", createGL31GTFPackage);
     registry->registerPackage("GTF-GL32", createGL32GTFPackage);
     registry->registerPackage("GTF-GL33", createGL33GTFPackage);
    
     registry->registerPackage("GTF-GL40", createGL40GTFPackage);
     registry->registerPackage("GTF-GL41", createGL41GTFPackage);
     registry->registerPackage("GTF-GL42", createGL42GTFPackage);
     registry->registerPackage("GTF-GL43", createGL43GTFPackage);
     registry->registerPackage("GTF-GL44", createGL44GTFPackage);
     registry->registerPackage("GTF-GL45", createGL45GTFPackage);
     registry->registerPackage("GTF-GL46", createGL46GTFPackage);
    #endif
    }
    }
    
    • 不同模块的测试用例:external/openglcts/modules里,如下图展示了modules目录的内容
    .
    ├── CMakeLists.txt
    ├── common                                  //测试框架相关源码
    ├── gl                                      //gl的测试case
    ├── glcTestPackageEntry.cpp
    ├── glcTestPackageRegistry.cpp
    ├── glcTestPackageRegistry.hpp
    ├── gles2                                   //gles2的测试case
    ├── gles3                                   //gles3的测试case
    ├── gles31                                  //gles31的测试case 
    ├── gles32                                  //gles32的测试case
    ├── glesext                                 //glesext的测试case
    ├── pch.cpp                                   
    ├── pch.h
    └── runner                                  //glcTestRunner相关文件,不同平台启动的内容也不同,比如glcAndroidTestActivity.cpp也在此文件夹内。
    

下载第三方软件

进入VK-GL-CTS目录,执行python external/fetch_sources.py.

注意,此部分可能下载困难,需要科学上网

编译[^cmake] 和 测试

  1. 由于是cmake,所以和下载的文件平行的位置创建build目录:

    mkdir x11gl (或者 mkdir gles32,根据不同编译对象建立不同目录)
    
  2. VK-GLS-CTS cmake 有两个选项:

    • -DDEQP_TARGET:依赖目标,如android,default,iOS,null,osx,raspi,curfaceless,vulkan_headless,wayland,x11_egl,x11_egl_glx,x11_glx
    • -DCLSTS_GTF_TARGET:测试对象,如gles2,gles3,gles31,gles32和gl
  3. 编译

    cmake <path to VK-GL-CTS> -DDEQP_TARGET=x11_glx -DGLCTS_GTF_TARGET=gl (或是:cmake <path to VK-GL-CTS> -DDEQP_TARGET=null -DGLCTS_GTF_TARGET=gl/gles32)
    cmake --build external/openglcts
    
  4. Debug

    cmake <path to VK-GL-CTS> -DDEQP_TARGET=default -DGLCTS_GTF_TARGET=gl -DCMAKE_BUILD_TYPE=Debug -DCMAKE_C_FLAGS=-m64 -DCMAKE_CXX_FLAGS=-m64
    cmake --build . -j12
    
  5. 测试

    ./cts-runner --type=gl45 (套装级测试)
    ./glcts --deqp-case=dEQP-GLES2.info.* (用例级测试)
    
  6. 测试结果

    在测试位置的本地目录会有个TestResults.qpa文件(默认不改log输出时可见)

编译框架详解

根CMakeLists

根CMakeLists主要定义:

  • 版本(cmake>3.10.2,python>3)
  • 编译目标(targets目录里的具体对象,默认default及default.cmake)和 项目 (dEQP-Core-default)
  • 定义变量,见set(DEQP_XXX);定义构建参数,见add_definitions;定义头文件,见include_directories;定义子cmake,见include;定义宏/宏函数,见macro,
  • 定义需要编译的subdirectory,见add_subdirectory,注意,这就是具体的编译步骤 。具体步骤为:
    1. 编译external里的第三方库,如glslang,spirv-tools,amber等;
    2. 编译framework里的delibs,如debase,depool等,相当于自己实现的基础库函数以避免对不同平台的依赖;
    3. 编译execserver和executor,测试框架的基础库
    4. 编译全部framework,modules,framework主要是针对不同的平台开发的平台适配内容,即为实现接口测试而需要的基础适配代码;modules是针对不同版本gl库开发的接口测试用例;
    5. 最后编译external/openglcts,生成测试对应的可执行文件 cts-runnerglcts

script脚本

用python写的工具,README介绍的主要两类,一个就是android生成apk的脚本,一个就是log分析和格式转换相关的。但是这里面其实有些基础的测试相关工具,如build_caselists.py,类似于直接运行的cmake命令。

platform的选择

根据DE_OS_IS_UNIX 和 DEQP_USE_X11确定是使用platform/lnx内的platform实现,如:tcu::Platform* tcu::lnx::LinuxPlatform;并且,由于在cmake编译时使用 -DDEQP_TARGET=default ,所以targets/default 目录里的default.cmake会被调用,然后在此文件里会找 find_package(X11) ,如果找到则会设置:set(DEQP_USE_X11 ON)set(DEQP_SUPPORT_GLX ON)

测试框架详解

cts-runner详解

  1. 编译:在源码目录CMakeList里定义了add_executable生成cts-runner,主要涉及两个文件:glcTestRunnerMain.cpp和glcTestPackageEntry.cpp
add_executable(cts-runner runner/glcTestRunnerMain.cpp glcTestPackageEntry.cpp)
  1. 主要调用关系
graph LR
glcTestRunnerMain[cts-runner] -->main(main)
    main --> platform(Platform)
    main --> glcTestRunner.cpp(TestRunner)
    glcTestRunner.cpp(TestRunner) --> init --> |--type| getDefaultConfigList
    init --> |--type| getTestRunParam
    glcTestRunner.cpp(TestRunner) --> initSession --> createSession --> tcuApp(createApp) --> tcuTestPackage.cpp(TestPackageRegistry)
    glcTestRunner.cpp(TestRunner) --> iterateSession --> glcTestRunner(RunSession.iterate) --> tcuApp.cpp(App.iterate)
    

总结:cts-runner根据参数里的--type初始化对应的配置文件和运行参数,然后生成 tcuAPP,根据注册的TestPackage进行具体测试

所以进一步需要了解的为:

  • Platform:主要对应的是具体的平台框架的实现,如Display和Context实现,对应的实现逻辑可以参考framework/platform内的实现。

    ├── android   
    ├── CMakeLists.txt
    ├── ios
    ├── lnx  //linux
    ├── null
    ├── nullws
    ├── osx
    ├── raspi
    ├── surfaceless
    ├── tcuMain.cpp
    ├── vanilla
    └── win32
    
  • ConfigList:根据传入--type,初始化基本配置,包括EGL,WGL,主要初始化display,render等需要的参数,如尺寸,RGB,YUV等的参数值,其中对应具体运行的case配置也是在ConfigList里,如 --deqp-case

  • RunParam:初始化基本参数,包括ES,GL等,主要初始化api,screen,surface,randonseed等

  • TestPackage:参考之前的测试包注册 ,实现对应的测试用例。

glcts详解

  1. 编译:和 cts-runner 不同,glcts独立的可执行程序是在 *external/openglcts/modules/CMakeLists里定义模块

    add_deqp_module(glcts "${GLCTS_SRCS}" "${GLCTS_LIBS}" glcTestPackageEntry.cpp)
    

    然后再在总CMakeLists里根据module名称套用tcuMain生成的可执行程序

    add_executable(${MODULE_NAME} ${PROJECT_SOURCE_DIR}/framework/platform/tcuMain.cpp ${ENTRY})
    
  2. 主要调用关系

    参加之前的 测试框架概览 ,tcuMain主要调用的就是tcuApp,所以glcts其实就是cts-runner最终调用的部分。cts-runner是在由 --type 对应的TestRunner里配置对应的参数。

    graph LR
    tcuMain[glcts] -->tcuApp(App) --> TestPackageRegistry(TestPackageRoot) --> tcuTestSessionExecutor(caseListFilter) --> TestSessionExecutor(iterate) 
    STATE_EXECUTE_TEST_CASE --> RenderCase(executeForConfig)
    tcu::App::iterate --> tcu::TestSessionExecutor --> tcu::TestHierarchyIterator --> deqp::egl::TestPackage --> deqp::egl::EglTestContext
    

    总结:cts-runner根据参数里的--type初始化对应的配置文件和运行参数,然后生成 tcuAPP,根据注册的TestPackage进行具体测试

target详解

target里存的都是cmake文件,在编译时-DDEQP_TARGET=?选择的对象即为target文件下的子文件夹。

targets
├── android
├── default
├── ios
├── null
├── nullws
├── osx
├── raspi
├── surfaceless
├── vulkan_headless
├── wayland
├── x11_egl
├── x11_egl_glx
└── x11_glx

platform详解

platform里存的是不同框架内的图形库的入口实现,以Debug对应的函数为例,LinuxPlatform实现 m_vkPlatformm_glPlatformm_eglPlatform 三个platform;

Display详解

graph LR
main --> createPlatform --> tcu::lnx::(LinuxPlatform) --> tcu::lnx::egl::Platform(egl::Platform) --> tcu::lnx::x11::egl::createDisplayFactory(createDisplayFactory) --> tcu::lnx::x11::egl::DisplayFactory(DisplayFactory) --> tcu::lnx::x11::egl::WindowFactory[WindowFactory]
eglw::DefaultLibrary[library]--> eglu::NativeDislay(Display) --> eglu::NativeWindow(Window) --> eglu::NativeWindowFactory(WindowFactory)

移植分析

移植涉及的API文件

framework/common/tcuPlatform.hpp
framework/opengl/gluPlatform.hpp
framework/egl/egluPlatform.hpp
framework/platform/tcuMain.cpp

如何增加测试对象和测试模块

  1. 测试对象为targets目录内的内容

    .
    ├── android
    ├── default
    ├── ios
    ├── null
    ├── nullws
    ├── osx
    ├── raspi
    ├── surfaceless
    ├── vulkan_headless
    ├── wayland
    ├── x11_egl
    ├── x11_egl_glx
    └── x11_glx
    

    以上为写文章时最新的目录内容。子目录为编译生成具体对象测试程序的cmake脚本,举个例子

    message("*** Using null context target")
    
    set(DEQP_TARGET_NAME "Null")
    
    set(TCUTIL_PLATFORM_SRCS
     null/tcuNullPlatform.cpp
     null/tcuNullPlatform.hpp
     null/tcuNullRenderContext.cpp
     null/tcuNullRenderContext.hpp
     null/tcuNullContextFactory.cpp
     null/tcuNullContextFactory.hpp
     )
    
    

    以上是null对象的生成脚步,内部文件对应位置则为framework/platform目录内。对应不同软件平台实现了不同GL接口和初始化实现

  2. 测试框架

    framework/common内是VK-GL-CTS的测试框架,对应生成的cts-runner和glcts是external/openglcts/modules里的文件。cts-runner对应的main就是runner/glcTestRunnerMain.cpp,glcts对应的则是glcTestPackageEntry.cpp(内部依赖glcTestPackageRegistry.cpp)然后根据cmake的编译规则add_module,add_executable,使用tcuapp.cpp作为glcts程序的main入口对模块级别的测试用例进行测试。


最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 160,585评论 4 365
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,923评论 1 301
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 110,314评论 0 248
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,346评论 0 214
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,718评论 3 291
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,828评论 1 223
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 32,020评论 2 315
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,758评论 0 204
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,486评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,722评论 2 251
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,196评论 1 262
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,546评论 3 258
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,211评论 3 240
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,132评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,916评论 0 200
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,904评论 2 283
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,758评论 2 274

推荐阅读更多精彩内容