Compare commits
4
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4d78c72a77 | ||
|
|
442f84f3d6 | ||
|
|
977da20d32 | ||
|
|
872ae0504e |
+1803
-1750
File diff suppressed because it is too large
Load Diff
+36
-1
@@ -11,4 +11,39 @@ endmacro()
|
||||
|
||||
oidn_add_app(oidnDenoise oidnDenoise.cpp)
|
||||
oidn_add_app(oidnBenchmark oidnBenchmark.cpp)
|
||||
oidn_add_app(oidnTest oidnTest.cpp "${PROJECT_SOURCE_DIR}/external/catch.hpp")
|
||||
oidn_add_app(oidnTest oidnTest.cpp "${PROJECT_SOURCE_DIR}/external/catch.hpp")
|
||||
|
||||
|
||||
|
||||
if(OIDN_INTEROP_TEST)
|
||||
find_package(OpenImageIO REQUIRED)
|
||||
|
||||
if(WIN32)
|
||||
set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreadedDLL")
|
||||
add_executable(oidnInteropTest oidnInteropTest.cpp ${OIDN_RESOURCE_FILE})
|
||||
set_property(TARGET oidnInteropTest PROPERTY CXX_STANDARD 17)
|
||||
target_link_libraries(oidnInteropTest PRIVATE
|
||||
OpenImageIO::OpenImageIO
|
||||
OpenImageDenoise_common
|
||||
#OpenImageDenoise_utils
|
||||
OpenImageDenoise
|
||||
d3d12
|
||||
dxgi
|
||||
dxguid
|
||||
)
|
||||
else()
|
||||
find_package(Vulkan REQUIRED)
|
||||
add_executable(oidnInteropTest oidnInteropTest.cpp ${OIDN_RESOURCE_FILE})
|
||||
set_property(TARGET oidnInteropTest PROPERTY CXX_STANDARD 17)
|
||||
target_link_libraries(oidnInteropTest PRIVATE
|
||||
Vulkan::Vulkan
|
||||
OpenImageIO::OpenImageIO
|
||||
OpenImageDenoise_common
|
||||
OpenImageDenoise_utils
|
||||
OpenImageDenoise
|
||||
)
|
||||
endif()
|
||||
|
||||
|
||||
|
||||
endif()
|
||||
@@ -0,0 +1,150 @@
|
||||
#ifdef _WIN32
|
||||
#include "oidnInteropTestDX.h"
|
||||
#else
|
||||
#include "oidnInteropTestVk.h"
|
||||
#endif
|
||||
|
||||
std::string usage() {
|
||||
return
|
||||
"Usage:\n"
|
||||
" oidnInteropTest - run oidn using directX/Vulkan interop\n"
|
||||
"\n"
|
||||
"SYNOPSIS\n"
|
||||
" oidnInteropTest --json <path> [OPTION]\n"
|
||||
"\n"
|
||||
"OPTIONS\n"
|
||||
" --scale <float> - scaling factor\n"
|
||||
" --out <ext> - extension of the out files, i.e. <path>.out.<n>.exr, default = out\n"
|
||||
" --help - print this help\n"
|
||||
" --verbose - vebose console output\n"
|
||||
;
|
||||
}
|
||||
|
||||
bool has_arg(const std::string& pname, std::vector<std::string>& args) {
|
||||
auto p = std::find(args.begin(), args.end(), pname);
|
||||
return p != args.end();
|
||||
}
|
||||
|
||||
bool has_param(const std::string& pname, std::vector<std::string>& args) {
|
||||
auto p = std::find(args.begin(), args.end(), pname);
|
||||
return p != args.end() && (p+1) != args.end();
|
||||
}
|
||||
|
||||
std::string parse(const std::string& pname, std::vector<std::string>& args) {
|
||||
auto p = std::find(args.begin(), args.end(), pname);
|
||||
if (p == args.end()) {
|
||||
throw std::runtime_error("could not parse parameter: " + pname + "\n" + usage());
|
||||
}
|
||||
|
||||
++p;
|
||||
if (p == args.end()) {
|
||||
throw std::runtime_error("could not parse parameter: " + pname + "\n" + usage());
|
||||
}
|
||||
|
||||
return *p;
|
||||
}
|
||||
|
||||
std::string parse_opt(const std::string& pname, std::vector<std::string>& args, std::string def = "") {
|
||||
return has_param(pname, args)? parse(pname, args) : def;
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
std::vector<std::string> args(argv + 1, argv + argc);
|
||||
|
||||
if (has_arg("--help", args)) {
|
||||
std::cout << usage() << std::endl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
auto path_in = parse("--in", args);
|
||||
auto path_color = path_in + ".hdr.exr";
|
||||
auto path_albedo = path_in + ".alb1.exr";
|
||||
auto path_normal = path_in + ".nrm1.exr";
|
||||
|
||||
auto path_out = parse_opt("--out", args, "./out.exr");
|
||||
auto scale = std::stof(parse_opt("--scale", args, "2.0f"));
|
||||
|
||||
std::cout << "oidn interop test" << std::endl;
|
||||
std::cout << " color: " << path_color << std::endl;
|
||||
std::cout << " albedo: " << path_albedo << std::endl;
|
||||
std::cout << " normal: " << path_normal << std::endl;
|
||||
std::cout << " output: " << path_out << std::endl;
|
||||
std::cout << " scale: " << scale << std::endl;
|
||||
|
||||
|
||||
#ifdef _WIN32
|
||||
InteropTestDX test;
|
||||
#else
|
||||
InteropTestVk test;
|
||||
#endif
|
||||
|
||||
std::cout << "Setting up OIDN device" << std::endl;
|
||||
test.setup_oidn_device();
|
||||
|
||||
oidn::DeviceType deviceType = test.oidn_device.get<oidn::DeviceType>("type");
|
||||
const int versionMajor = test.oidn_device.get<int>("versionMajor");
|
||||
const int versionMinor = test.oidn_device.get<int>("versionMinor");
|
||||
const int versionPatch = test.oidn_device.get<int>("versionPatch");
|
||||
|
||||
std::cout << std::setw(15) << std::left << "OIDN Device: ";
|
||||
switch (deviceType)
|
||||
{
|
||||
case oidn::DeviceType::Default: std::cout << std::setw(30) << std::left << "default"; break;
|
||||
case oidn::DeviceType::CPU: std::cout << std::setw(30) << std::left << "CPU"; break;
|
||||
case oidn::DeviceType::SYCL: std::cout << std::setw(30) << std::left << "SYCL"; break;
|
||||
case oidn::DeviceType::CUDA: std::cout << std::setw(30) << std::left << "CUDA"; break;
|
||||
case oidn::DeviceType::HIP: std::cout << std::setw(30) << std::left << "HIP"; break;
|
||||
case oidn::DeviceType::Metal: std::cout << std::setw(30) << std::left << "Metal"; break;
|
||||
default:
|
||||
throw std::invalid_argument("invalid device type");
|
||||
}
|
||||
|
||||
std::cout << "Version: " << versionMajor << "." << versionMinor << "." << versionPatch << std::endl;
|
||||
|
||||
|
||||
auto color = test.load_exr(path_color);
|
||||
auto albedo = test.load_exr(path_albedo);
|
||||
auto normal = test.load_exr(path_normal);
|
||||
|
||||
uint32_t render_width, render_height, target_width, target_height;
|
||||
{
|
||||
render_width = color.get_width();
|
||||
render_height = color.get_height();
|
||||
target_width = render_width * scale;
|
||||
target_height = render_height * scale;
|
||||
|
||||
std::cout << render_height << " x " << render_width << " -> "
|
||||
<< target_height << " x " << target_width << std::endl;
|
||||
}
|
||||
|
||||
ImageBuffer out = test.create_buffer(target_width, target_height, oidn::Format::Half3);
|
||||
|
||||
// Initialize the denoising filter
|
||||
std::cout << "Initializing filter" << std::endl;
|
||||
oidn::FilterRef filter = test.oidn_device.newFilter("RT");
|
||||
|
||||
auto oidn_color = test.create_oidn_buffer(color);
|
||||
auto oidn_albedo = test.create_oidn_buffer(albedo);
|
||||
auto oidn_normal = test.create_oidn_buffer(normal);
|
||||
|
||||
auto oidn_out = test.create_oidn_buffer(out);
|
||||
|
||||
filter.setImage("color", oidn_color, color.get_format(), color.get_width(), color.get_height());
|
||||
filter.setImage("albedo", oidn_albedo, albedo.get_format(), albedo.get_width(), albedo.get_height());
|
||||
filter.setImage("normal", oidn_normal, normal.get_format(), normal.get_width(), normal.get_height());
|
||||
|
||||
filter.setImage("output", oidn_out, out.get_format(), out.get_width(), out.get_height());
|
||||
|
||||
filter.set("hdr", true);
|
||||
filter.set("inputScale", scale);
|
||||
filter.set("quality", oidn::Quality::Default);
|
||||
|
||||
filter.commit();
|
||||
|
||||
filter.execute();
|
||||
|
||||
test.save_exr(out, "./out.exr");
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,447 @@
|
||||
#include <windows.h>
|
||||
#include <wrl.h>
|
||||
#include <d3d12.h>
|
||||
#include <dxgi1_6.h>
|
||||
|
||||
#include <vector>
|
||||
#include <optional>
|
||||
#include <set>
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
#include <algorithm>
|
||||
#include <cstring>
|
||||
|
||||
#include "OpenImageIO/imageio.h"
|
||||
|
||||
#include "OpenImageDenoise/oidn.hpp"
|
||||
|
||||
using Microsoft::WRL::ComPtr;
|
||||
|
||||
class CmdList {
|
||||
public:
|
||||
CmdList(ComPtr<ID3D12Device> device) {
|
||||
if (FAILED(device->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, IID_PPV_ARGS(&commandAllocator)))) {
|
||||
throw std::runtime_error("Failed to create command allocator.");
|
||||
}
|
||||
|
||||
if (FAILED(device->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, commandAllocator.Get(), nullptr, IID_PPV_ARGS(&commandList)))) {
|
||||
throw std::runtime_error("Failed to create command list.");
|
||||
}
|
||||
}
|
||||
|
||||
CmdList(const CmdList& other) = delete;
|
||||
CmdList& operator=(const CmdList& other) = delete;
|
||||
CmdList(CmdList&& other) noexcept : commandList(std::move(other.commandList)) {}
|
||||
CmdList& operator=(CmdList&& other) noexcept {
|
||||
if (this != &other) {
|
||||
commandList = std::move(other.commandList);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
~CmdList() {
|
||||
if (commandList) {
|
||||
std::cout << "Releasing command list." << std::endl;
|
||||
commandList.Reset();
|
||||
commandAllocator.Reset();
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
ID3D12GraphicsCommandList* operator->() { return commandList.Get(); }
|
||||
ID3D12GraphicsCommandList& operator*() { return *commandList.Get(); }
|
||||
|
||||
void closeAndWait(ComPtr<ID3D12Device>& device, ComPtr<ID3D12CommandQueue>& commandQueue) {
|
||||
// Close and execute command list
|
||||
if (FAILED(commandList->Close())) {
|
||||
throw std::runtime_error("Failed to close command list.");
|
||||
}
|
||||
ID3D12CommandList* ppCommandLists[] = { commandList.Get() };
|
||||
commandQueue->ExecuteCommandLists(1, ppCommandLists);
|
||||
|
||||
// Create fence for synchronization
|
||||
ComPtr<ID3D12Fence> fence;
|
||||
if (FAILED(device->CreateFence(0, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(&fence)))) {
|
||||
throw std::runtime_error("Failed to create fence.");
|
||||
}
|
||||
HANDLE fenceEvent = CreateEvent(nullptr, FALSE, FALSE, nullptr);
|
||||
if (!fenceEvent) {
|
||||
throw std::runtime_error("Failed to create fence event.");
|
||||
}
|
||||
UINT64 fenceValue = 1;
|
||||
if (FAILED(commandQueue->Signal(fence.Get(), fenceValue))) {
|
||||
CloseHandle(fenceEvent);
|
||||
throw std::runtime_error("Failed to signal fence.");
|
||||
}
|
||||
if (fence->GetCompletedValue() < fenceValue) {
|
||||
if (FAILED(fence->SetEventOnCompletion(fenceValue, fenceEvent))) {
|
||||
CloseHandle(fenceEvent);
|
||||
throw std::runtime_error("Failed to set event on completion.");
|
||||
}
|
||||
WaitForSingleObject(fenceEvent, INFINITE);
|
||||
}
|
||||
CloseHandle(fenceEvent);
|
||||
}
|
||||
|
||||
private:
|
||||
ComPtr<ID3D12CommandAllocator> commandAllocator;
|
||||
ComPtr<ID3D12GraphicsCommandList> commandList;
|
||||
};
|
||||
|
||||
|
||||
class Buffer {
|
||||
public:
|
||||
Buffer(ComPtr<ID3D12Device> device, size_t size, D3D12_HEAP_TYPE heapType, D3D12_HEAP_FLAGS heapFlags, D3D12_RESOURCE_FLAGS resourceFlags, D3D12_RESOURCE_STATES state): size(size) {
|
||||
// Describe the buffer
|
||||
D3D12_RESOURCE_DESC bufferDesc = {};
|
||||
bufferDesc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
|
||||
bufferDesc.Alignment = 0;
|
||||
bufferDesc.Width = size;
|
||||
bufferDesc.Height = 1;
|
||||
bufferDesc.DepthOrArraySize = 1;
|
||||
bufferDesc.MipLevels = 1;
|
||||
bufferDesc.Format = DXGI_FORMAT_UNKNOWN;
|
||||
bufferDesc.SampleDesc.Count = 1;
|
||||
bufferDesc.SampleDesc.Quality = 0;
|
||||
bufferDesc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
|
||||
bufferDesc.Flags = resourceFlags;
|
||||
|
||||
// Heap properties for shared resource
|
||||
D3D12_HEAP_PROPERTIES heapProps = {};
|
||||
heapProps.Type = heapType;
|
||||
heapProps.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN;
|
||||
heapProps.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN;
|
||||
heapProps.CreationNodeMask = 1;
|
||||
heapProps.VisibleNodeMask = 1;
|
||||
|
||||
// Create the buffer resource
|
||||
HRESULT hr = device->CreateCommittedResource(
|
||||
&heapProps,
|
||||
heapFlags,
|
||||
&bufferDesc,
|
||||
state,
|
||||
nullptr,
|
||||
IID_PPV_ARGS(&buffer)
|
||||
);
|
||||
if (FAILED(hr)) {
|
||||
throw std::runtime_error("Failed to create buffer resource.");
|
||||
}
|
||||
std::cout << "Buffer resource created successfully." << std::endl;
|
||||
}
|
||||
|
||||
static Buffer make_image_buffer(ComPtr<ID3D12Device>& device, uint32_t width, uint32_t height, oidn::Format format) {
|
||||
size_t size_bytes = 0;
|
||||
switch (format) {
|
||||
case oidn::Format::Undefined: size_bytes = 0; break;
|
||||
case oidn::Format::Float: size_bytes = sizeof(float); break;
|
||||
case oidn::Format::Float2: size_bytes = sizeof(float)*2; break;
|
||||
case oidn::Format::Float3: size_bytes = sizeof(float)*3; break;
|
||||
case oidn::Format::Float4: size_bytes = sizeof(float)*4; break;
|
||||
case oidn::Format::Half: size_bytes = sizeof(int16_t); break;
|
||||
case oidn::Format::Half2: size_bytes = sizeof(int16_t)*2; break;
|
||||
case oidn::Format::Half3: size_bytes = sizeof(int16_t)*3; break;
|
||||
case oidn::Format::Half4: size_bytes = sizeof(int16_t)*4; break;
|
||||
default:
|
||||
throw std::invalid_argument("invalid format");
|
||||
}
|
||||
|
||||
size_bytes = size_bytes * width * height;
|
||||
|
||||
return Buffer(device, size_bytes, D3D12_HEAP_TYPE_DEFAULT, D3D12_HEAP_FLAG_SHARED, D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS, D3D12_RESOURCE_STATE_UNORDERED_ACCESS);
|
||||
}
|
||||
|
||||
static Buffer make_staging_buffer(ComPtr<ID3D12Device> device, size_t size, char rw) {
|
||||
D3D12_HEAP_TYPE heapType;
|
||||
D3D12_RESOURCE_STATES state;
|
||||
if (rw == 'w') {
|
||||
heapType = D3D12_HEAP_TYPE_UPLOAD;
|
||||
state = D3D12_RESOURCE_STATE_GENERIC_READ;
|
||||
} else if (rw == 'r') {
|
||||
heapType = D3D12_HEAP_TYPE_READBACK;
|
||||
state = D3D12_RESOURCE_STATE_COPY_DEST;
|
||||
} else {
|
||||
throw std::invalid_argument("rw must be 'r' or 'w'");
|
||||
}
|
||||
|
||||
return Buffer(device, size, heapType, D3D12_HEAP_FLAG_NONE, D3D12_RESOURCE_FLAG_NONE, state);
|
||||
}
|
||||
|
||||
Buffer(const Buffer& other) = delete;
|
||||
Buffer& operator=(const Buffer& other) = delete;
|
||||
Buffer(Buffer&& other) noexcept
|
||||
: size(other.size), buffer(std::move(other.buffer))
|
||||
{
|
||||
other.size = 0;
|
||||
other.buffer = nullptr;
|
||||
}
|
||||
Buffer& operator=(Buffer&& other) noexcept
|
||||
{
|
||||
if (this != &other)
|
||||
{
|
||||
size = other.size;
|
||||
buffer = std::move(other.buffer);
|
||||
other.size = 0;
|
||||
other.buffer = nullptr;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
~Buffer() {
|
||||
if (buffer) {
|
||||
std::cout << "Releasing buffer resource." << std::endl;
|
||||
buffer.Reset();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public:
|
||||
operator ComPtr<ID3D12Resource>() const { return get(); }
|
||||
ComPtr<ID3D12Resource> get() const { return buffer; }
|
||||
size_t get_size() const { return size; }
|
||||
|
||||
private:
|
||||
size_t size;
|
||||
ComPtr<ID3D12Resource> buffer = nullptr;
|
||||
};
|
||||
|
||||
|
||||
|
||||
class ImageBuffer {
|
||||
public:
|
||||
ImageBuffer(ComPtr<ID3D12Device>& device, uint32_t width, uint32_t height, oidn::Format format)
|
||||
: buffer(Buffer::make_image_buffer(device, width, height, format)),
|
||||
width(width), height(height), format(format) {}
|
||||
|
||||
ImageBuffer(const ImageBuffer&) = delete;
|
||||
ImageBuffer& operator=(const ImageBuffer&) = delete;
|
||||
ImageBuffer(ImageBuffer&&) = default;
|
||||
ImageBuffer& operator=(ImageBuffer&&) = default;
|
||||
|
||||
~ImageBuffer() = default;
|
||||
|
||||
|
||||
public:
|
||||
static ImageBuffer load_exr(std::string filename, ComPtr<ID3D12Device>& device, ComPtr<ID3D12CommandQueue>& commandQueue) {
|
||||
auto in = OIIO::ImageInput::open(filename);
|
||||
if (!in) {
|
||||
throw std::runtime_error("failed to open image file");
|
||||
}
|
||||
|
||||
OIIO::ImageSpec spec = in->spec();
|
||||
if ((spec.channelformat(0) == OIIO::TypeDesc::FLOAT || spec.channelformat(0) == OIIO::TypeDesc::HALF) && (spec.nchannels < 1 || spec.nchannels > 4)) {
|
||||
throw std::invalid_argument("unsupported format");
|
||||
}
|
||||
|
||||
int width = spec.width;
|
||||
int height = spec.height;
|
||||
int nchannels = spec.nchannels;
|
||||
std::vector<oidn::Format> formats = {oidn::Format::Float, oidn::Format::Float2, oidn::Format::Float3, oidn::Format::Float4,
|
||||
oidn::Format::Half, oidn::Format::Half2, oidn::Format::Half3, oidn::Format::Half4};
|
||||
oidn::Format format = formats[spec.channelformat(0) == OIIO::TypeDesc::FLOAT ? nchannels - 1 : nchannels + 3];
|
||||
|
||||
|
||||
ImageBuffer buffer(device, width, height, format);
|
||||
Buffer stagingBuffer = Buffer::make_staging_buffer(device, buffer.buffer.get_size(), 'w');
|
||||
|
||||
auto stagingResource = stagingBuffer.get();
|
||||
|
||||
void* mapped = nullptr;
|
||||
stagingResource->Map(0, nullptr, &mapped);
|
||||
in->read_image(0, 0, 0, nchannels, spec.channelformat(0), mapped);
|
||||
D3D12_RANGE readingRange = {0, buffer.buffer.get_size()};
|
||||
stagingResource->Unmap(0, &readingRange);
|
||||
in->close();
|
||||
|
||||
CmdList cl(device);
|
||||
// Transition buffer to COPY_DEST
|
||||
D3D12_RESOURCE_BARRIER barrier = {};
|
||||
barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
|
||||
barrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
|
||||
barrier.Transition.pResource = buffer.get_buffer().get().Get();
|
||||
barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_UNORDERED_ACCESS;
|
||||
barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_COPY_DEST;
|
||||
barrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
|
||||
cl->ResourceBarrier(1, &barrier);
|
||||
|
||||
// Copy data from staging buffer to buffer
|
||||
cl->CopyResource(buffer.get_buffer().get().Get(), stagingBuffer.get().Get());
|
||||
|
||||
// Transition buffer back to UNORDERED_ACCESS
|
||||
std::swap(barrier.Transition.StateBefore, barrier.Transition.StateAfter);
|
||||
cl->ResourceBarrier(1, &barrier);
|
||||
|
||||
cl.closeAndWait(device, commandQueue);
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
void save_exr(std::string filename, ComPtr<ID3D12Device>& device, ComPtr<ID3D12CommandQueue>& commandQueue) {
|
||||
// Create a staging buffer to copy the data to
|
||||
Buffer stagingBuffer = Buffer::make_staging_buffer(device, buffer.get_size(), 'r');
|
||||
|
||||
// Create command list for copy operation
|
||||
CmdList cl(device);
|
||||
|
||||
// Transition buffer to COPY_SOURCE
|
||||
D3D12_RESOURCE_BARRIER barrier = {};
|
||||
barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
|
||||
barrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
|
||||
barrier.Transition.pResource = buffer.get().Get();
|
||||
barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_UNORDERED_ACCESS;
|
||||
barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_COPY_SOURCE;
|
||||
barrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
|
||||
cl->ResourceBarrier(1, &barrier);
|
||||
|
||||
// Copy buffer to staging
|
||||
cl->CopyResource(stagingBuffer.get().Get(), buffer.get().Get());
|
||||
|
||||
// Transition buffer back to UNORDERED_ACCESS
|
||||
std::swap(barrier.Transition.StateBefore, barrier.Transition.StateAfter);
|
||||
cl->ResourceBarrier(1, &barrier);
|
||||
|
||||
cl.closeAndWait(device, commandQueue);
|
||||
|
||||
|
||||
// create output file
|
||||
std::unique_ptr<OIIO::ImageOutput> out = OIIO::ImageOutput::create(filename);
|
||||
if (!out) {
|
||||
throw std::runtime_error("Could not create file: " + filename);
|
||||
}
|
||||
|
||||
std::vector<oidn::Format> formats = {oidn::Format::Float, oidn::Format::Float2, oidn::Format::Float3, oidn::Format::Float4,
|
||||
oidn::Format::Half, oidn::Format::Half2, oidn::Format::Half3, oidn::Format::Half4};
|
||||
|
||||
|
||||
auto it = std::find(formats.begin(), formats.end(), format);
|
||||
if (it == formats.end()) {
|
||||
throw std::invalid_argument("unsupported format");
|
||||
}
|
||||
|
||||
size_t nchannels = std::distance(formats.begin(), it) + 1;
|
||||
OIIO::TypeDesc type = OIIO::TypeDesc::FLOAT;
|
||||
|
||||
if (nchannels > 4){
|
||||
nchannels = nchannels - 4;
|
||||
type = OIIO::TypeDesc::HALF;
|
||||
}
|
||||
|
||||
OIIO::ImageSpec spec(width, height, nchannels, type);
|
||||
out->open(filename, spec);
|
||||
|
||||
void* mapped = nullptr;
|
||||
auto stagingResource = stagingBuffer.get();
|
||||
stagingResource->Map(0, nullptr, &mapped);
|
||||
out->write_image(type, mapped);
|
||||
D3D12_RANGE readingRange = {0, buffer.get_size()};
|
||||
stagingResource->Unmap(0, &readingRange);
|
||||
out->close();
|
||||
}
|
||||
|
||||
Buffer& get_buffer() {
|
||||
return buffer;
|
||||
}
|
||||
uint32_t get_width() {
|
||||
return width;
|
||||
}
|
||||
uint32_t get_height() {
|
||||
return height;
|
||||
}
|
||||
oidn::Format get_format() {
|
||||
return format;
|
||||
}
|
||||
|
||||
private:
|
||||
Buffer buffer;
|
||||
uint32_t width;
|
||||
uint32_t height;
|
||||
oidn::Format format;
|
||||
};
|
||||
|
||||
|
||||
|
||||
class InteropTestDX {
|
||||
public:
|
||||
InteropTestDX() {
|
||||
#if defined(_DEBUG)
|
||||
{
|
||||
if (SUCCEEDED(D3D12GetDebugInterface(IID_PPV_ARGS(&debugController)))) {
|
||||
debugController->EnableDebugLayer();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// Create DXGI factory
|
||||
if (FAILED(CreateDXGIFactory1(IID_PPV_ARGS(&factory)))) {
|
||||
throw std::runtime_error("Failed to create DXGI Factory.");
|
||||
}
|
||||
|
||||
// Create D3D12 device
|
||||
if (FAILED(D3D12CreateDevice(
|
||||
nullptr, // default adapter
|
||||
D3D_FEATURE_LEVEL_11_0,
|
||||
IID_PPV_ARGS(&device)
|
||||
))) {
|
||||
throw std::runtime_error("Failed to create D3D12 Device.");
|
||||
}
|
||||
|
||||
// Create command queue
|
||||
D3D12_COMMAND_QUEUE_DESC queueDesc = {};
|
||||
queueDesc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT;
|
||||
queueDesc.Flags = D3D12_COMMAND_QUEUE_FLAG_NONE;
|
||||
if (FAILED(device->CreateCommandQueue(&queueDesc, IID_PPV_ARGS(&commandQueue)))) {
|
||||
throw std::runtime_error("Failed to create command queue.");
|
||||
}
|
||||
}
|
||||
|
||||
~InteropTestDX() = default;
|
||||
|
||||
InteropTestDX(const InteropTestDX&) = delete;
|
||||
InteropTestDX& operator=(const InteropTestDX&) = delete;
|
||||
InteropTestDX(InteropTestDX&&) = default;
|
||||
InteropTestDX& operator=(InteropTestDX&&) = default;
|
||||
|
||||
|
||||
|
||||
void setup_oidn_device() {
|
||||
// Get the LUID of the adapter
|
||||
LUID luid = device->GetAdapterLuid();
|
||||
|
||||
// Initialize the denoiser device
|
||||
oidn_device = oidn::newDevice(oidn::LUID{luid.LowPart, luid.HighPart});
|
||||
if (oidn_device.getError() != oidn::Error::None)
|
||||
throw std::runtime_error("Failed to create OIDN device.");
|
||||
oidn_device.commit();
|
||||
if (oidn_device.getError() != oidn::Error::None)
|
||||
throw std::runtime_error("Failed to commit OIDN device.");
|
||||
|
||||
// Find a compatible external memory handle type
|
||||
const auto oidn_external_mem_types = oidn_device.get<oidn::ExternalMemoryTypeFlags>("externalMemoryTypes");
|
||||
if (!(oidn_external_mem_types & oidn::ExternalMemoryTypeFlag::OpaqueWin32))
|
||||
throw std::runtime_error("failed to find compatible external memory type");
|
||||
}
|
||||
|
||||
ImageBuffer create_buffer(uint32_t width, uint32_t height, oidn::Format format) {
|
||||
return ImageBuffer(device, width, height, format);
|
||||
}
|
||||
|
||||
ImageBuffer load_exr(std::string& path) {
|
||||
return ImageBuffer::load_exr(path, device, commandQueue);
|
||||
}
|
||||
|
||||
oidn::BufferRef create_oidn_buffer(ImageBuffer& imageBuffer) {
|
||||
// Create an OIDN buffer from the D3D12 resource
|
||||
HANDLE sharedHandle = nullptr;
|
||||
device->CreateSharedHandle(imageBuffer.get_buffer().get().Get(), nullptr, GENERIC_ALL, nullptr, &sharedHandle);
|
||||
return oidn_device.newBuffer(oidn::ExternalMemoryTypeFlag::OpaqueWin32, &sharedHandle, nullptr, imageBuffer.get_buffer().get_size());
|
||||
}
|
||||
|
||||
void save_exr(ImageBuffer& buf, const std::string& path) {
|
||||
return buf.save_exr(path, device, commandQueue);
|
||||
}
|
||||
|
||||
public:
|
||||
ComPtr<ID3D12Debug> debugController;
|
||||
ComPtr<IDXGIFactory6> factory;
|
||||
ComPtr<ID3D12Device> device;
|
||||
ComPtr<ID3D12CommandQueue> commandQueue;
|
||||
oidn::DeviceRef oidn_device;
|
||||
};
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user