Merge pull request #2851 from erikaharrison-adsk/feature-hgi-vulkan-unit-test
authorpixar-oss <pixar-oss@users.noreply.github.com>
Mon, 22 Jan 2024 22:31:23 +0000 (14:31 -0800)
committerpixar-oss <pixar-oss@users.noreply.github.com>
Mon, 22 Jan 2024 23:03:26 +0000 (15:03 -0800)
Autodesk: Feature hgi vulkan unit test

(Internal change: 2311664)
(Internal change: 2311695)

1  2 
pxr/imaging/hgi/CMakeLists.txt
pxr/imaging/hgi/testenv/testHgiCommand.cpp
pxr/imaging/hgi/unitTestHelper.cpp
pxr/imaging/hgi/unitTestHelper.h
pxr/imaging/hgiGL/CMakeLists.txt
pxr/imaging/hgiGL/testenv/testHgiGLCommand/baseline/testHgiGLCommand_triangle.png
pxr/imaging/hgiVulkan/CMakeLists.txt
pxr/imaging/hgiVulkan/testenv/testHgiVulkanCommand/baseline/testHgiVulkanCommand_triangle.png

index 9470e251aaad5351dcedd06f0190452b1731e5bc,9470e251aaad5351dcedd06f0190452b1731e5bc..925a793ed64875c3d9509e665350ee0de77954cb
@@@ -6,6 -6,6 +6,7 @@@ pxr_library(hg
          gf
          plug
          tf
++        hio
  
      PUBLIC_CLASSES
          attachmentDesc
@@@ -32,6 -32,6 +33,7 @@@
          texture
          tokens
          types
++        unitTestHelper
  
      PUBLIC_HEADERS
          api.h
          enums.h
          handle.h
  )
++
++if (${PXR_HEADLESS_TEST_MODE})
++    message(STATUS "Skipping ${PXR_PACKAGE} tests because PXR_HEADLESS_TEST_MODE is ON")
++    return()
++endif()
++
++if (APPLE)
++    message(STATUS "Skipping ${PXR_PACKAGE} tests because they are currently unsupported on macOS")
++    return()
++endif()
++
++if (WIN32)
++    message(STATUS "Skipping ${PXR_PACKAGE} tests because they are currently unsupported on Windows")
++    return()
++endif()
++
++pxr_build_test(testHgiCommand
++    LIBRARIES
++        hgi
++        garch
++        tf
++    CPPFILES
++        testenv/testHgiCommand.cpp
++)
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..b786ceec60aaa8eb328c2b8d6e5d51b0bdf94538
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,132 @@@
++//
++// Copyright 2023 Pixar
++//
++// Licensed under the Apache License, Version 2.0 (the "Apache License")
++// with the following modification; you may not use this file except in
++// compliance with the Apache License and the following modification to it:
++// Section 6. Trademarks. is deleted and replaced with:
++//
++// 6. Trademarks. This License does not grant permission to use the trade
++//    names, trademarks, service marks, or product names of the Licensor
++//    and its affiliates, except as required to comply with Section 4(c) of
++//    the License and to reproduce the content of the NOTICE file.
++//
++// You may obtain a copy of the Apache License at
++//
++//     http://www.apache.org/licenses/LICENSE-2.0
++//
++// Unless required by applicable law or agreed to in writing, software
++// distributed under the Apache License with the above modification is
++// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
++// KIND, either express or implied. See the Apache License for the specific
++// language governing permissions and limitations under the Apache License.
++//
++
++#include "pxr/imaging/hgi/unitTestHelper.h"
++
++#include "pxr/imaging/garch/glApi.h"
++#include "pxr/imaging/garch/glDebugWindow.h"
++
++#include "pxr/base/tf/errorMark.h"
++#include "pxr/base/tf/envSetting.h"
++
++#include <iostream>
++
++PXR_NAMESPACE_USING_DIRECTIVE
++
++static bool
++HgiBasicTest()
++{
++    HgiInitializationTestDriver driver;
++
++    if (driver.GetHgi() == nullptr) {
++        return false;
++    }
++    
++    return true;
++}
++
++static bool
++HgiPipelineCreateTest()
++{
++    HgiPipelineCreationTestDriver driver;
++    
++    if (!driver.CreateTestPipeline()) {
++        return false;
++    }
++    
++    return true;
++}
++
++static bool
++HgiExecuteGfxCmdBfrTest(std::string fileName)
++{
++    HgiGfxCmdBfrExecutionTestDriver driver;
++
++    if (!driver.CreateTestPipeline()) {
++        return false;
++    }
++
++    if (!driver.ExecuteTestGfxCmdBfr()) {
++        return false;
++    }
++
++    if (!fileName.empty()) {
++        if (!driver.WriteToFile(fileName)) {
++            return false;
++        }
++    }
++
++    return true;
++}
++
++class HgiUnitTestWindow : public GarchGLDebugWindow {
++public:
++    HgiUnitTestWindow(const char *title, int width, int height)
++    : GarchGLDebugWindow(title, width, height)
++    {}
++
++    ~HgiUnitTestWindow() {}
++
++    void OnInitializeGL() override {
++        GarchGLApiLoad();
++    }
++};
++
++/// Entrypoint to this unit test 
++/// Valid command line options for this unit test are : 
++/// --write <filename> // writes render output to disk
++int 
++main(int argc, char **argv)
++{
++    std::string fileName;
++    for (int i = 0; i < argc; ++i) {
++        std::string arg(argv[i]);
++        if (arg == "--write") {
++            if (i+1 < argc) { 
++                fileName = std::string(argv[++i]);
++            }            
++            break;
++        }
++    }
++    
++    TfErrorMark mark;
++
++    // Setup OpenGL context, needed for HgiGL version of test.
++    HgiUnitTestWindow unitTestWindow("hgi", 256, 256);
++    unitTestWindow.Init();
++
++    bool success = HgiBasicTest();
++    success = success && HgiPipelineCreateTest();
++    success = success && HgiExecuteGfxCmdBfrTest(fileName);
++
++    TF_VERIFY(mark.IsClean());
++
++    if (success && mark.IsClean()) {
++        std::cout << "OK" << std::endl;
++        return EXIT_SUCCESS;
++    } else {
++        std::cout << "FAILED" << std::endl;
++        return EXIT_FAILURE;
++    }
++}
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..95019d884b64de256acff2a66895736370f42639
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,483 @@@
++//
++// Copyright 2023 Pixar
++//
++// Licensed under the Apache License, Version 2.0 (the "Apache License")
++// with the following modification; you may not use this file except in
++// compliance with the Apache License and the following modification to it:
++// Section 6. Trademarks. is deleted and replaced with:
++//
++// 6. Trademarks. This License does not grant permission to use the trade
++//    names, trademarks, service marks, or product names of the Licensor
++//    and its affiliates, except as required to comply with Section 4(c) of
++//    the License and to reproduce the content of the NOTICE file.
++//
++// You may obtain a copy of the Apache License at
++//
++//     http://www.apache.org/licenses/LICENSE-2.0
++//
++// Unless required by applicable law or agreed to in writing, software
++// distributed under the Apache License with the above modification is
++// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
++// KIND, either express or implied. See the Apache License for the specific
++// language governing permissions and limitations under the Apache License.
++//
++#include "pxr/imaging/hgi/unitTestHelper.h"
++#include "pxr/imaging/hgi/blitCmds.h"
++#include "pxr/imaging/hgi/blitCmdsOps.h"
++
++#include "pxr/imaging/hio/image.h"
++
++#include <iostream>
++#include <string>
++#include <sstream>
++
++PXR_NAMESPACE_OPEN_SCOPE
++
++HgiInitializationTestDriver::HgiInitializationTestDriver()
++    : _hgi(Hgi::CreatePlatformDefaultHgi())
++{
++}
++
++HgiInitializationTestDriver::~HgiInitializationTestDriver() = default;
++
++static const std::string glslfx_vertShaderStr =
++"void main(void)\n"
++"{\n"
++"    gl_Position = position;\n"
++"    uvOut = uvIn;\n"
++"}\n";
++
++static const std::string glslfx_fragShaderStr =
++"void main(void)\n"
++"{\n"
++"    vec4 color = vec4(1.0, 0.0, 1.0, 1.0);\n"
++"    hd_FragColor = color;\n"
++"}\n";
++
++HgiPipelineCreationTestDriver::HgiPipelineCreationTestDriver()
++    : _hgi(Hgi::CreatePlatformDefaultHgi())
++{
++    _CreateVertexBufferDescriptor();
++}
++
++HgiPipelineCreationTestDriver::~HgiPipelineCreationTestDriver()
++{
++    if (_shaderProgram) {
++        _DestroyShaderProgram();
++    }
++    if (_pipeline) {
++        _hgi->DestroyGraphicsPipeline(&_pipeline);
++    }
++}
++
++void
++HgiPipelineCreationTestDriver::_CreateVertexBufferDescriptor()
++{
++    HgiVertexAttributeDesc posAttr;
++    posAttr.format = HgiFormatFloat32Vec3;
++    posAttr.offset = 0;
++    posAttr.shaderBindLocation = 0;
++
++    HgiVertexAttributeDesc uvAttr;
++    uvAttr.format = HgiFormatFloat32Vec2;
++    uvAttr.offset = sizeof(float) * 4; // after posAttr
++    uvAttr.shaderBindLocation = 1;
++
++    _vboDesc.bindingIndex = 0;
++    _vboDesc.vertexStride = sizeof(float) * 6; // pos, uv
++    _vboDesc.vertexAttributes = { posAttr, uvAttr };
++}
++
++bool
++HgiPipelineCreationTestDriver::CreateTestPipeline()
++{
++    if (!_CreateShaderProgram()) {
++        return false;
++    }
++
++    if (!_CreatePipeline()) {
++        return false;
++    }
++
++    return true;
++}
++
++bool 
++HgiPipelineCreationTestDriver::_CreateShaderProgram()
++{
++    HgiShaderFunctionDesc vertDesc;
++    vertDesc.debugName = TfToken("Vertex");
++    vertDesc.shaderStage = HgiShaderStageVertex;
++    HgiShaderFunctionAddStageInput(
++        &vertDesc, "position", "vec4", "position");
++    HgiShaderFunctionAddStageInput(
++        &vertDesc, "uvIn", "vec2");
++    HgiShaderFunctionAddStageOutput(
++        &vertDesc, "gl_Position", "vec4", "position");
++    HgiShaderFunctionAddStageOutput(
++        &vertDesc, "uvOut", "vec2");
++
++    HgiShaderFunctionDesc fragDesc;
++    fragDesc.debugName = TfToken("Fragment");
++    fragDesc.shaderStage = HgiShaderStageFragment;
++    HgiShaderFunctionAddStageInput(
++        &fragDesc, "uvOut", "vec2");
++    HgiShaderFunctionAddStageOutput(
++        &fragDesc, "hd_FragColor", "vec4", "color");
++
++    vertDesc.shaderCode = glslfx_vertShaderStr.c_str();
++    HgiShaderFunctionHandle vertFn = _hgi->CreateShaderFunction(vertDesc);
++    
++    fragDesc.shaderCode = glslfx_fragShaderStr.c_str();
++    HgiShaderFunctionHandle fragFn = _hgi->CreateShaderFunction(fragDesc);
++    
++    HgiShaderProgramDesc programDesc;
++    programDesc.debugName = TfToken("FullscreenTriangle").GetString();
++    programDesc.shaderFunctions.push_back(std::move(vertFn));
++    programDesc.shaderFunctions.push_back(std::move(fragFn));
++    _shaderProgram = _hgi->CreateShaderProgram(programDesc);
++    
++    if (!_shaderProgram->IsValid() || !vertFn->IsValid() ||
++        !fragFn->IsValid()) {
++        TF_CODING_ERROR("Failed to create shader program");
++        _PrintCompileErrors();
++        _DestroyShaderProgram();
++        return false;
++    }
++
++    return true;
++}
++
++bool
++HgiPipelineCreationTestDriver::_CreatePipeline()
++{
++    if (_pipeline) {
++        _hgi->DestroyGraphicsPipeline(&_pipeline);
++    }
++
++    // Setup color attachment
++    _colorAtt.blendEnabled = false;
++    _colorAtt.loadOp = HgiAttachmentLoadOpDontCare;
++    _colorAtt.storeOp = HgiAttachmentStoreOpStore;
++    _colorAtt.srcColorBlendFactor = HgiBlendFactorZero;
++    _colorAtt.dstColorBlendFactor = HgiBlendFactorZero;
++    _colorAtt.colorBlendOp = HgiBlendOpAdd;
++    _colorAtt.srcAlphaBlendFactor = HgiBlendFactorZero;
++    _colorAtt.dstAlphaBlendFactor = HgiBlendFactorZero;
++    _colorAtt.alphaBlendOp = HgiBlendOpAdd;
++    _colorAtt.format = HgiFormatUNorm8Vec4;
++    _colorAtt.usage = HgiTextureUsageBitsColorTarget;
++    
++    // Setup depth attachment
++    _depthAtt = HgiAttachmentDesc{};
++    _depthAtt.blendEnabled = false;
++    _depthAtt.loadOp = HgiAttachmentLoadOpDontCare;
++    _depthAtt.storeOp = HgiAttachmentStoreOpStore;
++    _depthAtt.srcColorBlendFactor = HgiBlendFactorZero;
++    _depthAtt.dstColorBlendFactor = HgiBlendFactorZero;
++    _depthAtt.colorBlendOp = HgiBlendOpAdd;
++    _depthAtt.srcAlphaBlendFactor = HgiBlendFactorZero;
++    _depthAtt.dstAlphaBlendFactor = HgiBlendFactorZero;
++    _depthAtt.alphaBlendOp = HgiBlendOpAdd;
++    _depthAtt.format = HgiFormatFloat32;
++    _depthAtt.usage = HgiTextureUsageBitsDepthTarget;
++    
++    HgiGraphicsPipelineDesc desc;
++    desc.debugName = "Forward Pipeline";
++    desc.shaderProgram = _shaderProgram;
++    desc.colorAttachmentDescs.push_back(_colorAtt);
++    desc.depthAttachmentDesc = _depthAtt;
++
++    HgiDepthStencilState depthState;
++    depthState.depthTestEnabled = true;
++    depthState.depthCompareFn = HgiCompareFunctionAlways;
++    depthState.stencilTestEnabled = false;
++    desc.depthState = depthState;
++
++    desc.vertexBuffers = { _vboDesc };
++    desc.depthState.depthWriteEnabled = false;
++    desc.multiSampleState.alphaToCoverageEnable = false;
++    desc.rasterizationState.cullMode = HgiCullModeBack;
++    desc.rasterizationState.polygonMode = HgiPolygonModeFill;
++    desc.rasterizationState.winding = HgiWindingCounterClockwise;
++    desc.shaderProgram = _shaderProgram;
++
++    _pipeline = _hgi->CreateGraphicsPipeline(desc);
++    if (!_pipeline) {
++        return false;
++    }
++
++    return true;
++}
++
++void
++HgiPipelineCreationTestDriver::_DestroyShaderProgram()
++{
++    for (HgiShaderFunctionHandle fn : _shaderProgram->GetShaderFunctions()) {
++        _hgi->DestroyShaderFunction(&fn);
++    }
++    _hgi->DestroyShaderProgram(&_shaderProgram);
++}
++
++void
++HgiPipelineCreationTestDriver::_PrintCompileErrors()
++{
++    for (HgiShaderFunctionHandle fn : _shaderProgram->GetShaderFunctions()) {
++        std::cout << fn->GetCompileErrors() << std::endl;
++    }
++    std::cout << _shaderProgram->GetCompileErrors() << std::endl;
++}
++
++HgiGfxCmdBfrExecutionTestDriver::HgiGfxCmdBfrExecutionTestDriver()
++    : HgiPipelineCreationTestDriver()
++    , _renderDim(600, 400, 1)
++{
++}
++
++HgiGfxCmdBfrExecutionTestDriver::~HgiGfxCmdBfrExecutionTestDriver()
++{
++    if (_colorTarget) {
++        _hgi->DestroyTexture(&_colorTarget);
++    }
++
++    if (_colorTargetView) {
++        _hgi->DestroyTextureView(&_colorTargetView);
++    }
++
++    if (_depthTarget) {
++        _hgi->DestroyTexture(&_depthTarget);
++    }
++
++    if (_depthTargetView) {
++        _hgi->DestroyTextureView(&_depthTargetView);
++    }
++
++    if (_vertexBuffer) {
++        _hgi->DestroyBuffer(&_vertexBuffer);
++    }
++
++    if (_indexBuffer) {
++        _hgi->DestroyBuffer(&_indexBuffer);
++    }
++}
++
++bool
++HgiGfxCmdBfrExecutionTestDriver::ExecuteTestGfxCmdBfr()
++{
++    if (!_CreateResourceBuffers()) {
++        return false;
++    }
++
++    if (!_CreateRenderTargets()) {
++        return false;
++    }
++
++    {
++        const GfVec4i viewport(0, 0, _renderDim[0], _renderDim[1]);
++
++        HgiGraphicsCmdsDesc gfxDesc;
++        gfxDesc.colorAttachmentDescs.push_back(_colorAtt);
++        gfxDesc.depthAttachmentDesc = _depthAtt;
++        gfxDesc.colorTextures.push_back(_colorTarget);
++        gfxDesc.depthTexture = _depthTarget;
++
++        HgiGraphicsCmdsUniquePtr gfxCmds = _hgi->CreateGraphicsCmds(gfxDesc);
++        gfxCmds->PushDebugGroup("Draw Test");
++        gfxCmds->BindPipeline(_pipeline);
++        gfxCmds->BindVertexBuffers({ {_vertexBuffer, 0, 0} });
++        gfxCmds->SetViewport(viewport);
++        gfxCmds->DrawIndexed(_indexBuffer, 3, 0, 0, 1, 0);
++        gfxCmds->PopDebugGroup();
++
++        _hgi->SubmitCmds(gfxCmds.get(), HgiSubmitWaitTypeWaitUntilCompleted);
++    }
++
++    return true;
++}
++
++bool
++HgiGfxCmdBfrExecutionTestDriver::WriteToFile(const std::string& filePath)
++{
++    const size_t byteSize = HgiGetDataSize(HgiFormatUNorm8Vec4, _renderDim);
++
++    std::vector<uint8_t> texels(byteSize, 0);
++    HgiTextureGpuToCpuOp readBackOp{};
++    readBackOp.cpuDestinationBuffer = texels.data();
++    readBackOp.destinationBufferByteSize = byteSize;
++    readBackOp.destinationByteOffset = 0;
++    readBackOp.gpuSourceTexture = _colorTarget;
++    readBackOp.mipLevel = 0;
++    readBackOp.sourceTexelOffset = GfVec3i(0);
++
++    HgiBlitCmdsUniquePtr blitCmds = _hgi->CreateBlitCmds();
++    blitCmds->CopyTextureGpuToCpu(readBackOp);
++    _hgi->SubmitCmds(blitCmds.get(), HgiSubmitWaitTypeWaitUntilCompleted);
++    
++    HioImage::StorageSpec storage;
++    storage.width = _renderDim[0];
++    storage.height = _renderDim[1];
++    storage.format = HioFormatUNorm8Vec4;
++    storage.data = readBackOp.cpuDestinationBuffer;
++    storage.flipped = true;
++
++    if (storage.format == HioFormatInvalid) {
++        printf("Hgi texture has format not corresponding to a"
++                        "HioFormat");
++        return false;
++    }
++
++    if (!storage.data) {
++        printf("No data for texture");
++        return false;
++    }
++        
++    HioImageSharedPtr const image = HioImage::OpenForWriting(filePath);
++    if (!image) {
++        printf("Failed to open image for writing %s",
++            filePath.c_str());
++        return false;
++    }
++
++    if (!image->Write(storage)) {
++        printf("Failed to write image to %s", filePath.c_str());
++        return false;
++    }
++    
++    return true;
++}
++
++bool
++HgiGfxCmdBfrExecutionTestDriver::_CreateResourceBuffers()
++{
++    if (_vertexBuffer) {
++       _hgi->DestroyBuffer(&_vertexBuffer);
++    }
++    
++    if (_indexBuffer) {
++        _hgi->DestroyBuffer(&_indexBuffer);
++    }
++
++    constexpr size_t elementsPerVertex = 6;
++    constexpr size_t vertDataCount = elementsPerVertex * 3;
++    constexpr float vertData[vertDataCount] = {
++        -0.25,  0.25, 0, 0.25,     0, 1,
++        -0.25, -0.25, 0, 0.25,     0, 0,
++         0.25, -0.25, 0, 0.25,     0.25, 0 };
++
++    HgiBufferDesc vboDesc{};
++    vboDesc.debugName = "VertexBuffer";
++    vboDesc.usage = HgiBufferUsageVertex;
++    vboDesc.initialData = vertData;
++    vboDesc.byteSize = sizeof(vertData);
++    vboDesc.vertexStride = elementsPerVertex * sizeof(vertData[0]);
++    _vertexBuffer = _hgi->CreateBuffer(vboDesc);
++    if (!_vertexBuffer) {
++        return false;
++    }
++
++    static const int32_t indices[3] = { 0, 1, 2 };
++
++    HgiBufferDesc iboDesc;
++    iboDesc.debugName = "IndexBuffer";
++    iboDesc.usage = HgiBufferUsageIndex32;
++    iboDesc.initialData = indices;
++    iboDesc.byteSize = sizeof(indices) * sizeof(indices[0]);
++    _indexBuffer = _hgi->CreateBuffer(iboDesc);
++    if (!_indexBuffer) {
++        return false;
++    }
++
++    return true;
++}
++
++bool
++HgiGfxCmdBfrExecutionTestDriver::_CreateRenderTargets()
++{
++    if (_colorTarget) {
++        _hgi->DestroyTexture(&_colorTarget);
++    }
++
++    if (_colorTargetView) {
++        _hgi->DestroyTextureView(&_colorTargetView);
++    }
++
++    if (_depthTarget) {
++        _hgi->DestroyTexture(&_depthTarget);
++    }
++
++    if (_depthTargetView) {
++        _hgi->DestroyTextureView(&_depthTargetView);
++    }
++
++    // create color render target
++    HgiTextureDesc desc{};
++    desc.componentMapping = HgiComponentMapping{
++        HgiComponentSwizzleR, HgiComponentSwizzleG,
++        HgiComponentSwizzleB, HgiComponentSwizzleA, };
++    desc.debugName = "Color Buffer";
++    desc.dimensions = _renderDim;
++    desc.format = HgiFormatUNorm8Vec4;
++    desc.initialData = nullptr;
++    desc.layerCount = 1;
++    desc.mipLevels = 1;
++    desc.pixelsByteSize = 0;
++    desc.sampleCount = HgiSampleCount1;
++    desc.type = HgiTextureType2D;
++    desc.usage = HgiTextureUsageBitsColorTarget;
++    _colorTarget = _hgi->CreateTexture(desc);
++    if (!_colorTarget) {
++        return false;
++    }
++
++    // create color view
++    HgiTextureViewDesc viewDesc{};
++    viewDesc.debugName = "Color Buffer View";
++    viewDesc.format = HgiFormatUNorm8Vec4;;
++    viewDesc.layerCount = 1;
++    viewDesc.mipLevels = 1;
++    viewDesc.sourceFirstLayer = 0;
++    viewDesc.sourceFirstMip = 0;
++    viewDesc.sourceTexture = _colorTarget;
++    _colorTargetView = _hgi->CreateTextureView(viewDesc);
++    if (!_colorTargetView) {
++        return false;
++    }
++
++    // create depth target
++    desc = HgiTextureDesc{};
++    desc.componentMapping = HgiComponentMapping{
++        HgiComponentSwizzleR, HgiComponentSwizzleG,
++        HgiComponentSwizzleB, HgiComponentSwizzleA, };
++    desc.debugName = "Depth Buffer";
++    desc.dimensions = _renderDim;
++    desc.format = HgiFormatFloat32;
++    desc.initialData = nullptr;
++    desc.layerCount = 1;
++    desc.mipLevels = 1;
++    desc.pixelsByteSize = 0;
++    desc.sampleCount = HgiSampleCount1;
++    desc.type = HgiTextureType2D;
++    desc.usage = HgiTextureUsageBitsDepthTarget;
++    _depthTarget = _hgi->CreateTexture(desc);
++    if (!_depthTarget) {
++        return false;
++    }
++
++    // create depth view
++    viewDesc = HgiTextureViewDesc{};
++    viewDesc.debugName = "Depth Buffer View";
++    viewDesc.format = HgiFormatFloat32;;
++    viewDesc.layerCount = 1;
++    viewDesc.mipLevels = 1;
++    viewDesc.sourceFirstLayer = 0;
++    viewDesc.sourceFirstMip = 0;
++    viewDesc.sourceTexture = _depthTarget;
++    _depthTargetView = _hgi->CreateTextureView(viewDesc);
++    if (!_depthTargetView) {
++        return false;
++    }
++
++    return true;
++}
++
++PXR_NAMESPACE_CLOSE_SCOPE
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..487094a84cb9365f76a1f8874e0fc93946dd9237
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,114 @@@
++//
++// Copyright 2023 Pixar
++//
++// Licensed under the Apache License, Version 2.0 (the "Apache License")
++// with the following modification; you may not use this file except in
++// compliance with the Apache License and the following modification to it:
++// Section 6. Trademarks. is deleted and replaced with:
++//
++// 6. Trademarks. This License does not grant permission to use the trade
++//    names, trademarks, service marks, or product names of the Licensor
++//    and its affiliates, except as required to comply with Section 4(c) of
++//    the License and to reproduce the content of the NOTICE file.
++//
++// You may obtain a copy of the Apache License at
++//
++//     http://www.apache.org/licenses/LICENSE-2.0
++//
++// Unless required by applicable law or agreed to in writing, software
++// distributed under the Apache License with the above modification is
++// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
++// KIND, either express or implied. See the Apache License for the specific
++// language governing permissions and limitations under the Apache License.
++//
++#ifndef PXR_IMAGING_HGI_UNIT_TEST_HELPER_H
++#define PXR_IMAGING_HGI_UNIT_TEST_HELPER_H
++
++#include "pxr/pxr.h"
++
++#include "pxr/imaging/hgi/hgi.h"
++
++PXR_NAMESPACE_OPEN_SCOPE
++
++using HgiUniquePtr = std::unique_ptr<class Hgi>;
++
++class HgiInitializationTestDriver
++{
++public:
++    HGI_API
++    HgiInitializationTestDriver();
++    
++    HGI_API
++    ~HgiInitializationTestDriver();
++
++    HGI_API
++    Hgi* GetHgi() { return _hgi.get(); }
++
++private:
++    HgiUniquePtr _hgi;
++};
++
++class HgiPipelineCreationTestDriver
++{
++public:
++    HGI_API
++    HgiPipelineCreationTestDriver();
++    
++    HGI_API
++    ~HgiPipelineCreationTestDriver();
++
++    HGI_API
++    bool CreateTestPipeline();
++
++    HGI_API
++    Hgi* GetHgi() { return _hgi.get(); }
++
++protected:
++    bool _CreateShaderProgram();
++    void _DestroyShaderProgram();
++    void _CreateVertexBufferDescriptor();
++    bool _CreatePipeline();
++    void _PrintCompileErrors();
++
++    HgiUniquePtr _hgi;
++    HgiShaderProgramHandle _shaderProgram;
++    HgiGraphicsPipelineHandle _pipeline;
++    HgiVertexBufferDesc _vboDesc;
++    HgiAttachmentDesc _colorAtt;
++    HgiAttachmentDesc _depthAtt;
++};
++
++class HgiGfxCmdBfrExecutionTestDriver : public HgiPipelineCreationTestDriver
++{
++public:
++    HGI_API
++    HgiGfxCmdBfrExecutionTestDriver();
++    
++    HGI_API
++    ~HgiGfxCmdBfrExecutionTestDriver();
++
++    HGI_API
++    bool ExecuteTestGfxCmdBfr();
++    
++    HGI_API
++    bool WriteToFile(const std::string& filePath);
++
++private:
++    GfVec3i _renderDim;
++
++    bool _CreateResourceBuffers();
++    bool _CreateRenderTargets();
++
++    HgiBufferHandle _indexBuffer;
++    HgiBufferHandle _vertexBuffer;
++
++    HgiTextureHandle _colorTarget;
++    HgiTextureViewHandle _colorTargetView;
++
++    HgiTextureHandle _depthTarget;
++    HgiTextureViewHandle _depthTargetView;
++};
++
++PXR_NAMESPACE_CLOSE_SCOPE
++
++#endif  // PXR_IMAGING_HGI_UNIT_TEST_HELPER_H
index 4776a6113c8676ae52ee808980e1e31112355b3b,4776a6113c8676ae52ee808980e1e31112355b3b..282795dc80e06e7bff015c762cac133a3b5e4cc2
@@@ -48,3 -48,3 +48,32 @@@ pxr_library(hgiG
      RESOURCE_FILES
          plugInfo.json
  )
++
++if (${PXR_HEADLESS_TEST_MODE})
++    message(STATUS "Skipping ${PXR_PACKAGE} tests because PXR_HEADLESS_TEST_MODE is ON")
++    return()
++endif()
++
++if (APPLE)
++    message(STATUS "Skipping ${PXR_PACKAGE} tests because they are currently unsupported on macOS")
++    return()
++endif()
++
++if (WIN32)
++    message(STATUS "Skipping ${PXR_PACKAGE} tests because they are currently unsupported on Windows")
++    return()
++endif()
++
++pxr_install_test_dir(
++    SRC testenv/testHgiGLCommand
++    DEST testHgiGLCommand
++)
++pxr_register_test(testHgiGLCommand
++    COMMAND "${CMAKE_INSTALL_PREFIX}/tests/testHgiCommand --write testHgiGLCommand_triangle.png"
++    IMAGE_DIFF_COMPARE
++        testHgiGLCommand_triangle.png
++    FAIL 1
++    FAIL_PERCENT 0.001
++    PERCEPTUAL
++    EXPECTED_RETURN_CODE 0
++)
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..e731671b3cc80cb918cfe4271c8cdb92738f1d38
new file mode 100644 (file)
Binary files differ
index a6811cb18667e53520ac839ad5e616493c2a1a9c,5b651b50ea121f13022995082bd57aa88ccb40ee..061c742af1ce7d9d44b39494b7031b7357ccc30a
@@@ -52,3 -52,3 +52,36 @@@ pxr_library(hgiVulka
      RESOURCE_FILES
          plugInfo.json
  )
++
++if (${PXR_HEADLESS_TEST_MODE})
++    message(STATUS "Skipping ${PXR_PACKAGE} tests because PXR_HEADLESS_TEST_MODE is ON")
++    return()
++endif()
++
++if (APPLE)
++    message(STATUS "Skipping ${PXR_PACKAGE} tests because they are currently unsupported on macOS")
++    return()
++endif()
++
++if (WIN32)
++    message(STATUS "Skipping ${PXR_PACKAGE} tests because they are currently unsupported on Windows")
++    return()
++endif()
++
++pxr_install_test_dir(
++    SRC testenv/testHgiVulkanCommand
++    DEST testHgiVulkanCommand
++)
++pxr_register_test(testHgiVulkanCommand
++    COMMAND "${CMAKE_INSTALL_PREFIX}/tests/testHgiCommand --write testHgiVulkanCommand_triangle.png"
++    # IMAGE_DIFF_COMPARE
++    #     testHgiVulkanCommand_triangle.png
++    # FAIL 1
++    # FAIL_PERCENT 0.001
++    # PERCEPTUAL
++    EXPECTED_RETURN_CODE 0
++    ENV
++        HGI_ENABLE_VULKAN=1
++        HGIVULKAN_DEBUG=1
++        HGIVULKAN_DEBUG_VERBOSE=1
++)
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..e731671b3cc80cb918cfe4271c8cdb92738f1d38
new file mode 100644 (file)
Binary files differ