Skip to content

Commit

Permalink
Copy bucket data if both components and the input format matches.
Browse files Browse the repository at this point in the history
  • Loading branch information
sirpalee committed Mar 23, 2020
1 parent cd4f1fb commit d975ebf
Show file tree
Hide file tree
Showing 3 changed files with 86 additions and 9 deletions.
81 changes: 76 additions & 5 deletions render_delegate/render_buffer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,22 @@

#include <ai.h>

// memcpy
#include <cstring>

// TOOD(pal): use a more efficient locking mechanism than the std::mutex.
PXR_NAMESPACE_OPEN_SCOPE

HdArnoldRenderBuffer::HdArnoldRenderBuffer(const SdfPath& id) : HdRenderBuffer(id) {}

bool HdArnoldRenderBuffer::Allocate(const GfVec3i& dimensions, HdFormat format, bool multiSampled)
{
_Deallocate();
std::lock_guard<std::mutex> _guard(_mutex);
// So deallocate won't lock.
decltype(_buffer) tmp{};
_buffer.swap(tmp);
TF_UNUSED(multiSampled);
_format = format;
_width = dimensions[0];
_height = dimensions[1];
const auto byteCount = _width * _height * HdDataSizeOfFormat(format);
Expand All @@ -34,22 +42,85 @@ bool HdArnoldRenderBuffer::Allocate(const GfVec3i& dimensions, HdFormat format,
return true;
}

void* HdArnoldRenderBuffer::Map() { return _buffer.data(); }
void* HdArnoldRenderBuffer::Map() {
_mutex.lock();
if (_buffer.empty()) {
_mutex.unlock();
return nullptr;
}
return _buffer.data();
}

void HdArnoldRenderBuffer::Unmap() {}
void HdArnoldRenderBuffer::Unmap() {
_mutex.unlock();
}

bool HdArnoldRenderBuffer::IsMapped() const { return false; }

void HdArnoldRenderBuffer::_Deallocate()
{
std::lock_guard<std::mutex> _guard(_mutex);
decltype(_buffer) tmp{};
_buffer.swap(tmp);
}

void HdArnoldRenderBuffer::WriteBucket(
unsigned int x, unsigned int y, unsigned int width, unsigned int height, HdFormat format, const void* data)
unsigned int bucketXO, unsigned int bucketYO, unsigned int bucketWidth, unsigned int bucketHeight, HdFormat format, const void* bucketData)
{
// TODO(pal): Implement
std::lock_guard<std::mutex> _guard(_mutex);
const auto xo = AiClamp(bucketXO, 0u, _width);
const auto xe = AiClamp(bucketXO + bucketWidth, 0u, _width);
// Empty bucket.
if (xe == xo) {
return;
}
const auto yo = AiClamp(bucketYO, 0u, _height);
const auto ye = AiClamp(bucketYO + bucketHeight, 0u, _height);
// Empty bucket.
if (ye == yo) {
return;
}
const auto dataWidth = (xe - xo);
// Single component formats can be:
// - HdFormatUNorm8
// - HdFormatSNorm8
// - HdFormatFloat16
// - HdFormatFloat32
// - HdformatInt32
// We need to check if the components formats and counts match.
// The simplest case is when the component format and the count matches, we can copy per line in this case.
// If the the component format matches, but the count is different, we are copying as much data as we can
// and zeroing out the rest.
// If the component count matches, but the format is different, we are converting each element.
// If none of the matches, we are converting as much as we can, and zeroing out the rest.
const auto componentCount = HdGetComponentCount(_format);
const auto componentFormat = HdGetComponentFormat(_format);
// TODO(pal): Implement the cases when formats don't match.
// For now we are only implementing cases where the format does matches.
const auto inComponentCount = HdGetComponentCount(format);
const auto inComponentFormat = HdGetComponentFormat(format);
if (componentFormat == inComponentFormat) {
const auto pixelSize = HdDataSizeOfFormat(_format);
// Copy per line
if (inComponentCount == componentCount) {
// The size of the line we are copying.
const auto lineDataSize = dataWidth * pixelSize;
// The full size of a line.
const auto fullLineDataSize = _width * pixelSize;
// The size of the line for the bucket, this could be more than the data copied.
const auto inLineDataSize = bucketWidth * pixelSize;
// This is the first pixel we are copying into.
auto* data = _buffer.data() + (xo + (_height - yo - 1) * _width) * pixelSize;
const auto* inData = static_cast<const uint8_t*>(bucketData);
for (auto y = yo; y < ye; y += 1) {
memcpy(data, inData, lineDataSize);
data -= fullLineDataSize;
inData += inLineDataSize;
}
}
} else { // Need to do conversion.
return;
}
}

PXR_NAMESPACE_CLOSE_SCOPE
4 changes: 3 additions & 1 deletion render_delegate/render_buffer.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
#include <pxr/imaging/hd/renderBuffer.h>

#include <unordered_map>
#include <mutex>

PXR_NAMESPACE_OPEN_SCOPE

Expand Down Expand Up @@ -88,14 +89,15 @@ class HdArnoldRenderBuffer : public HdRenderBuffer {

HDARNOLD_API
void WriteBucket(
unsigned int x, unsigned int y, unsigned int width, unsigned int height, HdFormat format, const void* data);
unsigned int bucketXO, unsigned int bucketYo, unsigned int bucketWidth, unsigned int bucketHeight, HdFormat format, const void* bucketData);

private:
/// Deallocates the data stored in the buffer.
HDARNOLD_API
void _Deallocate() override;

std::vector<uint8_t> _buffer; ///< Storing render data.
std::mutex _mutex; ///< Mutex for the parallel writes.
unsigned int _width = 0; ///< Buffer width.
unsigned int _height = 0; ///< Buffer height.
HdFormat _format = HdFormat::HdFormatUNorm8Vec4; ///< Internal format of the buffer.
Expand Down
10 changes: 7 additions & 3 deletions render_delegate/render_pass.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@
#include <pxr/imaging/hd/renderPassState.h>

#include <algorithm>
#include <cstring> // memset
#include <iostream>

#include "config.h"
#include "constant_strings.h"
Expand Down Expand Up @@ -114,13 +114,17 @@ void HdArnoldRenderPass::_Execute(const HdRenderPassStateSharedPtr& renderPassSt
renderParam->Interrupt();
_width = width;
_height = height;
auto* options = _delegate->GetOptions();
AiNodeSetInt(options, str::xres, _width);
AiNodeSetInt(options, str::yres, _height);
}

// We are checking if the current aov bindings match the ones we already created, if not,
// then rebuild the driver setup.
// If AOV bindings are empty, we are only setting up color and depth for basic opengl composition. This should
// not happen often.
// TODO(pal): Remove bindings to P and RGBA. Those are used for other buffers.
// TODO(pal): Remove bindings to P and RGBA. Those are used for other buffers. Or add support for writing to
// these in the driver.
HdRenderPassAovBindingVector aovBindings = renderPassState->GetAovBindings();

if (aovBindings.empty()) {
Expand Down Expand Up @@ -182,7 +186,7 @@ void HdArnoldRenderPass::_Execute(const HdRenderPassStateSharedPtr& renderPassSt
buffer.second->SetConverged(_isConverged);
}
}
// If the buffers are empty, we have to blit the data from the fallback buffers to OpenGL.
// If the buffers are empty, we have to blit the data from the fallback buffers to OpenGL.
} else {
// No AOV bindings means blit current framebuffer contents.
/*#ifdef USD_HAS_FULLSCREEN_SHADER
Expand Down

0 comments on commit d975ebf

Please sign in to comment.