Line data Source code
1 :
2 : /* Copyright (c) 2007-2017, Stefan Eilemann <eile@equalizergraphics.com>
3 : * Cedric Stalder <cedric.stalder@gmail.com>
4 : *
5 : * This file is part of Collage <https://github.com/Eyescale/Collage>
6 : *
7 : * This library is free software; you can redistribute it and/or modify it under
8 : * the terms of the GNU Lesser General Public License version 2.1 as published
9 : * by the Free Software Foundation.
10 : *
11 : * This library is distributed in the hope that it will be useful, but WITHOUT
12 : * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
13 : * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
14 : * details.
15 : *
16 : * You should have received a copy of the GNU Lesser General Public License
17 : * along with this library; if not, write to the Free Software Foundation, Inc.,
18 : * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 : */
20 :
21 : #include "dataIStream.h"
22 :
23 : #include "global.h"
24 : #include "log.h"
25 : #include "node.h"
26 :
27 : #include <lunchbox/buffer.h>
28 : #include <lunchbox/debug.h>
29 : #include <pression/data/Compressor.h>
30 : #include <pression/data/CompressorInfo.h>
31 :
32 : #include <string.h>
33 :
34 : namespace co
35 : {
36 : namespace detail
37 : {
38 2814033 : class DataIStream
39 : {
40 : public:
41 2809437 : DataIStream()
42 2809437 : : input(0)
43 : , inputSize(0)
44 2809437 : , position(0)
45 : {
46 2802442 : }
47 :
48 8 : void initCompressor(const CompressorInfo& info)
49 : {
50 8 : if (info == compressorInfo)
51 0 : return;
52 8 : compressorInfo = info;
53 8 : compressor.reset(info.create());
54 8 : LBLOG(LOG_OBJECTS) << "Allocated " << compressorInfo.name << std::endl;
55 : }
56 :
57 : /** The current input buffer */
58 : const uint8_t* input;
59 :
60 : /** The size of the input buffer */
61 : uint64_t inputSize;
62 :
63 : /** The current read position in the buffer */
64 : uint64_t position;
65 :
66 : CompressorPtr compressor; //!< current decompressor
67 : CompressorInfo compressorInfo; //!< current decompressor data
68 : lunchbox::Bufferb data; //!< decompressed buffer
69 : };
70 : }
71 :
72 2807337 : DataIStream::DataIStream()
73 2807337 : : _impl(new detail::DataIStream())
74 : {
75 2802492 : }
76 :
77 5623955 : DataIStream::~DataIStream()
78 : {
79 2814214 : _reset();
80 2814078 : delete _impl;
81 2809741 : }
82 :
83 2814202 : void DataIStream::_reset()
84 : {
85 2814202 : _impl->input = 0;
86 2814202 : _impl->inputSize = 0;
87 2814202 : _impl->position = 0;
88 2814202 : }
89 :
90 3409582 : void DataIStream::_read(void* data, uint64_t size)
91 : {
92 3409582 : if (!_checkBuffer())
93 : {
94 0 : LBUNREACHABLE;
95 0 : LBERROR << "No more input data" << std::endl;
96 0 : return;
97 : }
98 :
99 3409617 : LBASSERT(_impl->input);
100 3409615 : if (size > _impl->inputSize - _impl->position)
101 : {
102 0 : LBERROR << "Not enough data in input buffer: need 0x" << std::hex
103 0 : << size << " bytes, 0x" << _impl->inputSize - _impl->position
104 0 : << " left " << std::dec << std::endl;
105 0 : LBUNREACHABLE;
106 : // TODO: Allow reads which are asymmetric to writes by reading from
107 : // multiple blocks here?
108 0 : return;
109 : }
110 :
111 3409615 : memcpy(data, _impl->input + _impl->position, size);
112 3409615 : _impl->position += size;
113 : }
114 :
115 2302004 : const void* DataIStream::getRemainingBuffer(const uint64_t size)
116 : {
117 2302004 : if (!_checkBuffer())
118 0 : return 0;
119 :
120 2311455 : LBASSERT(_impl->position + size <= _impl->inputSize);
121 2311705 : if (_impl->position + size > _impl->inputSize)
122 0 : return 0;
123 :
124 2311705 : _impl->position += size;
125 2311705 : return _impl->input + _impl->position - size;
126 : }
127 :
128 2691858 : uint64_t DataIStream::getRemainingBufferSize()
129 : {
130 2691858 : if (!_checkBuffer())
131 110 : return 0;
132 :
133 2673790 : return _impl->inputSize - _impl->position;
134 : }
135 :
136 0 : bool DataIStream::wasUsed() const
137 : {
138 0 : return _impl->input != 0;
139 : }
140 :
141 10801051 : bool DataIStream::_checkBuffer()
142 : {
143 13207640 : while (_impl->position >= _impl->inputSize)
144 : {
145 4831021 : CompressorInfo info;
146 2390673 : uint32_t nChunks = 0;
147 2390673 : const void* data = 0;
148 :
149 2390673 : _impl->position = 0;
150 2390673 : _impl->input = 0;
151 2390673 : _impl->inputSize = 0;
152 :
153 2390673 : if (!getNextBuffer(info, nChunks, data, _impl->inputSize))
154 155 : return false;
155 :
156 2392525 : _impl->input = _decompress(data, info, nChunks, _impl->inputSize);
157 : }
158 8376619 : return true;
159 : }
160 :
161 2395333 : const uint8_t* DataIStream::_decompress(const void* data,
162 : const CompressorInfo& info,
163 : const uint32_t nChunks,
164 : const uint64_t dataSize)
165 : {
166 2395333 : const uint8_t* src = reinterpret_cast<const uint8_t*>(data);
167 2395333 : if (info.name.empty())
168 2395900 : return src;
169 :
170 8 : LBASSERT(!info.name.empty());
171 : #ifndef CO_AGGRESSIVE_CACHING
172 8 : _impl->data.clear();
173 : #endif
174 8 : _impl->data.reset(dataSize);
175 8 : _impl->initCompressor(info);
176 :
177 16 : std::vector<std::pair<const uint8_t*, size_t>> inputs(nChunks);
178 16 : for (uint32_t i = 0; i < nChunks; ++i)
179 : {
180 8 : const uint64_t size = *reinterpret_cast<const uint64_t*>(src);
181 8 : src += sizeof(uint64_t);
182 :
183 8 : inputs[i] = {src, size};
184 8 : src += size;
185 : }
186 :
187 8 : _impl->compressor->decompress(inputs, _impl->data.getData(), dataSize);
188 8 : return _impl->data.getData();
189 : }
190 63 : }
|