1/*
2* Copyright (C) 2011 The Android Open Source Project
3*
4* Licensed under the Apache License, Version 2.0 (the "License");
5* you may not use this file except in compliance with the License.
6* You may obtain a copy of the License at
7*
8* http://www.apache.org/licenses/LICENSE-2.0
9*
10* Unless required by applicable law or agreed to in writing, software
11* distributed under the License is distributed on an "AS IS" BASIS,
12* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13* See the License for the specific language governing permissions and
14* limitations under the License.
15*/
16#include "RenderingThread.h"
17#include <stdlib.h>
18#include <unistd.h>
19#include <string.h>
20#include <pthread.h>
21#include "ReadBuffer.h"
22#include "Renderer.h"
23#include "TimeUtils.h"
24
25#include <GLES/glext.h>
26
27__thread RenderingThread * RenderingThread::m_tls;
28
29#ifdef PVR_WAR
30void RenderingThread::s_glTexParameteriv(GLenum target, GLenum param, const int *p)
31{
32    if (target == GL_TEXTURE_2D && param == GL_TEXTURE_CROP_RECT_OES) {
33        m_tls->m_currentContext->addPendingCropRect(p);
34    } else {
35        m_tls->m_glTexParameteriv(target, param, p);
36    }
37}
38
39void RenderingThread::s_glDrawTexfOES(GLfloat x, GLfloat y, GLfloat z, GLfloat w, GLfloat h)
40{
41    m_tls->applyPendingCropRects();
42    m_tls->m_glDrawTexfOES(x, y, z, w, h);
43    m_tls->fixTextureEnable();
44}
45
46void RenderingThread::s_glDrawTexsOES(GLshort x, GLshort y, GLshort z, GLshort w, GLshort h)
47{
48    m_tls->applyPendingCropRects();
49    m_tls->m_glDrawTexsOES(x, y, z, w, h);
50    m_tls->fixTextureEnable();
51}
52
53void RenderingThread::s_glDrawTexiOES(GLint x, GLint y, GLint z, GLint w, GLint h)
54{
55    m_tls->applyPendingCropRects();
56    m_tls->m_glDrawTexiOES(x, y, z, w, h);
57    m_tls->fixTextureEnable();
58}
59
60void RenderingThread::s_glDrawTexxOES(GLfixed x, GLfixed y, GLfixed z, GLfixed w, GLfixed h)
61{
62    m_tls->applyPendingCropRects();
63    m_tls->m_glDrawTexxOES(x, y, z, w, h);
64    m_tls->fixTextureEnable();
65}
66
67void RenderingThread::s_glDrawTexfvOES(const GLfloat *coords)
68{
69    m_tls->applyPendingCropRects();
70    m_tls->m_glDrawTexfvOES(coords);
71    m_tls->fixTextureEnable();
72}
73
74void RenderingThread::s_glDrawTexsvOES(const GLshort *coords)
75{
76    m_tls->applyPendingCropRects();
77    m_tls->m_glDrawTexsvOES(coords);
78    m_tls->fixTextureEnable();
79}
80
81void RenderingThread::s_glDrawTexivOES(const GLint *coords)
82{
83    m_tls->applyPendingCropRects();
84    m_tls->m_glDrawTexivOES(coords);
85    m_tls->fixTextureEnable();
86}
87
88void RenderingThread::s_glDrawTexxvOES(const GLfixed *coords)
89{
90    m_tls->applyPendingCropRects();
91    m_tls->m_glDrawTexxvOES(coords);
92    m_tls->fixTextureEnable();
93}
94
95
96void RenderingThread::s_glActiveTexture(GLenum texture)
97{
98    if (texture - GL_TEXTURE0 >= m_tls->m_backendCaps.maxTextureUnits) return;
99
100    m_tls->m_currentContext->setActiveTexture(texture);
101    m_tls->m_glActiveTexture(texture);
102}
103
104void RenderingThread::s_glBindTexture(GLenum target, GLuint texture)
105{
106    if (target == GL_TEXTURE_2D) m_tls->m_currentContext->setTex2DBind(texture);
107    m_tls->m_glBindTexture(target, texture);
108}
109
110void RenderingThread::s_glEnable(GLenum cap)
111{
112    if (cap == GL_TEXTURE_2D) m_tls->m_currentContext->setTex2DEnable(true);
113    m_tls->m_glEnable(cap);
114}
115
116void RenderingThread::s_glDisable(GLenum cap)
117{
118    if (cap == GL_TEXTURE_2D) m_tls->m_currentContext->setTex2DEnable(false);
119    m_tls->m_glDisable(cap);
120}
121
122void RenderingThread::s_glClientActiveTexture(GLenum texture)
123{
124    if (texture - GL_TEXTURE0 >= m_tls->m_backendCaps.maxTextureUnits) return;
125    m_tls->m_currentContext->setClientActiveTexture(texture);
126    m_tls->m_glClientActiveTexture(texture);
127}
128
129void RenderingThread::s_glEnableClientState(GLenum cap)
130{
131    m_tls->m_currentContext->enableClientState(cap, true);
132    m_tls->m_glEnableClientState(cap);
133}
134
135void RenderingThread::s_glDisableClientState(GLenum cap)
136{
137    m_tls->m_currentContext->enableClientState(cap, false);
138    m_tls->m_glDisableClientState(cap);
139}
140
141void RenderingThread::applyPendingCropRects()
142{
143    PendingCropRectSet &rset = m_currentContext->getPendingCropRects();
144    if (rset.size() > 0) {
145        GLuint currBindedTex = m_currentContext->getTex2DBind();
146        for (PendingCropRectSet::iterator i = rset.begin();
147             i != rset.end();
148             i++) {
149            m_glBindTexture(GL_TEXTURE_2D, (*i)->texture);
150            m_glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_CROP_RECT_OES, (int *)(*i)->rect);
151            delete (*i);
152        }
153        m_glBindTexture(GL_TEXTURE_2D, currBindedTex);
154        rset.clear();
155    }
156}
157
158void RenderingThread::fixTextureEnable()
159{
160    // restore texture units enable state
161    for (unsigned int i=0; i<m_backendCaps.maxTextureUnits; i++) {
162        m_glActiveTexture(GL_TEXTURE0 + i);
163        if (m_currentContext->isTex2DEnable(i)) {
164            m_glEnable(GL_TEXTURE_2D);
165        }
166        else {
167            m_glDisable(GL_TEXTURE_2D);
168        }
169        m_glClientActiveTexture(GL_TEXTURE0 + i);
170        if (m_currentContext->getClientState(GL_TEXTURE_COORD_ARRAY, i)) {
171            m_glEnableClientState(GL_TEXTURE_COORD_ARRAY);
172        }
173        else {
174            m_glDisableClientState(GL_TEXTURE_COORD_ARRAY);
175        }
176    }
177    // restore current active texture
178    m_glActiveTexture(m_currentContext->getActiveTexture());
179    m_glClientActiveTexture(m_currentContext->getClientActiveTexture());
180
181    // restore other client state enable bits
182    if (m_currentContext->getClientState(GL_VERTEX_ARRAY, 0)) {
183        m_glEnableClientState(GL_VERTEX_ARRAY);
184    }
185    else {
186        m_glDisableClientState(GL_VERTEX_ARRAY);
187    }
188
189    if (m_currentContext->getClientState(GL_NORMAL_ARRAY, 0)) {
190        m_glEnableClientState(GL_NORMAL_ARRAY);
191    }
192    else {
193        m_glDisableClientState(GL_NORMAL_ARRAY);
194    }
195
196    if (m_currentContext->getClientState(GL_COLOR_ARRAY, 0)) {
197        m_glEnableClientState(GL_COLOR_ARRAY);
198    }
199    else {
200        m_glDisableClientState(GL_COLOR_ARRAY);
201    }
202
203    if (m_currentContext->getClientState(GL_POINT_SIZE_ARRAY_OES, 0)) {
204        m_glEnableClientState(GL_POINT_SIZE_ARRAY_OES);
205    }
206    else {
207        m_glDisableClientState(GL_POINT_SIZE_ARRAY_OES);
208    }
209}
210#endif
211
212
213int RenderingThread::s_createContext(uint32_t pid, uint32_t handle, uint32_t shareCtx, int version)
214{
215    return Renderer::instance()->createContext(m_tls, Renderer::ClientHandle(pid, handle),
216                                               Renderer::ClientHandle(pid, shareCtx),
217                                               version);
218
219}
220
221
222int RenderingThread::s_createSurface(uint32_t pid, uint32_t handle)
223{
224    return Renderer::instance()->createSurface(m_tls, Renderer::ClientHandle(pid, handle));
225}
226
227int RenderingThread::s_destroySurface(uint32_t pid, uint32_t handle)
228{
229    return Renderer::instance()->destroySurface(m_tls, Renderer::ClientHandle(pid, handle));
230}
231
232int RenderingThread::s_destroyContext(uint32_t pid, uint32_t handle)
233{
234    return Renderer::instance()->destroyContext(m_tls, Renderer::ClientHandle(pid, handle));
235}
236
237
238int RenderingThread::s_makeCurrent(uint32_t pid, uint32_t drawSurface, uint32_t readSurface, uint32_t ctx)
239{
240    int ret = Renderer::instance()->makeCurrent(m_tls,
241                                             Renderer::ClientHandle(pid, drawSurface),
242                                             Renderer::ClientHandle(pid, readSurface),
243                                             Renderer::ClientHandle(pid, ctx));
244
245    if (ret && ctx) {
246        m_tls->initBackendCaps();
247    }
248
249    return ret;
250}
251
252void RenderingThread::s_swapBuffers(uint32_t pid, uint32_t surface)
253{
254    Renderer::instance()->swapBuffers(m_tls, Renderer::ClientHandle(pid, surface));
255}
256
257
258RenderingThread::RenderingThread(SocketStream *stream) :
259    m_stream(stream),
260    m_currentContext(NULL)
261{
262    m_backendCaps.initialized = false;
263}
264
265int RenderingThread::start(void)
266{
267    if (pthread_create(&m_thread, NULL, s_thread, this) < 0) {
268        perror("pthread_create");
269        return -1;
270    }
271    return 0;
272}
273
274
275void * RenderingThread::s_thread(void *data)
276{
277    RenderingThread *self = (RenderingThread *)data;
278    m_tls = self;
279    return self->thread();
280}
281
282void RenderingThread::initBackendCaps()
283{
284    if (m_backendCaps.initialized) return;
285
286    m_glDec.glGetIntegerv(GL_MAX_TEXTURE_UNITS, (GLint *)&m_backendCaps.maxTextureUnits);
287    m_backendCaps.initialized = true;
288}
289
290void *RenderingThread::thread()
291{
292
293    // initialize our decoders;
294    m_glDec.initGL();
295
296#ifdef PVR_WAR
297    m_glTexParameteriv = m_glDec.set_glTexParameteriv(s_glTexParameteriv);
298    m_glDrawTexfOES = m_glDec.set_glDrawTexfOES(s_glDrawTexfOES);
299    m_glDrawTexsOES = m_glDec.set_glDrawTexsOES(s_glDrawTexsOES);
300    m_glDrawTexiOES = m_glDec.set_glDrawTexiOES(s_glDrawTexiOES);
301    m_glDrawTexxOES = m_glDec.set_glDrawTexxOES(s_glDrawTexxOES);
302    m_glDrawTexfvOES = m_glDec.set_glDrawTexfvOES(s_glDrawTexfvOES);
303    m_glDrawTexsvOES = m_glDec.set_glDrawTexsvOES(s_glDrawTexsvOES);
304    m_glDrawTexivOES = m_glDec.set_glDrawTexivOES(s_glDrawTexivOES);
305    m_glDrawTexxvOES = m_glDec.set_glDrawTexxvOES(s_glDrawTexxvOES);
306    m_glActiveTexture = m_glDec.set_glActiveTexture(s_glActiveTexture);
307    m_glBindTexture = m_glDec.set_glBindTexture(s_glBindTexture);
308    m_glEnable = m_glDec.set_glEnable(s_glEnable);
309    m_glDisable = m_glDec.set_glDisable(s_glDisable);
310    m_glClientActiveTexture = m_glDec.set_glClientActiveTexture(s_glClientActiveTexture);
311    m_glEnableClientState = m_glDec.set_glEnableClientState(s_glEnableClientState);
312    m_glDisableClientState = m_glDec.set_glDisableClientState(s_glDisableClientState);
313#endif
314
315    m_gl2Dec.initGL();
316
317    m_utDec.set_swapBuffers(s_swapBuffers);
318    m_utDec.set_createContext(s_createContext);
319    m_utDec.set_destroyContext(s_destroyContext);
320    m_utDec.set_createSurface(s_createSurface);
321    m_utDec.set_destroySurface(s_destroySurface);
322    m_utDec.set_makeCurrentContext(s_makeCurrent);
323
324    ReadBuffer readBuf(m_stream, DECODER_BUF_SIZE);
325
326    int stats_totalBytes = 0;
327    long long stats_t0 = GetCurrentTimeMS();
328
329    while (1) {
330
331        int stat = readBuf.getData();
332        if (stat == 0) {
333            fprintf(stderr, "client shutdown\n");
334            break;
335        } else if (stat < 0) {
336            perror("getData");
337            break;
338        }
339
340        //
341        // log received bandwidth statistics
342        //
343        stats_totalBytes += readBuf.validData();
344        long long dt = GetCurrentTimeMS() - stats_t0;
345        if (dt > 1000) {
346            float dts = (float)dt / 1000.0f;
347            printf("Used Bandwidth %5.3f MB/s\n", ((float)stats_totalBytes / dts) / (1024.0f*1024.0f));
348            stats_totalBytes = 0;
349            stats_t0 = GetCurrentTimeMS();
350        }
351
352        bool progress = true;
353        while (progress) {
354            progress = false;
355            // we need at least one header (8 bytes) in our buffer
356            if (readBuf.validData() >= 8) {
357                size_t last = m_glDec.decode(readBuf.buf(), readBuf.validData(), m_stream);
358                if (last > 0) {
359                    progress = true;
360                    readBuf.consume(last);
361                }
362            }
363
364            if (readBuf.validData() >= 8) {
365                size_t last = m_gl2Dec.decode(readBuf.buf(), readBuf.validData(), m_stream);
366                if (last > 0) {
367                    readBuf.consume(last);
368                    progress = true;
369                }
370            }
371
372            if (readBuf.validData() >= 8) {
373                size_t last = m_utDec.decode(readBuf.buf(), readBuf.validData(), m_stream);
374                if (last > 0) {
375                    readBuf.consume(last);
376                    progress = true;
377                }
378            }
379        }
380    }
381    // shutdown
382    if (m_currentContext != NULL) {
383        m_currentContext->unref();
384    }
385
386    return NULL;
387}
388