Line data Source code
1 : /* Copyright (c) 2009, Cedric Stalder <cedric.stalder@gmail.com>
2 : * 2009, Maxim Makhinya
3 : * 2010-2013, Stefan Eilemann <eile@eyescale.ch>
4 : * 2012, Daniel Nachbaur <danielnachbaur@gmail.com>
5 : *
6 : * This library is free software; you can redistribute it and/or modify it under
7 : * the terms of the GNU Lesser General Public License version 2.1 as published
8 : * by the Free Software Foundation.
9 : *
10 : * This library is distributed in the hope that it will be useful, but WITHOUT
11 : * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
12 : * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
13 : * details.
14 : *
15 : * You should have received a copy of the GNU Lesser General Public License
16 : * along with this library; if not, write to the Free Software Foundation, Inc.,
17 : * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 : */
19 :
20 : #include "compressorYUV.h"
21 :
22 : #include <eq/util/frameBufferObject.h>
23 : #include <eq/client/gl.h>
24 : #include <eq/client/zoomFilter.h>
25 : #include <eq/fabric/pixelViewport.h>
26 :
27 : #include "yuv420readback_glsl.h"
28 : #include "yuv420unpack_glsl.h"
29 :
30 : #define glewGetContext() glewContext
31 :
32 : namespace eq
33 : {
34 : namespace plugin
35 : {
36 : namespace
37 : {
38 9 : static void _getInfo( EqCompressorInfo* const info )
39 : {
40 9 : info->version = EQ_COMPRESSOR_VERSION;
41 9 : info->name = EQ_COMPRESSOR_TRANSFER_RGBA_TO_YUVA_50P;
42 : info->capabilities = EQ_COMPRESSOR_TRANSFER | EQ_COMPRESSOR_DATA_2D |
43 : EQ_COMPRESSOR_USE_TEXTURE_RECT |
44 9 : EQ_COMPRESSOR_USE_FRAMEBUFFER;
45 9 : info->tokenType = EQ_COMPRESSOR_DATATYPE_RGBA;
46 9 : info->outputTokenType = EQ_COMPRESSOR_DATATYPE_YUVA_50P;
47 9 : info->outputTokenSize = 4;
48 9 : info->quality = 0.5f;
49 9 : info->ratio = 0.5f;
50 9 : info->speed = 0.5f;
51 9 : }
52 :
53 12 : static bool _register()
54 : {
55 : Compressor::registerEngine(
56 : Compressor::Functions( EQ_COMPRESSOR_TRANSFER_RGBA_TO_YUVA_50P,
57 : _getInfo, CompressorYUV::getNewCompressor,
58 : CompressorYUV::getNewDecompressor, 0,
59 12 : CompressorYUV::isCompatible ));
60 12 : return true;
61 : }
62 :
63 12 : static bool _initialized LB_UNUSED = _register();
64 : }
65 :
66 : /** Construct a new compressor Yuv */
67 0 : CompressorYUV::CompressorYUV()
68 : : Compressor()
69 : , _program( 0 )
70 : , _fbo( 0 )
71 0 : , _texture( 0 )
72 0 : { }
73 :
74 : /** Destruct the compressor Yuv */
75 0 : CompressorYUV::~CompressorYUV( )
76 : {
77 : // replace original texture
78 0 : delete _fbo;
79 0 : _fbo = 0;
80 :
81 0 : if ( _texture )
82 : {
83 0 : _texture->flush();
84 0 : delete _texture;
85 : }
86 0 : _texture = 0;
87 0 : }
88 :
89 0 : bool CompressorYUV::isCompatible( const GLEWContext* glewContext )
90 : {
91 0 : return ( GLEW_ARB_texture_non_power_of_two &&
92 0 : GLEW_VERSION_2_0 &&
93 0 : GLEW_EXT_framebuffer_object );
94 : }
95 :
96 0 : void CompressorYUV::_initShader( const GLEWContext* glewContext LB_UNUSED,
97 : const char* fShaderPtr )
98 : {
99 0 : if ( _program )
100 : {
101 : // use fragment shader and setup uniforms
102 0 : EQ_GL_CALL( glUseProgram( _program ));
103 0 : return ;
104 : }
105 :
106 : // Create fragment shader which reads depth values from
107 : // rectangular textures
108 0 : const GLuint shader = glCreateShader( GL_FRAGMENT_SHADER );
109 :
110 0 : EQ_GL_CALL( glShaderSource( shader, 1, &fShaderPtr, 0 ));
111 0 : EQ_GL_CALL( glCompileShader( shader ));
112 :
113 : GLint status;
114 0 : glGetShaderiv( shader, GL_COMPILE_STATUS, &status );
115 0 : LBASSERT( status );
116 :
117 0 : _program = glCreateProgram( );
118 :
119 0 : EQ_GL_CALL( glAttachShader( _program, shader ));
120 0 : EQ_GL_CALL( glLinkProgram( _program ));
121 :
122 0 : glGetProgramiv( _program, GL_LINK_STATUS, &status );
123 0 : LBASSERT( status );
124 :
125 : // use fragment shader and setup uniforms
126 0 : EQ_GL_CALL( glUseProgram( _program ));
127 :
128 : }
129 :
130 :
131 0 : void CompressorYUV::_compress( const GLEWContext* glewContext,
132 : const eq_uint64_t* /*inDims*/,
133 : eq_uint64_t outDims[4] )
134 : {
135 : /* save the current FBO ID for bind it at the end of the compression */
136 0 : GLint oldFBO = 0;
137 0 : glGetIntegerv( GL_FRAMEBUFFER_BINDING_EXT, &oldFBO );
138 :
139 0 : if ( _fbo )
140 : {
141 0 : LBCHECK( _fbo->resize( outDims[1], outDims[3] ));
142 0 : _fbo->bind();
143 : }
144 : else
145 : {
146 0 : _fbo = new util::FrameBufferObject( glewContext );
147 0 : LBCHECK( _fbo->init( outDims[1], outDims[3], GL_RGBA, 0, 0 ));
148 : }
149 :
150 0 : _texture->bind();
151 :
152 0 : glDisable( GL_LIGHTING );
153 0 : glEnable( GL_TEXTURE_RECTANGLE_ARB );
154 :
155 0 : _texture->applyZoomFilter( FILTER_NEAREST );
156 0 : _texture->applyWrap();
157 :
158 0 : _initShader( glewContext, yuv420readback_glsl.c_str() );
159 :
160 0 : const GLint colorParam = glGetUniformLocation( _program, "color" );
161 0 : EQ_GL_CALL( glUniform1i( colorParam, 0 ));
162 :
163 0 : glDisable( GL_DEPTH_TEST );
164 0 : glBegin( GL_QUADS );
165 0 : glVertex3i( 0, 0, 0 );
166 0 : glVertex3i( outDims[1], 0, 0 );
167 0 : glVertex3i( outDims[1], outDims[3], 0 );
168 0 : glVertex3i( 0, outDims[3], 0 );
169 0 : glEnd();
170 :
171 : // restore state
172 : //glEnable( GL_DEPTH_TEST );
173 0 : glDisable( GL_TEXTURE_RECTANGLE_ARB );
174 0 : EQ_GL_CALL( glUseProgram( 0 ));
175 :
176 : /* apply the initial fbo */
177 0 : EQ_GL_CALL( glBindFramebufferEXT( GL_FRAMEBUFFER_EXT, oldFBO ));
178 0 : }
179 :
180 0 : void CompressorYUV::_download( void* data )
181 : {
182 0 : util::Texture* texture = _fbo->getColorTextures()[0];
183 0 : LBASSERT( texture->getFormat() == GL_RGBA );
184 0 : LBASSERT( texture->getType() == GL_UNSIGNED_BYTE );
185 0 : texture->download( data );
186 0 : }
187 :
188 0 : void CompressorYUV::download( const GLEWContext* glewContext,
189 : const eq_uint64_t inDims[4],
190 : const unsigned source,
191 : const eq_uint64_t flags,
192 : eq_uint64_t outDims[4],
193 : void** out )
194 : {
195 : glPushAttrib( GL_ENABLE_BIT | GL_DEPTH_BUFFER_BIT | GL_TEXTURE_BIT |
196 0 : GL_COLOR_BUFFER_BIT | GL_CURRENT_BIT | GL_LIGHTING_BIT );
197 0 : glColorMask( true, true, true, true );
198 0 : outDims[0] = inDims[0];
199 0 : outDims[1] = (inDims[1] + 1) / 2;
200 0 : outDims[2] = inDims[2];
201 0 : outDims[3] = (inDims[3] + 1) / 2;
202 0 : outDims[3] *= 2;
203 0 : buffer.resize( outDims[1] * outDims[3] * 4 );
204 : // first time we instanciate the working texture
205 0 : if ( !_texture )
206 0 : _texture = new util::Texture( GL_TEXTURE_RECTANGLE_ARB, glewContext );
207 :
208 : // the data is in the frame buffer
209 0 : if( flags & EQ_COMPRESSOR_USE_FRAMEBUFFER )
210 : {
211 : // read data in frame Buffer
212 0 : const eq::fabric::PixelViewport pvp( inDims[0], inDims[2],
213 0 : inDims[1], inDims[3] );
214 0 : _texture->init( GL_RGBA, outDims[1]*2, outDims[3] );
215 0 : _texture->copyFromFrameBuffer( GL_RGBA, pvp );
216 :
217 : // compress data
218 0 : _compress( glewContext, inDims, outDims );
219 0 : buffer.resize( outDims[1] * outDims[3] * 4 );
220 0 : _download( buffer.getData( ));
221 : }
222 : // the data is in the texture id define by the field "source"
223 0 : else if( flags & EQ_COMPRESSOR_USE_TEXTURE_RECT )
224 : {
225 : // assign texture id to the local texture class
226 : // compress Data
227 : // allow buffer memory on cpu
228 : // transfer data from gpu to cpu
229 0 : _texture->setGLData( source, GL_RGBA, inDims[1], inDims[3] );
230 0 : _compress( glewContext, inDims, outDims );
231 0 : _download( buffer.getData( ));
232 0 : _texture->flushNoDelete();
233 : }
234 : else
235 : {
236 0 : LBUNIMPLEMENTED;
237 : }
238 0 : out[0] = buffer.getData();
239 0 : glPopAttrib();
240 0 : }
241 :
242 0 : void CompressorYUV::_decompress( const GLEWContext* glewContext,
243 : const eq_uint64_t inDims[4] )
244 : {
245 0 : glDepthMask( false );
246 0 : _initShader( glewContext, yuv420unpack_glsl.c_str() );
247 :
248 0 : const GLint colorParam = glGetUniformLocation( _program, "color" );
249 0 : glUniform1i( colorParam, 0 );
250 :
251 0 : glDisable( GL_LIGHTING );
252 0 : glEnable( GL_TEXTURE_RECTANGLE_ARB );
253 :
254 0 : _texture->applyWrap();
255 0 : _texture->applyZoomFilter( FILTER_NEAREST );
256 :
257 0 : glColor3f( 1.0f, 1.0f, 1.0f );
258 0 : const float startX = static_cast< float >( inDims[0] );
259 0 : const float endX = static_cast< float >( inDims[1] ) + startX;
260 0 : const float startY = static_cast< float >( inDims[2] );
261 0 : const float endY = static_cast< float >( inDims[3] ) + startY;
262 :
263 0 : const GLint shiftX = glGetUniformLocation( _program, "shiftX" );
264 0 : glUniform1f( shiftX, startX );
265 0 : const GLint shiftY = glGetUniformLocation( _program, "shiftY" );
266 0 : glUniform1f( shiftY, startY );
267 :
268 0 : glBegin( GL_QUADS );
269 0 : glVertex3f( startX, startY, 0.0f );
270 0 : glVertex3f( endX, startY, 0.0f );
271 0 : glVertex3f( endX, endY, 0.0f );
272 0 : glVertex3f( startX, endY, 0.0f );
273 0 : glEnd();
274 :
275 0 : glDisable( GL_TEXTURE_RECTANGLE_ARB );
276 0 : EQ_GL_CALL( glUseProgram( 0 ));
277 0 : glDepthMask( true );
278 0 : }
279 :
280 0 : void CompressorYUV::upload( const GLEWContext* glewContext,
281 : const void* data,
282 : const eq_uint64_t inDims[4],
283 : const eq_uint64_t flags,
284 : const eq_uint64_t outDims[4],
285 : const unsigned destination )
286 : {
287 : glPushAttrib( GL_ENABLE_BIT | GL_DEPTH_BUFFER_BIT | GL_TEXTURE_BIT |
288 0 : GL_COLOR_BUFFER_BIT | GL_CURRENT_BIT | GL_LIGHTING_BIT );
289 0 : if ( !_texture )
290 : {
291 0 : _texture = new util::Texture( GL_TEXTURE_RECTANGLE_ARB, glewContext );
292 0 : _texture->init( GL_RGBA, outDims[1], outDims[3] );
293 : }
294 :
295 0 : if ( flags & EQ_COMPRESSOR_USE_FRAMEBUFFER )
296 : {
297 0 : _texture->upload( inDims[1], inDims[3], data );
298 0 : _decompress( glewContext, outDims );
299 : }
300 0 : else if( flags & EQ_COMPRESSOR_USE_TEXTURE_RECT )
301 : {
302 : /* save the current FBO ID for bind it at the end of the compression */
303 0 : GLint oldFBO = 0;
304 0 : glGetIntegerv( GL_FRAMEBUFFER_BINDING_EXT, &oldFBO );
305 :
306 0 : if ( !_fbo )
307 0 : _fbo = new util::FrameBufferObject( glewContext );
308 :
309 0 : util::Texture* texture = _fbo->getColorTextures().front();
310 0 : texture->setGLData( destination, GL_RGBA, outDims[1], outDims[3] );
311 :
312 0 : if( _fbo->isValid() )
313 : {
314 0 : _fbo->bind();
315 0 : texture->bindToFBO( GL_COLOR_ATTACHMENT0, outDims[1], outDims[3] );
316 : }
317 : else
318 : {
319 0 : LBCHECK( _fbo->init( outDims[1], outDims[3], GL_RGBA, 0, 0 ));
320 : }
321 :
322 0 : _texture->upload( inDims[1], inDims[3], data );
323 0 : _decompress( glewContext, outDims );
324 :
325 : /* apply the initial fbo */
326 0 : EQ_GL_CALL( glBindFramebufferEXT( GL_FRAMEBUFFER_EXT, oldFBO ));
327 :
328 0 : texture->flushNoDelete();
329 : }
330 : else
331 : {
332 0 : LBASSERT( 0 );
333 : }
334 0 : glPopAttrib();
335 0 : }
336 :
337 : }
338 36 : }
|