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