record frames / print camera WIP

This commit is contained in:
Matt Pharr 2022-04-07 17:16:54 -07:00
parent 9e0c78621c
commit d70dce2e1e
4 changed files with 110 additions and 27 deletions

View file

@ -63,12 +63,13 @@ class CUDAOutputBuffer {
void setDevice(int32_t device_idx) { m_device_idx = device_idx; }
void setStream(CUstream stream) { m_stream = stream; }
void resize(int32_t width, int32_t height);
// Allocate or update device pointer as necessary for CUDA access
PIXEL_FORMAT* map();
PIXEL_FORMAT *map();
void unmap();
void StartAsynchronousReadback();
const PIXEL_FORMAT *GetReadbackPixels();
int32_t width() const { return m_width; }
int32_t height() const { return m_height; }
@ -82,9 +83,13 @@ class CUDAOutputBuffer {
int32_t m_width = 0u;
int32_t m_height = 0u;
cudaGraphicsResource* m_cuda_gfx_resource = nullptr;
cudaGraphicsResource *m_cuda_gfx_resource = nullptr;
GLuint m_pbo = 0u;
PIXEL_FORMAT* m_device_pixels = nullptr;
PIXEL_FORMAT *m_device_pixels = nullptr;
PIXEL_FORMAT *m_host_pixels = nullptr;
bool readbackActive = false;
cudaEvent_t readbackFinishedEvent;
CUstream m_stream = 0u;
int32_t m_device_idx = 0;
@ -102,26 +107,6 @@ CUDAOutputBuffer<PIXEL_FORMAT>::CUDAOutputBuffer(int32_t width, int32_t height)
if (!is_display_device)
LOG_FATAL("GL interop is only available on display device.");
resize(width, height);
}
template <typename PIXEL_FORMAT>
CUDAOutputBuffer<PIXEL_FORMAT>::~CUDAOutputBuffer() {
makeCurrent();
if (m_pbo != 0u) {
GL_CHECK(glBindBuffer(GL_ARRAY_BUFFER, 0));
GL_CHECK(glDeleteBuffers(1, &m_pbo));
}
}
template <typename PIXEL_FORMAT>
void CUDAOutputBuffer<PIXEL_FORMAT>::resize(int32_t width, int32_t height) {
CHECK(width > 0 && height > 0);
if (m_width == width && m_height == height)
return;
m_width = width;
m_height = height;
@ -136,6 +121,19 @@ void CUDAOutputBuffer<PIXEL_FORMAT>::resize(int32_t width, int32_t height) {
CUDA_CHECK(cudaGraphicsGLRegisterBuffer(&m_cuda_gfx_resource, m_pbo,
cudaGraphicsMapFlagsWriteDiscard));
CUDA_CHECK(cudaEventCreate(&readbackFinishedEvent));
CUDA_CHECK(cudaMallocHost(&m_host_pixels, m_width * m_height * sizeof(PIXEL_FORMAT)));
}
template <typename PIXEL_FORMAT>
CUDAOutputBuffer<PIXEL_FORMAT>::~CUDAOutputBuffer() {
makeCurrent();
if (m_pbo != 0u) {
GL_CHECK(glBindBuffer(GL_ARRAY_BUFFER, 0));
GL_CHECK(glDeleteBuffers(1, &m_pbo));
}
}
template <typename PIXEL_FORMAT>
@ -171,6 +169,31 @@ void CUDAOutputBuffer<PIXEL_FORMAT>::deletePBO() {
m_pbo = 0;
}
template <typename PIXEL_FORMAT>
void CUDAOutputBuffer<PIXEL_FORMAT>::StartAsynchronousReadback() {
CHECK(!readbackActive);
makeCurrent();
CUDA_CHECK(cudaMemcpyAsync(m_host_pixels, m_device_pixels,
m_width * m_height * sizeof(PIXEL_FORMAT),
cudaMemcpyDeviceToHost));
CUDA_CHECK(cudaEventRecord(readbackFinishedEvent));
readbackActive = true;
}
template <typename PIXEL_FORMAT>
const PIXEL_FORMAT *CUDAOutputBuffer<PIXEL_FORMAT>::GetReadbackPixels() {
if (!readbackActive)
return nullptr;
makeCurrent();
CUDA_CHECK(cudaEventSynchronize(readbackFinishedEvent));
readbackActive = false;
return m_host_pixels;
}
} // end namespace pbrt
#endif // PBRT_GPU_CUDAGL_H

View file

@ -9,6 +9,8 @@
#include <pbrt/gpu/util.h>
#endif PBRT_BUILD_GPU_RENDERER
#include <pbrt/util/error.h>
#include <pbrt/util/image.h>
#include <pbrt/util/parallel.h>
#define GL_CHECK(call) \
do { \
@ -297,7 +299,7 @@ static void glfwErrorCallback(int error, const char* desc) {
LOG_ERROR("GLFW [%d]: %s", error, desc);
}
void GUI::keyboardCallback(GLFWwindow* window, int key, int scan, int action, int mods) {
void GUI::keyboardCallback(GLFWwindow *window, int key, int scan, int action, int mods) {
if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS)
glfwSetWindowShouldClose(window, GLFW_TRUE);
@ -318,14 +320,22 @@ void GUI::keyboardCallback(GLFWwindow* window, int key, int scan, int action, in
doKey(GLFW_KEY_W, 'w');
doKey(GLFW_KEY_Q, 'q');
doKey(GLFW_KEY_E, 'e');
doKey(GLFW_KEY_B, (mods & GLFW_MOD_SHIFT) ? 'B' : 'b');
doKey(GLFW_KEY_R, 'r');
doKey(GLFW_KEY_C, 'c');
doKey(GLFW_KEY_EQUAL, '=');
doKey(GLFW_KEY_MINUS, '-');
doKey(GLFW_KEY_LEFT, 'L');
doKey(GLFW_KEY_RIGHT, 'R');
doKey(GLFW_KEY_UP, 'U');
doKey(GLFW_KEY_DOWN, 'D');
if (key == GLFW_KEY_R && action == GLFW_PRESS &&
glfwGetKey(window, GLFW_KEY_LEFT_CONTROL) == GLFW_PRESS)
recordFrames = !recordFrames;
else
doKey(GLFW_KEY_R, 'r');
}
bool GUI::processKeys() {
@ -361,6 +371,10 @@ bool GUI::processKeys() {
handleNeedsReset('r', [&](Transform t) { return Transform(); });
// No reset needed for these.
if (keysDown.find('c') != keysDown.end()) {
keysDown.erase(keysDown.find('c'));
printCameraTransform = true;
}
if (keysDown.find('b') != keysDown.end()) {
keysDown.erase(keysDown.find('b'));
exposure *= 1.125f;
@ -452,6 +466,34 @@ DisplayState GUI::RefreshDisplay() {
glfwSwapBuffers(window);
glfwPollEvents();
if (recordFrames) {
const RGB *fb = nullptr;
#ifdef PBRT_BUILD_GPU_RENDERER
if (cudaFramebuffer)
fb = cudaFramebuffer->GetReadbackPixels();
else
#endif
fb = cpuFramebuffer;
if (fb) {
Image image(PixelFormat::Float, {width, height}, {"R", "G", "B"});
std::memcpy(image.RawPointer({0, 0}), fb, width * height * sizeof(RGB));
//CO RunAsync([](Image image, int frameNumber) {
// TODO: set metadata for e.g. current camera position...
ImageMetadata metadata;
image.Write(StringPrintf("pbrt-frame%05d.exr", frameNumber), metadata);
//CO return 0; // FIXME: RunAsync() doesn't like lambdas that return void..
//CO }, std::move(image), frameNumber);
++frameNumber;
}
#ifdef PBRT_BUILD_GPU_RENDERER
if (cudaFramebuffer)
cudaFramebuffer->StartAsynchronousReadback();
#endif
}
if (glfwWindowShouldClose(window))
return DisplayState::EXIT;
else if (processKeys())

View file

@ -48,8 +48,12 @@ class GUI {
DisplayState RefreshDisplay();
// It's a little messy that the state of values controlled via the UI
// are just public variables here but it's probably not worth putting
// an abstraction layer on top of all this at this point.
Transform GetCameraTransform() const { return movingFromCamera; }
Float exposure = 1.f;
bool printCameraTransform = false;
void keyboardCallback(GLFWwindow *window, int key, int scan, int action, int mods);
@ -60,6 +64,8 @@ class GUI {
Float moveScale = 1.f;
Transform movingFromCamera;
Vector2i resolution;
bool recordFrames = false;
int frameNumber = 0;
#ifdef PBRT_BUILD_GPU_RENDERER
CUDAOutputBuffer<RGB> *cudaFramebuffer = nullptr;

View file

@ -31,6 +31,7 @@
#include <pbrt/wavefront/aggregate.h>
#include <atomic>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <map>
@ -293,6 +294,7 @@ Float WavefrontPathIntegrator::Render() {
// FIXME: camera animation; whatever...
Transform renderFromCamera = camera.GetCameraTransform().RenderFromCamera().startTransform;
Transform cameraFromRender = Inverse(renderFromCamera);
Transform cameraFromWorld = camera.GetCameraTransform().CameraFromWorld(camera.SampleTime(0.f));
if (Options->interactive) {
if (!Options->displayServer.empty())
ErrorExit("--interactive and --display-server cannot be used at the same time.");
@ -432,6 +434,16 @@ Float WavefrontPathIntegrator::Render() {
UpdateFramebufferFromFilm(pixelBounds, gui->exposure, rgb);
gui->UnmapFramebuffer();
if (gui->printCameraTransform) {
SquareMatrix<4> cfw = (Inverse(gui->GetCameraTransform()) * cameraFromWorld).GetMatrix();
Printf("Current camera transform:\nTransform [ ");
for (int i = 0; i < 16; ++i)
Printf("%f ", cfw[i % 4][i / 4]);
Printf("]\n");
std::fflush(stdout);
gui->printCameraTransform = false;
}
DisplayState state = gui->RefreshDisplay();
if (state == DisplayState::EXIT)
break;