Skip to content

Commit

Permalink
Improve .rpr export (#372)
Browse files Browse the repository at this point in the history
* Improve .rpr export

Wrap `USD Render ROP` into `RPR Export .rpr` HDA. The previous implementation of `RPR Export .rpr` was based on a really hacky python code. The new implementation relies on UsdRenderSettings primitive which is proved to be robust in all use-cases.

* Fix compilation error

* Disable .rpr export for Apprentice
  • Loading branch information
hshakula authored Oct 22, 2020
1 parent bd9e9c2 commit 0cf4e51
Show file tree
Hide file tree
Showing 10 changed files with 395 additions and 50 deletions.
19 changes: 16 additions & 3 deletions pxr/imaging/plugin/hdRpr/python/generateRenderSettingFiles.py
Original file line number Diff line number Diff line change
Expand Up @@ -373,6 +373,16 @@ def hidewhen_not_northstar(render_setting_categories):
'defaultValue': False,
},
]
},
{
'name': 'RprExport',
'settings': [
{
'name': 'rprExportPath',
'defaultValue': '',
'c_type': 'std::string'
}
]
}
]

Expand Down Expand Up @@ -573,9 +583,12 @@ class HdRprConfig {{

default_value = setting['defaultValue']

c_type_str = type(default_value).__name__
if c_type_str == 'str':
c_type_str = 'TfToken'
if 'c_type' in setting:
c_type_str = setting['c_type']
else:
c_type_str = type(default_value).__name__
if c_type_str == 'str':
c_type_str = 'TfToken'
type_str = c_type_str

if 'values' in setting:
Expand Down
8 changes: 0 additions & 8 deletions pxr/imaging/plugin/hdRpr/renderDelegate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -422,11 +422,3 @@ char* HdRprGetRenderQuality() {
void HdRprFree(void* ptr) {
free(ptr);
}

int HdRprExportRprSceneOnNextRender(const char* exportPath) {
if (!PXR_INTERNAL_NS::g_rprApi) {
return -1;
}
PXR_INTERNAL_NS::g_rprApi->ExportRprSceneOnNextRender(exportPath);
return 0;
}
2 changes: 0 additions & 2 deletions pxr/imaging/plugin/hdRpr/renderDelegate.h
Original file line number Diff line number Diff line change
Expand Up @@ -119,8 +119,6 @@ HDRPR_API char* HdRprGetRenderQuality();

HDRPR_API void HdRprFree(void* ptr);

HDRPR_API int HdRprExportRprSceneOnNextRender(const char* exportPath);

} // extern "C"

#endif // HDRPR_RENDER_DELEGATE_H
217 changes: 182 additions & 35 deletions pxr/imaging/plugin/hdRpr/rprApi.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ See the License for the specific language governing permissions and
limitations under the License.
************************************************************************/

#include <json/json.hpp>
using json = nlohmann::json;

#include "rprApi.h"
#include "rprApiAov.h"
#include "aovDescriptor.h"
Expand Down Expand Up @@ -54,6 +57,10 @@ limitations under the License.
#include <RadeonProRender_Baikal.h>
#include <RprLoadStore.h>

#ifdef BUILD_AS_HOUDINI_PLUGIN
#include <HOM/HOM_Module.h>
#endif // BUILD_AS_HOUDINI_PLUGIN

#include <fstream>
#include <chrono>
#include <vector>
Expand Down Expand Up @@ -1342,6 +1349,10 @@ class HdRprApiImpl {
instantaneousShutter.isDirty = config->IsDirty(HdRprConfig::DirtyUsdNativeCamera);
instantaneousShutter.value = config->GetInstantaneousShutter();

if (config->IsDirty(HdRprConfig::DirtyRprExport)) {
m_rprSceneExportPath = config->GetRprExportPath();
}

if (config->IsDirty(HdRprConfig::DirtyRenderQuality)) {
m_currentRenderQuality = GetRenderQuality(*config);
}
Expand Down Expand Up @@ -1956,31 +1967,7 @@ class HdRprApiImpl {
}

if (!m_rprSceneExportPath.empty()) {
std::string exportPath;
{
std::lock_guard<std::mutex> lock(m_rprSceneExportPathMutex);
std::swap(m_rprSceneExportPath, exportPath);
}
if (!exportPath.empty()) {
uint32_t currentYFlip;
if (m_isOutputFlipped) {
currentYFlip = RprUsdGetInfo<uint32_t>(m_rprContext.get(), RPR_CONTEXT_Y_FLIP);

currentYFlip = !currentYFlip;
RPR_ERROR_CHECK_THROW(m_rprContext->SetParameter(RPR_CONTEXT_Y_FLIP, currentYFlip), "Failed to set context Y FLIP parameter");
}

auto rprContextHandle = rpr::GetRprObject(m_rprContext.get());
auto rprSceneHandle = rpr::GetRprObject(m_scene.get());
if (!RPR_ERROR_CHECK(rprsExport(exportPath.c_str(), rprContextHandle, rprSceneHandle, 0, nullptr, nullptr, 0, nullptr, nullptr, 0), "Failed to export .rpr file")) {
printf("Successfully exported \"%s\"\n", exportPath.c_str());
}

if (m_isOutputFlipped) {
currentYFlip = !currentYFlip;
RPR_ERROR_CHECK_THROW(m_rprContext->SetParameter(RPR_CONTEXT_Y_FLIP, currentYFlip), "Failed to set context Y FLIP parameter");
}
}
return ExportRpr();
}

if (m_state == kStateRender) {
Expand Down Expand Up @@ -2014,6 +2001,171 @@ Don't show this message again?
}
}

void ExportRpr() {
#ifdef BUILD_AS_HOUDINI_PLUGIN
if (HOM().isApprentice()) {
fprintf(stderr, "Cannot export .rpr from Apprentice");
return;
}
#endif // BUILD_AS_HOUDINI_PLUGIN

uint32_t currentYFlip;
if (m_isOutputFlipped) {
currentYFlip = RprUsdGetInfo<uint32_t>(m_rprContext.get(), RPR_CONTEXT_Y_FLIP);

currentYFlip = !currentYFlip;
RPR_ERROR_CHECK(m_rprContext->SetParameter(RPR_CONTEXT_Y_FLIP, currentYFlip), "Failed to set context Y FLIP parameter");
}

auto rprContextHandle = rpr::GetRprObject(m_rprContext.get());
auto rprSceneHandle = rpr::GetRprObject(m_scene.get());
if (RPR_ERROR_CHECK(rprsExport(m_rprSceneExportPath.c_str(), rprContextHandle, rprSceneHandle, 0, nullptr, nullptr, 0, nullptr, nullptr, 0), "Failed to export .rpr file")) {
return;
}

if (m_isOutputFlipped) {
currentYFlip = !currentYFlip;
RPR_ERROR_CHECK(m_rprContext->SetParameter(RPR_CONTEXT_Y_FLIP, currentYFlip), "Failed to set context Y FLIP parameter");
}

TfStringReplace(m_rprSceneExportPath, ".rpr", ".json");
auto configFilename = m_rprSceneExportPath.substr(0, m_rprSceneExportPath.size() - 4) + ".json";
std::ofstream configFile(configFilename);
if (!configFile.is_open()) {
fprintf(stderr, "Failed to create config file: %s\n", configFilename.c_str());
return;
}

try {
json config;
config["width"] = m_viewportSize[0];
config["height"] = m_viewportSize[1];
config["iterations"] = m_maxSamples;
config["batchsize"] = m_maxSamples;

auto basename = TfStringGetBeforeSuffix(TfGetBaseName(m_rprSceneExportPath));
config["output"] = basename + ".exr";
config["output.json"] = basename + ".output.json";

static std::map<rpr_creation_flags, const char*> kRprsContextFlags = {
{RPR_CREATION_FLAGS_ENABLE_CPU, "cpu"},
{RPR_CREATION_FLAGS_ENABLE_DEBUG, "debug"},
{RPR_CREATION_FLAGS_ENABLE_GPU0, "gpu0"},
{RPR_CREATION_FLAGS_ENABLE_GPU1, "gpu1"},
{RPR_CREATION_FLAGS_ENABLE_GPU2, "gpu2"},
{RPR_CREATION_FLAGS_ENABLE_GPU3, "gpu3"},
{RPR_CREATION_FLAGS_ENABLE_GPU4, "gpu4"},
{RPR_CREATION_FLAGS_ENABLE_GPU5, "gpu5"},
{RPR_CREATION_FLAGS_ENABLE_GPU6, "gpu6"},
{RPR_CREATION_FLAGS_ENABLE_GPU7, "gpu7"},
{RPR_CREATION_FLAGS_ENABLE_GPU8, "gpu8"},
{RPR_CREATION_FLAGS_ENABLE_GPU9, "gpu9"},
{RPR_CREATION_FLAGS_ENABLE_GPU10, "gpu10"},
{RPR_CREATION_FLAGS_ENABLE_GPU11, "gpu11"},
{RPR_CREATION_FLAGS_ENABLE_GPU12, "gpu12"},
{RPR_CREATION_FLAGS_ENABLE_GPU13, "gpu13"},
{RPR_CREATION_FLAGS_ENABLE_GPU14, "gpu14"},
{RPR_CREATION_FLAGS_ENABLE_GPU15, "gpu15"},
};

json context;
auto creationFlags = RprUsdGetInfo<uint32_t>(m_rprContext.get(), RPR_CONTEXT_CREATION_FLAGS);
for (auto& entry : kRprsContextFlags) {
if (creationFlags & entry.first) {
context[entry.second] = 1;
}
}
if (creationFlags & RPR_CREATION_FLAGS_ENABLE_CPU) {
context["threads"] = RprUsdGetInfo<uint32_t>(m_rprContext.get(), RPR_CONTEXT_CPU_THREAD_LIMIT);
}
config["context"] = context;

static const char* kRprsAovNames[] = {
/* RPR_AOV_COLOR = */ "color",
/* RPR_AOV_OPACITY = */ "opacity",
/* RPR_AOV_WORLD_COORDINATE = */ "world.coordinate",
/* RPR_AOV_UV = */ "uv",
/* RPR_AOV_MATERIAL_ID = */ "material.id",
/* RPR_AOV_GEOMETRIC_NORMAL = */ "geometric.normal",
/* RPR_AOV_SHADING_NORMAL = */ "shading.normal",
/* RPR_AOV_DEPTH = */ "depth",
/* RPR_AOV_OBJECT_ID = */ "object.id",
/* RPR_AOV_OBJECT_GROUP_ID = */ "object.group.id",
/* RPR_AOV_SHADOW_CATCHER = */ "shadow.catcher",
/* RPR_AOV_BACKGROUND = */ "background",
/* RPR_AOV_EMISSION = */ "emission",
/* RPR_AOV_VELOCITY = */ "velocity",
/* RPR_AOV_DIRECT_ILLUMINATION = */ "direct.illumination",
/* RPR_AOV_INDIRECT_ILLUMINATION = */ "indirect.illumination",
/* RPR_AOV_AO = */ "ao",
/* RPR_AOV_DIRECT_DIFFUSE = */ "direct.diffuse",
/* RPR_AOV_DIRECT_REFLECT = */ "direct.reflect",
/* RPR_AOV_INDIRECT_DIFFUSE = */ "indirect.diffuse",
/* RPR_AOV_INDIRECT_REFLECT = */ "indirect.reflect",
/* RPR_AOV_REFRACT = */ "refract",
/* RPR_AOV_VOLUME = */ "volume",
/* RPR_AOV_LIGHT_GROUP0 = */ "light.group0",
/* RPR_AOV_LIGHT_GROUP1 = */ "light.group1",
/* RPR_AOV_LIGHT_GROUP2 = */ "light.group2",
/* RPR_AOV_LIGHT_GROUP3 = */ "light.group3",
/* RPR_AOV_DIFFUSE_ALBEDO = */ "diffuse.albedo",
/* RPR_AOV_VARIANCE = */ "variance",
/* RPR_AOV_VIEW_SHADING_NORMAL = */ "view.shading.normal",
/* RPR_AOV_REFLECTION_CATCHER = */ "reflection.catcher",
/* RPR_AOV_COLOR_RIGHT = */ "color.right",
/* RPR_AOV_LPE_0 = */ "lpe0",
/* RPR_AOV_LPE_1 = */ "lpe1",
/* RPR_AOV_LPE_2 = */ "lpe2",
/* RPR_AOV_LPE_3 = */ "lpe3",
/* RPR_AOV_LPE_4 = */ "lpe4",
/* RPR_AOV_LPE_5 = */ "lpe5",
/* RPR_AOV_LPE_6 = */ "lpe6",
/* RPR_AOV_LPE_7 = */ "lpe7",
/* RPR_AOV_LPE_8 = */ "lpe8",
};
static const size_t kNumRprsAovNames = sizeof(kRprsAovNames) / sizeof(kRprsAovNames[0]);

json configAovs;
for (auto& outputRb : m_outputRenderBuffers) {
auto aovDesc = &outputRb.rprAov->GetDesc();
if (aovDesc->computed) {
if (aovDesc->id == kColorAlpha) {
aovDesc = &HdRprAovRegistry::GetInstance().GetAovDesc(RPR_AOV_COLOR, false);
} else if (aovDesc->id == kNdcDepth) {
// RprsRender does not support it...yet?
continue;
} else {
fprintf(stderr, "Unprocessed computed AOV: %u\n", aovDesc->id);
continue;
}
}

if (TF_VERIFY(aovDesc->id < kNumRprsAovNames) &&
TF_VERIFY(!aovDesc->computed)) {
auto aovName = kRprsAovNames[aovDesc->id];
auto outputName = TfStringPrintf("%s.%s.exr", basename.c_str(), aovName);
if (aovDesc->id >= RPR_AOV_LPE_0 && aovDesc->id <= RPR_AOV_LPE_8) {
try {
json lpeAov;
lpeAov["output"] = outputName;
lpeAov["lpe"] = RprUsdGetInfo<std::string>(outputRb.rprAov->GetAovFb()->GetRprObject(), RPR_FRAMEBUFFER_LPE);
configAovs[aovName] = lpeAov;
} catch (RprUsdError& e) {
fprintf(stderr, "Failed to export %s AOV: %s\n", aovName, e.what());
}
} else {
configAovs[aovName] = outputName;
}
}
}
config["aovs"] = configAovs;

configFile << config;
} catch (json::exception& e) {
fprintf(stderr, "Failed to fill config file: %s\n", configFilename.c_str());
}
}

void CommitResources() {
if (!m_rprContext) {
return;
Expand Down Expand Up @@ -2049,6 +2201,11 @@ Don't show this message again?
HdRprApi::RenderStats GetRenderStats() const {
HdRprApi::RenderStats stats = {};

// rprsExport has no progress callback
if (!m_rprSceneExportPath.empty()) {
return stats;
}

double progress = double(m_numSamples) / m_maxSamples;
if (m_activePixels != -1) {
int numPixels = m_viewportSize[0] * m_viewportSize[1];
Expand Down Expand Up @@ -2122,11 +2279,6 @@ Don't show this message again?
return m_currentRenderQuality;
}

void ExportRprSceneOnNextRender(const char* exportPath) {
std::lock_guard<std::mutex> lock(m_rprSceneExportPathMutex);
m_rprSceneExportPath = exportPath;
}

private:
static RprUsdPluginType GetPluginType(TfToken const& renderQuality) {
if (renderQuality == HdRprRenderQualityTokens->Full) {
Expand Down Expand Up @@ -2915,7 +3067,6 @@ Don't show this message again?
std::atomic<bool> m_isAbortingEnabled;
std::atomic<bool> m_abortRender;

std::mutex m_rprSceneExportPathMutex;
std::string m_rprSceneExportPath;
};

Expand Down Expand Up @@ -3191,10 +3342,6 @@ TfToken const& HdRprApi::GetCurrentRenderQuality() const {
return m_impl->GetCurrentRenderQuality();
}

void HdRprApi::ExportRprSceneOnNextRender(const char* exportPath) {
m_impl->ExportRprSceneOnNextRender(exportPath);
}

std::string HdRprApi::GetAppDataPath() {
auto appDataPath = []() -> std::string {
#ifdef WIN32
Expand Down
1 change: 0 additions & 1 deletion pxr/imaging/plugin/hdRpr/rprApi.h
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,6 @@ class HdRprApi final {
bool IsArbitraryShapedLightSupported() const;
bool IsSphereAndDiskLightSupported() const;
TfToken const& GetCurrentRenderQuality() const;
void ExportRprSceneOnNextRender(const char* exportPath);

static std::string GetAppDataPath();
static std::string GetCachePath();
Expand Down
7 changes: 6 additions & 1 deletion pxr/imaging/plugin/rprHoudini/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,14 @@ endif()
add_library(RPR_for_Houdini SHARED
plugin.cpp
VOP_RPRMaterial.h
VOP_RPRMaterial.cpp)
VOP_RPRMaterial.cpp
LOP_RPRExportHelper.h
LOP_RPRExportHelper.cpp)

target_link_libraries(RPR_for_Houdini
usd
usdGeom
usdRender
rprUsd
Houdini)

Expand Down
Loading

0 comments on commit 0cf4e51

Please sign in to comment.