File: FrameBuffer.cpp

package info (click to toggle)
ospray 3.2.0-1
  • links: PTS, VCS
  • area: main
  • in suites: trixie
  • size: 10,040 kB
  • sloc: cpp: 80,569; ansic: 951; sh: 805; makefile: 171; python: 69
file content (198 lines) | stat: -rw-r--r-- 5,251 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
// Copyright 2009 Intel Corporation
// SPDX-License-Identifier: Apache-2.0

#include "FrameBuffer.h"
#include "FrameOp.h"
#include "OSPConfig.h"
#include "fb/FrameBufferView.h"
#ifndef OSPRAY_TARGET_SYCL
#include "ISPCDevice_ispc.h"
#endif

namespace {
// Internal utilities for thread local progress tracking
thread_local int threadLastFrameID = -1;
thread_local uint32_t threadNumPixelsRendered = 0;

extern "C" uint32_t *getThreadNumPixelsRendered()
{
  return &threadNumPixelsRendered;
}

extern "C" int *getThreadLastFrameID()
{
  return &threadLastFrameID;
}

}; // namespace

namespace ospray {

FrameBuffer::FrameBuffer(api::ISPCDevice &device,
    const vec2i &_size,
    ColorBufferFormat _colorBufferFormat,
    const uint32 channels,
    const FeatureFlagsOther ffo)
    : AddStructShared(device.getDRTDevice(), device),
      size(_size),
      colorBufferFormat(_colorBufferFormat),
      hasColorBuffer(channels & OSP_FB_COLOR),
      hasDepthBuffer(channels & OSP_FB_DEPTH),
      hasVarianceBuffer((channels & OSP_FB_COLOR)
          && (channels & OSP_FB_VARIANCE) && (channels & OSP_FB_ACCUM)),
      hasNormalBuffer(channels & OSP_FB_NORMAL),
      hasAlbedoBuffer(channels & OSP_FB_ALBEDO),
      hasPrimitiveIDBuffer(channels & OSP_FB_ID_PRIMITIVE),
      hasObjectIDBuffer(channels & OSP_FB_ID_OBJECT),
      hasInstanceIDBuffer(channels & OSP_FB_ID_INSTANCE),
      doAccum(channels & OSP_FB_ACCUM),
      featureFlags(ffo)
{
  managedObjectType = OSP_FRAMEBUFFER;
  if (_size.x <= 0 || _size.y <= 0) {
    throw std::runtime_error(
        "framebuffer has invalid size. Dimensions must be greater than 0");
  }
  getSh()->size = _size;
  getSh()->rcpSize = vec2f(1.f) / vec2f(_size);
  getSh()->channels = channels;
  getSh()->accumulateVariance = false;
  getSh()->targetFrames = !doAccum;

#if OSPRAY_RENDER_TASK_SIZE == -1
#ifdef OSPRAY_TARGET_SYCL
  vec2i renderTaskSize(8);
#else
  // Compute render task size based on the simd width to get as "square" as
  // possible a task size that has simdWidth pixels
  const int simdWidth = ispc::ISPCDevice_programCount();
  vec2i renderTaskSize(simdWidth, 1);
  while (renderTaskSize.x / 2 > renderTaskSize.y) {
    renderTaskSize.y *= 2;
    renderTaskSize.x /= 2;
  }
#endif
#else
  // Note: we could also allow changing this at runtime if we want to add this
  // to the API
  vec2i renderTaskSize(OSPRAY_RENDER_TASK_SIZE);
#endif
  getSh()->renderTaskSize = renderTaskSize;
}

void FrameBuffer::commit()
{
  imageOpData = getParamDataT<ImageOp *>("imageOperation");
  // always query `targetFrames` to clear query status
  getSh()->targetFrames = max(0, getParam<int>("targetFrames", 0));
  if (!doAccum)
    getSh()->targetFrames = 1;
}

void FrameBuffer::clear()
{
  getSh()->frameID = -1; // we increment at the start of the frame

  if (hasVarianceBuffer) {
    mtGen.seed(mtSeed); // reset the RNG with same seed
    frameVariance = inf;
  }
}

vec2i FrameBuffer::getRenderTaskSize() const
{
  return getSh()->renderTaskSize;
}

float FrameBuffer::getVariance() const
{
  return frameVariance;
}

void FrameBuffer::beginFrame()
{
  cancelRender = false;
  getSh()->frameID = doAccum ? getSh()->frameID + 1 : 0;
#ifndef OSPRAY_TARGET_SYCL
  // TODO: Cancellation isn't supported on the GPU
  getSh()->cancelRender = 0;
  // TODO: Maybe better as a kernel to avoid USM thrash to host
  getSh()->numPixelsRendered = 0;
#endif

  if (hasVarianceBuffer) {
    // collect half of the samples
    // To not run into correlation issues with low discrepancy sequences used
    // in renders, we randomly pick whether the even or the odd frame is
    // accumulated into the variance buffer.
    const bool evenFrame = (getSh()->frameID & 1) == 0;
    if (evenFrame)
      pickOdd = mtGen() & 1; // coin flip every other frame

    getSh()->accumulateVariance = evenFrame != pickOdd;
  }
}

std::string FrameBuffer::toString() const
{
  return "ospray::FrameBuffer";
}

void FrameBuffer::setCompletedEvent(OSPSyncEvent event)
{
#ifndef OSPRAY_TARGET_SYCL
  // We won't be running ISPC-side rendering tasks when updating the
  // progress values here in C++
  if (event == OSP_NONE_FINISHED)
    getSh()->numPixelsRendered = 0;
  if (event == OSP_FRAME_FINISHED)
    getSh()->numPixelsRendered = getNumPixels().long_product();
#endif
  stagesCompleted = event;
}

OSPSyncEvent FrameBuffer::getLatestCompleteEvent() const
{
  return stagesCompleted;
}

void FrameBuffer::waitForEvent(OSPSyncEvent event) const
{
  // TODO: condition variable to sleep calling thread instead of spinning?
  while (stagesCompleted < event)
    ;
}

float FrameBuffer::getCurrentProgress() const
{
#ifdef OSPRAY_TARGET_SYCL
  // TODO: Continually polling this will cause a lot of USM thrashing
  return 0.f;
#else
  return static_cast<float>(getSh()->numPixelsRendered)
      / getNumPixels().long_product();
#endif
}

void FrameBuffer::cancelFrame()
{
  cancelRender = true;
  // TODO: Cancellation isn't supported on the GPU
#ifndef OSPRAY_TARGET_SYCL
  getSh()->cancelRender = 1;
#endif
}

bool FrameBuffer::frameCancelled() const
{
  return cancelRender;
}

uint32 FrameBuffer::getChannelFlags() const
{
  return getSh()->channels;
}

OSPTYPEFOR_DEFINITION(FrameBuffer *);

} // namespace ospray