1 
2 //
3 // This source file is part of appleseed.
4 // Visit https://appleseedhq.net/ for additional information and resources.
5 //
6 // This software is released under the MIT license.
7 //
8 // Copyright (c) 2017-2018 Esteban Tovagliari, The appleseedhq Organization
9 //
10 // Permission is hereby granted, free of charge, to any person obtaining a copy
11 // of this software and associated documentation files (the "Software"), to deal
12 // in the Software without restriction, including without limitation the rights
13 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14 // copies of the Software, and to permit persons to whom the Software is
15 // furnished to do so, subject to the following conditions:
16 //
17 // The above copyright notice and this permission notice shall be included in
18 // all copies or substantial portions of the Software.
19 //
20 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
26 // THE SOFTWARE.
27 //
28 
29 // Interface header.
30 #include "aovaccumulator.h"
31 
32 // appleseed.renderer headers.
33 #include "renderer/global/globaltypes.h"
34 #include "renderer/modeling/aov/aov.h"
35 #include "renderer/modeling/frame/frame.h"
36 
37 // appleseed.foundation headers.
38 #include "foundation/image/canvasproperties.h"
39 #include "foundation/image/image.h"
40 #include "foundation/image/tile.h"
41 
42 // Standard headers.
43 #include <cassert>
44 #include <cstring>
45 
46 using namespace foundation;
47 using namespace std;
48 
49 namespace renderer
50 {
51 
52 //
53 // AOVAccumulator class implementation.
54 //
55 
~AOVAccumulator()56 AOVAccumulator::~AOVAccumulator()
57 {
58 }
59 
release()60 void AOVAccumulator::release()
61 {
62     delete this;
63 }
64 
on_tile_begin(const Frame & frame,const size_t tile_x,const size_t tile_y,const size_t max_spp)65 void AOVAccumulator::on_tile_begin(
66     const Frame&                frame,
67     const size_t                tile_x,
68     const size_t                tile_y,
69     const size_t                max_spp)
70 {
71 }
72 
on_tile_end(const Frame & frame,const size_t tile_x,const size_t tile_y)73 void AOVAccumulator::on_tile_end(
74     const Frame&                frame,
75     const size_t                tile_x,
76     const size_t                tile_y)
77 {
78 }
79 
on_pixel_begin(const Vector2i & pi)80 void AOVAccumulator::on_pixel_begin(
81     const Vector2i&             pi)
82 {
83 }
84 
on_pixel_end(const Vector2i & pi)85 void AOVAccumulator::on_pixel_end(
86     const Vector2i&             pi)
87 {
88 }
89 
on_sample_begin(const PixelContext & pixel_context)90 void AOVAccumulator::on_sample_begin(
91     const PixelContext&         pixel_context)
92 {
93 }
94 
on_sample_end(const PixelContext & pixel_context)95 void AOVAccumulator::on_sample_end(
96     const PixelContext&         pixel_context)
97 {
98 }
99 
write(const PixelContext & pixel_context,const ShadingPoint & shading_point,const ShadingComponents & shading_components,const AOVComponents & aov_components,ShadingResult & shading_result)100 void AOVAccumulator::write(
101     const PixelContext&         pixel_context,
102     const ShadingPoint&         shading_point,
103     const ShadingComponents&    shading_components,
104     const AOVComponents&        aov_components,
105     ShadingResult&              shading_result)
106 {
107 }
108 
109 
110 //
111 // UnfilteredAOVAccumulator class implementation.
112 //
113 
UnfilteredAOVAccumulator(Image & image)114 UnfilteredAOVAccumulator::UnfilteredAOVAccumulator(Image& image)
115   : m_image(image)
116   , m_tile(nullptr)
117 {
118 }
119 
on_tile_begin(const Frame & frame,const size_t tile_x,const size_t tile_y,const size_t max_spp)120 void UnfilteredAOVAccumulator::on_tile_begin(
121     const Frame&                frame,
122     const size_t                tile_x,
123     const size_t                tile_y,
124     const size_t                max_spp)
125 {
126     // Fetch the destination tile.
127     m_tile = &m_image.tile(tile_x, tile_y);
128 
129     // Compute the tile's origin and cropped bounding box (inclusive on all sides).
130     const CanvasProperties& props = frame.image().properties();
131     m_tile_origin_x = tile_x * props.m_tile_width;
132     m_tile_origin_y = tile_y * props.m_tile_height;
133     m_cropped_tile_bbox.min.x = static_cast<int>(m_tile_origin_x);
134     m_cropped_tile_bbox.min.y = static_cast<int>(m_tile_origin_y);
135     m_cropped_tile_bbox.max.x = static_cast<int>(m_tile_origin_x + m_tile->get_width() - 1);
136     m_cropped_tile_bbox.max.y = static_cast<int>(m_tile_origin_y + m_tile->get_height() - 1);
137     assert(m_cropped_tile_bbox.is_valid());
138 
139     // Clip the tile's bounding box against the crop window.
140     m_cropped_tile_bbox = AABB2i::intersect(m_cropped_tile_bbox, frame.get_crop_window());
141     assert(m_cropped_tile_bbox.is_valid());
142 }
143 
on_tile_end(const Frame & frame,const size_t tile_x,const size_t tile_y)144 void UnfilteredAOVAccumulator::on_tile_end(
145     const Frame&                frame,
146     const size_t                tile_x,
147     const size_t                tile_y)
148 {
149     m_tile = nullptr;
150 }
151 
152 
153 //
154 // AOVAccumulatorContainer class implementation.
155 //
156 
AOVAccumulatorContainer()157 AOVAccumulatorContainer::AOVAccumulatorContainer()
158 {
159     init();
160 }
161 
AOVAccumulatorContainer(const Frame & frame)162 AOVAccumulatorContainer::AOVAccumulatorContainer(const Frame& frame)
163 {
164     init();
165 
166     // Create accumulators for AOVs.
167     for (size_t i = 0, e = frame.aovs().size(); i < e; ++i)
168     {
169         const AOV* aov = frame.aovs().get_by_index(i);
170         insert(aov->create_accumulator());
171     }
172 
173     // Create accumulators for internal AOVs.
174     for (size_t i = 0, e = frame.internal_aovs().size(); i < e; ++i)
175     {
176         const AOV* aov = frame.internal_aovs().get_by_index(i);
177         insert(aov->create_accumulator());
178     }
179 }
180 
init()181 void AOVAccumulatorContainer::init()
182 {
183     m_size = 0;
184     memset(m_accumulators, 0, MaxAOVAccumulatorCount * sizeof(AOVAccumulator*));
185 }
186 
~AOVAccumulatorContainer()187 AOVAccumulatorContainer::~AOVAccumulatorContainer()
188 {
189     for (size_t i = 0, e = m_size; i < e; ++i)
190         delete m_accumulators[i];
191 }
192 
on_tile_begin(const Frame & frame,const size_t tile_x,const size_t tile_y,const size_t max_spp)193 void AOVAccumulatorContainer::on_tile_begin(
194     const Frame&                frame,
195     const size_t                tile_x,
196     const size_t                tile_y,
197     const size_t                max_spp)
198 {
199     for (size_t i = 0, e = m_size; i < e; ++i)
200         m_accumulators[i]->on_tile_begin(frame, tile_x, tile_y, max_spp);
201 }
202 
on_tile_end(const Frame & frame,const size_t tile_x,const size_t tile_y)203 void AOVAccumulatorContainer::on_tile_end(
204     const Frame&                frame,
205     const size_t                tile_x,
206     const size_t                tile_y)
207 {
208     for (size_t i = 0, e = m_size; i < e; ++i)
209         m_accumulators[i]->on_tile_end(frame, tile_x, tile_y);
210 }
211 
on_pixel_begin(const Vector2i & pi)212 void AOVAccumulatorContainer::on_pixel_begin(
213     const Vector2i&             pi)
214 {
215     for (size_t i = 0, e = m_size; i < e; ++i)
216         m_accumulators[i]->on_pixel_begin(pi);
217 }
218 
on_pixel_end(const Vector2i & pi)219 void AOVAccumulatorContainer::on_pixel_end(
220     const Vector2i&             pi)
221 {
222     for (size_t i = 0, e = m_size; i < e; ++i)
223         m_accumulators[i]->on_pixel_end(pi);
224 }
225 
on_sample_begin(const PixelContext & pixel_context)226 void AOVAccumulatorContainer::on_sample_begin(
227     const PixelContext&         pixel_context)
228 {
229     for (size_t i = 0, e = m_size; i < e; ++i)
230         m_accumulators[i]->on_sample_begin(pixel_context);
231 }
232 
on_sample_end(const PixelContext & pixel_context)233 void AOVAccumulatorContainer::on_sample_end(
234     const PixelContext&         pixel_context)
235 {
236     for (size_t i = 0, e = m_size; i < e; ++i)
237         m_accumulators[i]->on_sample_end(pixel_context);
238 }
239 
write(const PixelContext & pixel_context,const ShadingPoint & shading_point,const ShadingComponents & shading_components,const AOVComponents & aov_components,ShadingResult & shading_result)240 void AOVAccumulatorContainer::write(
241     const PixelContext&         pixel_context,
242     const ShadingPoint&         shading_point,
243     const ShadingComponents&    shading_components,
244     const AOVComponents&        aov_components,
245     ShadingResult&              shading_result)
246 {
247     for (size_t i = 0, e = m_size; i < e; ++i)
248     {
249         m_accumulators[i]->write(
250             pixel_context,
251             shading_point,
252             shading_components,
253             aov_components,
254             shading_result);
255     }
256 }
257 
insert(auto_release_ptr<AOVAccumulator> aov_accum)258 bool AOVAccumulatorContainer::insert(auto_release_ptr<AOVAccumulator> aov_accum)
259 {
260     assert(aov_accum.get());
261 
262     if (m_size + 1 == MaxAOVAccumulatorCount)
263         return false;
264 
265     m_accumulators[m_size++] = aov_accum.release();
266     return true;
267 }
268 
269 }   // namespace renderer
270