rsProgram.cpp revision 6e9342199959dc9beb5299fefc9775fe8c32620e
1/*
2 * Copyright (C) 2009 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
17#ifndef ANDROID_RS_BUILD_FOR_HOST
18#include "rsContext.h"
19#include <GLES2/gl2.h>
20#include <GLES2/gl2ext.h>
21#else
22#include "rsContextHostStub.h"
23#include <OpenGL/gl.h>
24#include <OpenGL/glext.h>
25#endif //ANDROID_RS_BUILD_FOR_HOST
26
27#include "rsProgram.h"
28
29using namespace android;
30using namespace android::renderscript;
31
32
33Program::Program(Context *rsc) : ObjectBase(rsc)
34{
35    mAllocFile = __FILE__;
36    mAllocLine = __LINE__;
37    mDirty = true;
38    mShaderID = 0;
39    mAttribCount = 0;
40    mUniformCount = 0;
41
42    mInputElements = NULL;
43    mOutputElements = NULL;
44    mConstantTypes = NULL;
45    mInputCount = 0;
46    mOutputCount = 0;
47    mConstantCount = 0;
48    mIsValid = false;
49}
50
51Program::Program(Context *rsc, const char * shaderText, uint32_t shaderLength,
52                 const uint32_t * params, uint32_t paramLength) :
53    ObjectBase(rsc)
54{
55    mAllocFile = __FILE__;
56    mAllocLine = __LINE__;
57    mDirty = true;
58    mShaderID = 0;
59    mAttribCount = 0;
60    mUniformCount = 0;
61    mTextureCount = 0;
62
63    mInputCount = 0;
64    mOutputCount = 0;
65    mConstantCount = 0;
66
67    for (uint32_t ct=0; ct < paramLength; ct+=2) {
68        if (params[ct] == RS_PROGRAM_PARAM_INPUT) {
69            mInputCount++;
70        }
71        if (params[ct] == RS_PROGRAM_PARAM_OUTPUT) {
72            mOutputCount++;
73        }
74        if (params[ct] == RS_PROGRAM_PARAM_CONSTANT) {
75            mConstantCount++;
76        }
77        if (params[ct] == RS_PROGRAM_PARAM_TEXTURE_COUNT) {
78            mTextureCount = params[ct+1];
79        }
80    }
81
82    mInputElements = new ObjectBaseRef<Element>[mInputCount];
83    mOutputElements = new ObjectBaseRef<Element>[mOutputCount];
84    mConstantTypes = new ObjectBaseRef<Type>[mConstantCount];
85
86    uint32_t input = 0;
87    uint32_t output = 0;
88    uint32_t constant = 0;
89    for (uint32_t ct=0; ct < paramLength; ct+=2) {
90        if (params[ct] == RS_PROGRAM_PARAM_INPUT) {
91            mInputElements[input++].set(reinterpret_cast<Element *>(params[ct+1]));
92        }
93        if (params[ct] == RS_PROGRAM_PARAM_OUTPUT) {
94            mOutputElements[output++].set(reinterpret_cast<Element *>(params[ct+1]));
95        }
96        if (params[ct] == RS_PROGRAM_PARAM_CONSTANT) {
97            mConstantTypes[constant++].set(reinterpret_cast<Type *>(params[ct+1]));
98        }
99    }
100    mUserShader.setTo(shaderText, shaderLength);
101}
102
103Program::~Program()
104{
105    for (uint32_t ct=0; ct < MAX_UNIFORMS; ct++) {
106        bindAllocation(NULL, ct);
107    }
108
109    delete[] mInputElements;
110    delete[] mOutputElements;
111    delete[] mConstantTypes;
112    mInputCount = 0;
113    mOutputCount = 0;
114    mConstantCount = 0;
115}
116
117
118void Program::bindAllocation(Allocation *alloc, uint32_t slot)
119{
120    if (mConstants[slot].get() == alloc) {
121        return;
122    }
123    if (mConstants[slot].get()) {
124        mConstants[slot].get()->removeProgramToDirty(this);
125    }
126    mConstants[slot].set(alloc);
127    if (alloc) {
128        alloc->addProgramToDirty(this);
129    }
130    mDirty = true;
131}
132
133void Program::bindTexture(uint32_t slot, Allocation *a)
134{
135    if (slot >= MAX_TEXTURE) {
136        LOGE("Attempt to bind a texture to a slot > MAX_TEXTURE");
137        return;
138    }
139
140    //LOGE("bindtex %i %p", slot, a);
141    mTextures[slot].set(a);
142    mDirty = true;
143}
144
145void Program::bindSampler(uint32_t slot, Sampler *s)
146{
147    if (slot >= MAX_TEXTURE) {
148        LOGE("Attempt to bind a Sampler to a slot > MAX_TEXTURE");
149        return;
150    }
151
152    mSamplers[slot].set(s);
153    mDirty = true;
154}
155
156String8 Program::getGLSLInputString() const
157{
158    String8 s;
159    for (uint32_t ct=0; ct < mInputCount; ct++) {
160        const Element *e = mInputElements[ct].get();
161        for (uint32_t field=0; field < e->getFieldCount(); field++) {
162            const Element *f = e->getField(field);
163
164            // Cannot be complex
165            rsAssert(!f->getFieldCount());
166            switch(f->getComponent().getVectorSize()) {
167            case 1: s.append("attribute float ATTRIB_"); break;
168            case 2: s.append("attribute vec2 ATTRIB_"); break;
169            case 3: s.append("attribute vec3 ATTRIB_"); break;
170            case 4: s.append("attribute vec4 ATTRIB_"); break;
171            default:
172                rsAssert(0);
173            }
174
175            s.append(e->getFieldName(field));
176            s.append(";\n");
177        }
178    }
179    return s;
180}
181
182String8 Program::getGLSLOutputString() const
183{
184    return String8();
185}
186
187String8 Program::getGLSLConstantString() const
188{
189    return String8();
190}
191
192
193void Program::createShader()
194{
195}
196
197bool Program::loadShader(Context *rsc, uint32_t type)
198{
199    mShaderID = glCreateShader(type);
200    rsAssert(mShaderID);
201
202    if (rsc->props.mLogShaders) {
203        LOGV("Loading shader type %x, ID %i", type, mShaderID);
204        LOGV("%s", mShader.string());
205    }
206
207    if (mShaderID) {
208        const char * ss = mShader.string();
209        glShaderSource(mShaderID, 1, &ss, NULL);
210        glCompileShader(mShaderID);
211
212        GLint compiled = 0;
213        glGetShaderiv(mShaderID, GL_COMPILE_STATUS, &compiled);
214        if (!compiled) {
215            GLint infoLen = 0;
216            glGetShaderiv(mShaderID, GL_INFO_LOG_LENGTH, &infoLen);
217            if (infoLen) {
218                char* buf = (char*) malloc(infoLen);
219                if (buf) {
220                    glGetShaderInfoLog(mShaderID, infoLen, NULL, buf);
221                    LOGE("Could not compile shader \n%s\n", buf);
222                    free(buf);
223                }
224                glDeleteShader(mShaderID);
225                mShaderID = 0;
226                rsc->setError(RS_ERROR_BAD_SHADER, "Error returned from GL driver loading shader text,");
227                return false;
228            }
229        }
230    }
231
232    if (rsc->props.mLogShaders) {
233        LOGV("--Shader load result %x ", glGetError());
234    }
235    mIsValid = true;
236    return true;
237}
238
239void Program::setShader(const char *txt, uint32_t len)
240{
241    mUserShader.setTo(txt, len);
242}
243
244void Program::appendUserConstants() {
245    for (uint32_t ct=0; ct < mConstantCount; ct++) {
246        const Element *e = mConstantTypes[ct]->getElement();
247        for (uint32_t field=0; field < e->getFieldCount(); field++) {
248            const Element *f = e->getField(field);
249            const char *fn = e->getFieldName(field);
250
251            if (fn[0] == '#') {
252                continue;
253            }
254
255            // Cannot be complex
256            rsAssert(!f->getFieldCount());
257            if(f->getType() == RS_TYPE_MATRIX_4X4) {
258                mShader.append("uniform mat4 UNI_");
259            }
260            else if(f->getType() == RS_TYPE_MATRIX_3X3) {
261                mShader.append("uniform mat3 UNI_");
262            }
263            else if(f->getType() == RS_TYPE_MATRIX_2X2) {
264                mShader.append("uniform mat2 UNI_");
265            }
266            else {
267                switch(f->getComponent().getVectorSize()) {
268                case 1: mShader.append("uniform float UNI_"); break;
269                case 2: mShader.append("uniform vec2 UNI_"); break;
270                case 3: mShader.append("uniform vec3 UNI_"); break;
271                case 4: mShader.append("uniform vec4 UNI_"); break;
272                default:
273                    rsAssert(0);
274                }
275            }
276
277            mShader.append(fn);
278            mShader.append(";\n");
279        }
280    }
281}
282
283void Program::setupUserConstants(ShaderCache *sc, bool isFragment) {
284    uint32_t uidx = 1;
285    for (uint32_t ct=0; ct < mConstantCount; ct++) {
286        Allocation *alloc = mConstants[ct+1].get();
287        if (!alloc) {
288            continue;
289        }
290
291        const uint8_t *data = static_cast<const uint8_t *>(alloc->getPtr());
292        const Element *e = mConstantTypes[ct]->getElement();
293        for (uint32_t field=0; field < e->getFieldCount(); field++) {
294            const Element *f = e->getField(field);
295            const char *fieldName = e->getFieldName(field);
296            // If this field is padding, skip it
297            if(fieldName[0] == '#') {
298                continue;
299            }
300
301            uint32_t offset = e->getFieldOffsetBytes(field);
302            const float *fd = reinterpret_cast<const float *>(&data[offset]);
303
304            int32_t slot = -1;
305            if(!isFragment) {
306                slot = sc->vtxUniformSlot(uidx);
307            }
308            else {
309                slot = sc->fragUniformSlot(uidx);
310            }
311
312            //LOGE("Uniform  slot=%i, offset=%i, constant=%i, field=%i, uidx=%i, name=%s", slot, offset, ct, field, uidx, fieldName);
313            if (slot >= 0) {
314                if(f->getType() == RS_TYPE_MATRIX_4X4) {
315                    glUniformMatrix4fv(slot, 1, GL_FALSE, fd);
316                }
317                else if(f->getType() == RS_TYPE_MATRIX_3X3) {
318                    glUniformMatrix3fv(slot, 1, GL_FALSE, fd);
319                }
320                else if(f->getType() == RS_TYPE_MATRIX_2X2) {
321                    glUniformMatrix2fv(slot, 1, GL_FALSE, fd);
322                }
323                else {
324                    switch(f->getComponent().getVectorSize()) {
325                    case 1:
326                        //LOGE("Uniform 1 = %f", fd[0]);
327                        glUniform1fv(slot, 1, fd);
328                        break;
329                    case 2:
330                        //LOGE("Uniform 2 = %f %f", fd[0], fd[1]);
331                        glUniform2fv(slot, 1, fd);
332                        break;
333                    case 3:
334                        //LOGE("Uniform 3 = %f %f %f", fd[0], fd[1], fd[2]);
335                        glUniform3fv(slot, 1, fd);
336                        break;
337                    case 4:
338                        //LOGE("Uniform 4 = %f %f %f %f", fd[0], fd[1], fd[2], fd[3]);
339                        glUniform4fv(slot, 1, fd);
340                        break;
341                    default:
342                        rsAssert(0);
343                    }
344                }
345            }
346            uidx ++;
347        }
348    }
349}
350
351void Program::initAddUserElement(const Element *e, String8 *names, uint32_t *count, const char *prefix)
352{
353    rsAssert(e->getFieldCount());
354    for (uint32_t ct=0; ct < e->getFieldCount(); ct++) {
355        const Element *ce = e->getField(ct);
356        if (ce->getFieldCount()) {
357            initAddUserElement(ce, names, count, prefix);
358        }
359        else if(e->getFieldName(ct)[0] != '#') {
360            String8 tmp(prefix);
361            tmp.append(e->getFieldName(ct));
362            names[*count].setTo(tmp.string());
363            (*count)++;
364        }
365    }
366}
367
368namespace android {
369namespace renderscript {
370
371
372void rsi_ProgramBindConstants(Context *rsc, RsProgram vp, uint32_t slot, RsAllocation constants)
373{
374    Program *p = static_cast<Program *>(vp);
375    p->bindAllocation(static_cast<Allocation *>(constants), slot);
376}
377
378void rsi_ProgramBindTexture(Context *rsc, RsProgram vpf, uint32_t slot, RsAllocation a)
379{
380    Program *p = static_cast<Program *>(vpf);
381    p->bindTexture(slot, static_cast<Allocation *>(a));
382}
383
384void rsi_ProgramBindSampler(Context *rsc, RsProgram vpf, uint32_t slot, RsSampler s)
385{
386    Program *p = static_cast<Program *>(vpf);
387    p->bindSampler(slot, static_cast<Sampler *>(s));
388}
389
390}
391}
392
393