Skip to content

Commit

Permalink
Image file writing, with test. (#255)
Browse files Browse the repository at this point in the history
* Image file writing, with test.

* Updated to latest dev branch requirements.

* Fix clang / g++ builds.

* Addressed code review comments and macOS build failures.
  • Loading branch information
ppt-adsk authored Feb 25, 2025
1 parent 8f846b2 commit ea8c934
Show file tree
Hide file tree
Showing 17 changed files with 770 additions and 2 deletions.
1 change: 1 addition & 0 deletions lib/flowViewport/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -113,3 +113,4 @@ add_subdirectory(sceneIndex)
add_subdirectory(API)
add_subdirectory(selection)
add_subdirectory(usdPlugins)
add_subdirectory(imageWriter)
34 changes: 34 additions & 0 deletions lib/flowViewport/imageWriter/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# -----------------------------------------------------------------------------
# sources
# -----------------------------------------------------------------------------
target_sources(${TARGET_NAME}
PRIVATE
fvpImageBufferWriter.cpp
fvpTextureBufferWriter.cpp
fvpRenderBufferWriter.cpp
fvpImageBufferWriterFactory.cpp
)

set(HEADERS
fvpImageBufferWriter.h
fvpTextureBufferWriter.h
fvpRenderBufferWriter.h
)

# -----------------------------------------------------------------------------
# promoted headers
# -----------------------------------------------------------------------------
mayaUsd_promoteHeaderList(
HEADERS
${HEADERS}
BASEDIR
${TARGET_NAME}/imageWriter
)

# -----------------------------------------------------------------------------
# install
# -----------------------------------------------------------------------------
install(FILES ${HEADERS}
DESTINATION
${CMAKE_INSTALL_PREFIX}/include/flowViewport/imageWriter
)
95 changes: 95 additions & 0 deletions lib/flowViewport/imageWriter/fvpImageBufferWriter.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
//
// Copyright 2025 Autodesk
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//

#include <flowViewport/imageWriter/fvpImageBufferWriter.h>

#include <pxr/base/tf/scoped.h>
#include <pxr/imaging/hdx/types.h>

PXR_NAMESPACE_USING_DIRECTIVE

namespace FVP_NS_DEF {

std::string ImageBufferWriter::_fileName{};

bool ImageBufferWriter::ValidSource() const
{
return ValidHandle() &&
(Width() != 0) && (Height() != 0) &&
(Format() != HioFormatInvalid);
}

bool ImageBufferWriter::Write(const std::string& fileName)
{
if (!ValidSource()) {
return false;
}

HioImage::StorageSpec storage;
storage.width = Width();
storage.height = Height();
storage.format = Format();
storage.flipped = true;
storage.data = Map();

if (!storage.data) {
return false;
}

TfScoped unmapGuard([this](){ Unmap(); });

const auto image = HioImage::OpenForWriting(fileName);
return image && image->Write(storage);
}

/* static */
bool ImageBufferWriter::Write(
const PXR_NS::VtDictionary& args,
const std::string& fileName,
const PXR_NS::TfToken& aov
)
{
auto writer = Create(args, aov);
return (writer ? writer->Write(fileName) : false);
}

/* static */
bool ImageBufferWriter::Write(
const std::string& fileName,
const HioImage::StorageSpec& storageSpec
)
{
if (!storageSpec.data) {
return false;
}

const auto image = HioImage::OpenForWriting(fileName);
return image && image->Write(storageSpec);
}

/* static */
void ImageBufferWriter::SetFileName(const std::string& fileName)
{
_fileName = fileName;
}

/* static */
std::string ImageBufferWriter::GetFileName()
{
return _fileName;
}

}
131 changes: 131 additions & 0 deletions lib/flowViewport/imageWriter/fvpImageBufferWriter.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
//
// Copyright 2025 Autodesk
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
#ifndef FVP_IMAGE_BUFFER_WRITER_H
#define FVP_IMAGE_BUFFER_WRITER_H

#include <flowViewport/api.h>

#include <pxr/pxr.h>
#include <pxr/imaging/hio/types.h>
#include <pxr/imaging/hio/image.h>
#include <pxr/imaging/hd/tokens.h>

#include <memory> // shared_ptr
#include <string>

PXR_NAMESPACE_OPEN_SCOPE
class HdEngine;
class TfToken;
class VtDictionary;
PXR_NAMESPACE_CLOSE_SCOPE

namespace FVP_NS_DEF {

/// \class ImageBufferWriter
///
/// Base class for writing Hydra images to files.
///
/// The dictionary of arguments passed to methods of this class determines
/// what kind of buffer is read:
/// - For hardware texture buffers, the dictionary must contain an Hgi*,
/// with key "hgi", and an HdEngine*, with key "engine".
/// - For software render buffers, the dictionary must contain
/// an HdxTaskController*, with key "taskController".
///
class ImageBufferWriter
{
public:

using Ptr = std::shared_ptr<ImageBufferWriter>;

FVP_API
virtual ~ImageBufferWriter() = default;

//! Factory method to create an image buffer writer.
FVP_API
static Ptr Create(
const PXR_NS::VtDictionary& args,
const PXR_NS::TfToken& aov = PXR_NS::HdAovTokens->color
);

//! Create an image buffer writer and use it to write to the file
//! path passed in as argument. Returns false if the file name is
//! empty.
//! \return true for success.
FVP_API
static bool Write(
const PXR_NS::VtDictionary& args,
const std::string& fileName,
const PXR_NS::TfToken& aov = PXR_NS::HdAovTokens->color
);

//! Utility method to write the content of the image buffer
//! described by the StorageSpec to the file path passed in as argument.
//! \return true for success.
FVP_API
static bool Write(
const std::string& fileName,
const PXR_NS::HioImage::StorageSpec& storageSpec
);

//! Utility modifier and accessor for file name to be used when calling
//! Write() overload which takes a file argument. Useful as a central
//! storage location for a file name, mostly for testing purposes, as
//! this is not thread-safe or multi-viewport ready.
FVP_API
static void SetFileName(const std::string& fileName);
FVP_API
static std::string GetFileName();

//! Write the content of the image buffer writer to the
//! file path passed in as argument.
//! \return true for success.
FVP_API
bool Write(const std::string& fileName);

FVP_API
virtual unsigned int Width() const = 0;
FVP_API
virtual unsigned int Height() const = 0;

FVP_API
virtual PXR_NS::HioFormat Format() const = 0;

FVP_API
bool ValidSource() const;

FVP_API
virtual bool ValidHandle() const = 0;

FVP_API
virtual void* Map() = 0;

FVP_API
virtual void Unmap() = 0;

protected:

FVP_API
ImageBufferWriter() = default;

private:

static std::string _fileName;
};

}

#endif
39 changes: 39 additions & 0 deletions lib/flowViewport/imageWriter/fvpImageBufferWriterFactory.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
//
// Copyright 2025 Autodesk
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//

#include <flowViewport/imageWriter/fvpTextureBufferWriter.h>
#include <flowViewport/imageWriter/fvpRenderBufferWriter.h>

#include <pxr/base/vt/dictionary.h>

namespace FVP_NS_DEF {

/* static */
ImageBufferWriter::Ptr ImageBufferWriter::Create(
const PXR_NS::VtDictionary& args,
const PXR_NS::TfToken& aov
)
{
// Can't use ternary operator because of differing std::shared_ptr types.
if (args.find("hgi") == args.end()) {
return std::make_shared<RenderBufferWriter>(args, aov);
}
else {
return std::make_shared<TextureBufferWriter>(args, aov);
}
}

}
85 changes: 85 additions & 0 deletions lib/flowViewport/imageWriter/fvpRenderBufferWriter.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
//
// Copyright 2025 Autodesk
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//

#include <flowViewport/imageWriter/fvpRenderBufferWriter.h>

#include <pxr/imaging/hdSt/hioConversions.h>
#include <pxr/imaging/hdx/taskController.h>
#include <pxr/imaging/hd/renderBuffer.h>
#include <pxr/base/vt/dictionary.h>

PXR_NAMESPACE_USING_DIRECTIVE

namespace {

HdRenderBuffer* getRenderBuffer(
const VtDictionary& args,
const PXR_NS::TfToken& aovToken
)
{
auto found = args.find("taskController");
if (found == args.end() || !found->second.IsHolding<HdxTaskController*>()) {
return nullptr;
}

auto taskController = found->second.Get<HdxTaskController*>();
return taskController ? taskController->GetRenderOutput(aovToken) : nullptr;
}

}

namespace FVP_NS_DEF {

RenderBufferWriter::RenderBufferWriter(
const PXR_NS::VtDictionary& args,
const TfToken& aov
) : ImageBufferWriter(), _renderBuffer(getRenderBuffer(args, aov))
{}

unsigned int RenderBufferWriter::Width() const
{
return _renderBuffer ? _renderBuffer->GetWidth() : 0;
}

unsigned int RenderBufferWriter::Height() const
{
return _renderBuffer ? _renderBuffer->GetHeight() : 0;
}

HioFormat RenderBufferWriter::Format() const
{
return _renderBuffer ? HdStHioConversions::GetHioFormat(
_renderBuffer->GetFormat()) : HioFormatInvalid;
}

bool RenderBufferWriter::ValidHandle() const
{
return bool(_renderBuffer);
}

void* RenderBufferWriter::Map()
{
return _renderBuffer ? _renderBuffer->Map() : nullptr;
}

void RenderBufferWriter::Unmap()
{
if (_renderBuffer) {
_renderBuffer->Unmap();
}
}

}
Loading

0 comments on commit ea8c934

Please sign in to comment.