rsdShader.cpp revision 7f126c78a107257090c6675ea40ffac41516a9dc
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
17#include <GLES2/gl2.h>
18#include <GLES2/gl2ext.h>
19
20#include <rs_hal.h>
21#include <rsContext.h>
22#include <rsProgram.h>
23
24#include "rsdCore.h"
25#include "rsdShader.h"
26#include "rsdShaderCache.h"
27
28using namespace android;
29using namespace android::renderscript;
30
31RsdShader::RsdShader(const Program *p, uint32_t type,
32                       const char * shaderText, uint32_t shaderLength) {
33
34    mUserShader.setTo(shaderText, shaderLength);
35    mRSProgram = p;
36    mType = type;
37    initMemberVars();
38    initAttribAndUniformArray();
39    init();
40}
41
42RsdShader::~RsdShader() {
43    if (mShaderID) {
44        glDeleteShader(mShaderID);
45    }
46
47    delete[] mAttribNames;
48    delete[] mUniformNames;
49    delete[] mUniformArraySizes;
50}
51
52void RsdShader::initMemberVars() {
53    mDirty = true;
54    mShaderID = 0;
55    mAttribCount = 0;
56    mUniformCount = 0;
57
58    mAttribNames = NULL;
59    mUniformNames = NULL;
60    mUniformArraySizes = NULL;
61
62    mIsValid = false;
63}
64
65void RsdShader::init() {
66    uint32_t attribCount = 0;
67    uint32_t uniformCount = 0;
68    for (uint32_t ct=0; ct < mRSProgram->mHal.state.inputElementsCount; ct++) {
69        initAddUserElement(mRSProgram->mHal.state.inputElements[ct].get(), mAttribNames, NULL, &attribCount, RS_SHADER_ATTR);
70    }
71    for (uint32_t ct=0; ct < mRSProgram->mHal.state.constantsCount; ct++) {
72        initAddUserElement(mRSProgram->mHal.state.constantTypes[ct]->getElement(), mUniformNames, mUniformArraySizes, &uniformCount, RS_SHADER_UNI);
73    }
74
75    mTextureUniformIndexStart = uniformCount;
76    char buf[256];
77    for (uint32_t ct=0; ct < mRSProgram->mHal.state.texturesCount; ct++) {
78        snprintf(buf, sizeof(buf), "UNI_Tex%i", ct);
79        mUniformNames[uniformCount].setTo(buf);
80        mUniformArraySizes[uniformCount] = 1;
81        uniformCount++;
82    }
83}
84
85String8 RsdShader::getGLSLInputString() const {
86    String8 s;
87    for (uint32_t ct=0; ct < mRSProgram->mHal.state.inputElementsCount; ct++) {
88        const Element *e = mRSProgram->mHal.state.inputElements[ct].get();
89        for (uint32_t field=0; field < e->getFieldCount(); field++) {
90            const Element *f = e->getField(field);
91
92            // Cannot be complex
93            rsAssert(!f->getFieldCount());
94            switch (f->getComponent().getVectorSize()) {
95            case 1: s.append("attribute float ATTRIB_"); break;
96            case 2: s.append("attribute vec2 ATTRIB_"); break;
97            case 3: s.append("attribute vec3 ATTRIB_"); break;
98            case 4: s.append("attribute vec4 ATTRIB_"); break;
99            default:
100                rsAssert(0);
101            }
102
103            s.append(e->getFieldName(field));
104            s.append(";\n");
105        }
106    }
107    return s;
108}
109
110void RsdShader::appendAttributes() {
111    for (uint32_t ct=0; ct < mRSProgram->mHal.state.inputElementsCount; ct++) {
112        const Element *e = mRSProgram->mHal.state.inputElements[ct].get();
113        for (uint32_t field=0; field < e->getFieldCount(); field++) {
114            const Element *f = e->getField(field);
115            const char *fn = e->getFieldName(field);
116
117            if (fn[0] == '#') {
118                continue;
119            }
120
121            // Cannot be complex
122            rsAssert(!f->getFieldCount());
123            switch (f->getComponent().getVectorSize()) {
124            case 1: mShader.append("attribute float ATTRIB_"); break;
125            case 2: mShader.append("attribute vec2 ATTRIB_"); break;
126            case 3: mShader.append("attribute vec3 ATTRIB_"); break;
127            case 4: mShader.append("attribute vec4 ATTRIB_"); break;
128            default:
129                rsAssert(0);
130            }
131
132            mShader.append(fn);
133            mShader.append(";\n");
134        }
135    }
136}
137
138void RsdShader::appendTextures() {
139    char buf[256];
140    for (uint32_t ct=0; ct < mRSProgram->mHal.state.texturesCount; ct++) {
141        if (mRSProgram->mHal.state.textureTargets[ct] == RS_TEXTURE_2D) {
142            snprintf(buf, sizeof(buf), "uniform sampler2D UNI_Tex%i;\n", ct);
143        } else {
144            snprintf(buf, sizeof(buf), "uniform samplerCube UNI_Tex%i;\n", ct);
145        }
146        mShader.append(buf);
147    }
148}
149
150bool RsdShader::createShader() {
151
152    if (mType == GL_FRAGMENT_SHADER) {
153        mShader.append("precision mediump float;\n");
154    }
155    appendUserConstants();
156    appendAttributes();
157    appendTextures();
158
159    mShader.append(mUserShader);
160
161    return true;
162}
163
164bool RsdShader::loadShader(const Context *rsc) {
165    mShaderID = glCreateShader(mType);
166    rsAssert(mShaderID);
167
168    if (rsc->props.mLogShaders) {
169        LOGV("Loading shader type %x, ID %i", mType, mShaderID);
170        LOGV("%s", mShader.string());
171    }
172
173    if (mShaderID) {
174        const char * ss = mShader.string();
175        glShaderSource(mShaderID, 1, &ss, NULL);
176        glCompileShader(mShaderID);
177
178        GLint compiled = 0;
179        glGetShaderiv(mShaderID, GL_COMPILE_STATUS, &compiled);
180        if (!compiled) {
181            GLint infoLen = 0;
182            glGetShaderiv(mShaderID, GL_INFO_LOG_LENGTH, &infoLen);
183            if (infoLen) {
184                char* buf = (char*) malloc(infoLen);
185                if (buf) {
186                    glGetShaderInfoLog(mShaderID, infoLen, NULL, buf);
187                    LOGE("Could not compile shader \n%s\n", buf);
188                    free(buf);
189                }
190                glDeleteShader(mShaderID);
191                mShaderID = 0;
192                rsc->setError(RS_ERROR_BAD_SHADER, "Error returned from GL driver loading shader text,");
193                return false;
194            }
195        }
196    }
197
198    if (rsc->props.mLogShaders) {
199        LOGV("--Shader load result %x ", glGetError());
200    }
201    mIsValid = true;
202    return true;
203}
204
205void RsdShader::appendUserConstants() {
206    for (uint32_t ct=0; ct < mRSProgram->mHal.state.constantsCount; ct++) {
207        const Element *e = mRSProgram->mHal.state.constantTypes[ct]->getElement();
208        for (uint32_t field=0; field < e->getFieldCount(); field++) {
209            const Element *f = e->getField(field);
210            const char *fn = e->getFieldName(field);
211
212            if (fn[0] == '#') {
213                continue;
214            }
215
216            // Cannot be complex
217            rsAssert(!f->getFieldCount());
218            if (f->getType() == RS_TYPE_MATRIX_4X4) {
219                mShader.append("uniform mat4 UNI_");
220            } else if (f->getType() == RS_TYPE_MATRIX_3X3) {
221                mShader.append("uniform mat3 UNI_");
222            } else if (f->getType() == RS_TYPE_MATRIX_2X2) {
223                mShader.append("uniform mat2 UNI_");
224            } else {
225                switch (f->getComponent().getVectorSize()) {
226                case 1: mShader.append("uniform float UNI_"); break;
227                case 2: mShader.append("uniform vec2 UNI_"); break;
228                case 3: mShader.append("uniform vec3 UNI_"); break;
229                case 4: mShader.append("uniform vec4 UNI_"); break;
230                default:
231                    rsAssert(0);
232                }
233            }
234
235            mShader.append(fn);
236            if (e->getFieldArraySize(field) > 1) {
237                mShader.appendFormat("[%d]", e->getFieldArraySize(field));
238            }
239            mShader.append(";\n");
240        }
241    }
242}
243
244void RsdShader::logUniform(const Element *field, const float *fd, uint32_t arraySize ) {
245    RsDataType dataType = field->getType();
246    uint32_t elementSize = field->getSizeBytes() / sizeof(float);
247    for (uint32_t i = 0; i < arraySize; i ++) {
248        if (arraySize > 1) {
249            LOGV("Array Element [%u]", i);
250        }
251        if (dataType == RS_TYPE_MATRIX_4X4) {
252            LOGV("Matrix4x4");
253            LOGV("{%f, %f, %f, %f",  fd[0], fd[4], fd[8], fd[12]);
254            LOGV(" %f, %f, %f, %f",  fd[1], fd[5], fd[9], fd[13]);
255            LOGV(" %f, %f, %f, %f",  fd[2], fd[6], fd[10], fd[14]);
256            LOGV(" %f, %f, %f, %f}", fd[3], fd[7], fd[11], fd[15]);
257        } else if (dataType == RS_TYPE_MATRIX_3X3) {
258            LOGV("Matrix3x3");
259            LOGV("{%f, %f, %f",  fd[0], fd[3], fd[6]);
260            LOGV(" %f, %f, %f",  fd[1], fd[4], fd[7]);
261            LOGV(" %f, %f, %f}", fd[2], fd[5], fd[8]);
262        } else if (dataType == RS_TYPE_MATRIX_2X2) {
263            LOGV("Matrix2x2");
264            LOGV("{%f, %f",  fd[0], fd[2]);
265            LOGV(" %f, %f}", fd[1], fd[3]);
266        } else {
267            switch (field->getComponent().getVectorSize()) {
268            case 1:
269                LOGV("Uniform 1 = %f", fd[0]);
270                break;
271            case 2:
272                LOGV("Uniform 2 = %f %f", fd[0], fd[1]);
273                break;
274            case 3:
275                LOGV("Uniform 3 = %f %f %f", fd[0], fd[1], fd[2]);
276                break;
277            case 4:
278                LOGV("Uniform 4 = %f %f %f %f", fd[0], fd[1], fd[2], fd[3]);
279                break;
280            default:
281                rsAssert(0);
282            }
283        }
284        LOGE("Element size %u data=%p", elementSize, fd);
285        fd += elementSize;
286        LOGE("New data=%p", fd);
287    }
288}
289
290void RsdShader::setUniform(const Context *rsc, const Element *field, const float *fd,
291                         int32_t slot, uint32_t arraySize ) {
292    RsDataType dataType = field->getType();
293    if (dataType == RS_TYPE_MATRIX_4X4) {
294        glUniformMatrix4fv(slot, arraySize, GL_FALSE, fd);
295    } else if (dataType == RS_TYPE_MATRIX_3X3) {
296        glUniformMatrix3fv(slot, arraySize, GL_FALSE, fd);
297    } else if (dataType == RS_TYPE_MATRIX_2X2) {
298        glUniformMatrix2fv(slot, arraySize, GL_FALSE, fd);
299    } else {
300        switch (field->getComponent().getVectorSize()) {
301        case 1:
302            glUniform1fv(slot, arraySize, fd);
303            break;
304        case 2:
305            glUniform2fv(slot, arraySize, fd);
306            break;
307        case 3:
308            glUniform3fv(slot, arraySize, fd);
309            break;
310        case 4:
311            glUniform4fv(slot, arraySize, fd);
312            break;
313        default:
314            rsAssert(0);
315        }
316    }
317}
318
319void RsdShader::setupSampler(const Context *rsc, const Sampler *s, const Allocation *tex) {
320    RsdHal *dc = (RsdHal *)rsc->mHal.drv;
321
322    GLenum trans[] = {
323        GL_NEAREST, //RS_SAMPLER_NEAREST,
324        GL_LINEAR, //RS_SAMPLER_LINEAR,
325        GL_LINEAR_MIPMAP_LINEAR, //RS_SAMPLER_LINEAR_MIP_LINEAR,
326        GL_REPEAT, //RS_SAMPLER_WRAP,
327        GL_CLAMP_TO_EDGE, //RS_SAMPLER_CLAMP
328        GL_LINEAR_MIPMAP_NEAREST, //RS_SAMPLER_LINEAR_MIP_NEAREST
329    };
330
331    GLenum transNP[] = {
332        GL_NEAREST, //RS_SAMPLER_NEAREST,
333        GL_LINEAR, //RS_SAMPLER_LINEAR,
334        GL_LINEAR, //RS_SAMPLER_LINEAR_MIP_LINEAR,
335        GL_CLAMP_TO_EDGE, //RS_SAMPLER_WRAP,
336        GL_CLAMP_TO_EDGE, //RS_SAMPLER_CLAMP
337        GL_LINEAR, //RS_SAMPLER_LINEAR_MIP_NEAREST,
338    };
339
340    // This tells us the correct texture type
341    GLenum target = (GLenum)tex->getGLTarget();
342
343    if (!dc->gl.gl.OES_texture_npot && tex->getType()->getIsNp2()) {
344        if (tex->getHasGraphicsMipmaps() &&
345            (dc->gl.gl.GL_NV_texture_npot_2D_mipmap || dc->gl.gl.GL_IMG_texture_npot)) {
346            if (dc->gl.gl.GL_NV_texture_npot_2D_mipmap) {
347                glTexParameteri(target, GL_TEXTURE_MIN_FILTER, trans[s->mHal.state.minFilter]);
348            } else {
349                switch (trans[s->mHal.state.minFilter]) {
350                case GL_LINEAR_MIPMAP_LINEAR:
351                    glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
352                    break;
353                default:
354                    glTexParameteri(target, GL_TEXTURE_MIN_FILTER, trans[s->mHal.state.minFilter]);
355                    break;
356                }
357            }
358        } else {
359            glTexParameteri(target, GL_TEXTURE_MIN_FILTER, transNP[s->mHal.state.minFilter]);
360        }
361        glTexParameteri(target, GL_TEXTURE_MAG_FILTER, transNP[s->mHal.state.magFilter]);
362        glTexParameteri(target, GL_TEXTURE_WRAP_S, transNP[s->mHal.state.wrapS]);
363        glTexParameteri(target, GL_TEXTURE_WRAP_T, transNP[s->mHal.state.wrapT]);
364    } else {
365        if (tex->getHasGraphicsMipmaps()) {
366            glTexParameteri(target, GL_TEXTURE_MIN_FILTER, trans[s->mHal.state.minFilter]);
367        } else {
368            glTexParameteri(target, GL_TEXTURE_MIN_FILTER, transNP[s->mHal.state.minFilter]);
369        }
370        glTexParameteri(target, GL_TEXTURE_MAG_FILTER, trans[s->mHal.state.magFilter]);
371        glTexParameteri(target, GL_TEXTURE_WRAP_S, trans[s->mHal.state.wrapS]);
372        glTexParameteri(target, GL_TEXTURE_WRAP_T, trans[s->mHal.state.wrapT]);
373    }
374
375    float anisoValue = rsMin(dc->gl.gl.EXT_texture_max_aniso, s->mHal.state.aniso);
376    if (dc->gl.gl.EXT_texture_max_aniso > 1.0f) {
377        glTexParameterf(target, GL_TEXTURE_MAX_ANISOTROPY_EXT, anisoValue);
378    }
379
380    rsc->checkError("Sampler::setupGL2 tex env");
381}
382
383void RsdShader::setupTextures(const Context *rsc, RsdShaderCache *sc) {
384    if (mRSProgram->mHal.state.texturesCount == 0) {
385        return;
386    }
387
388    uint32_t numTexturesToBind = mRSProgram->mHal.state.texturesCount;
389    uint32_t numTexturesAvailable = rsc->getMaxFragmentTextures();
390    if (numTexturesToBind >= numTexturesAvailable) {
391        LOGE("Attempting to bind %u textures on shader id %u, but only %u are available",
392             mRSProgram->mHal.state.texturesCount, (uint32_t)this, numTexturesAvailable);
393        rsc->setError(RS_ERROR_BAD_SHADER, "Cannot bind more textuers than available");
394        numTexturesToBind = numTexturesAvailable;
395    }
396
397    for (uint32_t ct=0; ct < numTexturesToBind; ct++) {
398        glActiveTexture(GL_TEXTURE0 + ct);
399        if (!mRSProgram->mHal.state.textures[ct].get()) {
400            LOGE("No texture bound for shader id %u, texture unit %u", (uint)this, ct);
401            rsc->setError(RS_ERROR_BAD_SHADER, "No texture bound");
402            continue;
403        }
404
405        GLenum target = (GLenum)mRSProgram->mHal.state.textures[ct]->getGLTarget();
406        if (target != GL_TEXTURE_2D && target != GL_TEXTURE_CUBE_MAP) {
407            LOGE("Attempting to bind unknown texture to shader id %u, texture unit %u", (uint)this, ct);
408            rsc->setError(RS_ERROR_BAD_SHADER, "Non-texture allocation bound to a shader");
409        }
410        glBindTexture(target, mRSProgram->mHal.state.textures[ct]->getTextureID());
411        rsc->checkError("ProgramFragment::setupGL2 tex bind");
412        if (mRSProgram->mHal.state.samplers[ct].get()) {
413            setupSampler(rsc, mRSProgram->mHal.state.samplers[ct].get(), mRSProgram->mHal.state.textures[ct].get());
414        } else {
415            glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
416            glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
417            glTexParameteri(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
418            glTexParameteri(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
419            rsc->checkError("ProgramFragment::setupGL2 tex env");
420        }
421
422        glUniform1i(sc->fragUniformSlot(mTextureUniformIndexStart + ct), ct);
423        rsc->checkError("ProgramFragment::setupGL2 uniforms");
424    }
425
426    glActiveTexture(GL_TEXTURE0);
427    mDirty = false;
428    rsc->checkError("ProgramFragment::setupGL2");
429}
430
431void RsdShader::setupUserConstants(const Context *rsc, RsdShaderCache *sc, bool isFragment) {
432    uint32_t uidx = 0;
433    for (uint32_t ct=0; ct < mRSProgram->mHal.state.constantsCount; ct++) {
434        Allocation *alloc = mRSProgram->mHal.state.constants[ct].get();
435        if (!alloc) {
436            LOGE("Attempting to set constants on shader id %u, but alloc at slot %u is not set", (uint32_t)this, ct);
437            rsc->setError(RS_ERROR_BAD_SHADER, "No constant allocation bound");
438            continue;
439        }
440
441        const uint8_t *data = static_cast<const uint8_t *>(alloc->getPtr());
442        const Element *e = mRSProgram->mHal.state.constantTypes[ct]->getElement();
443        for (uint32_t field=0; field < e->getFieldCount(); field++) {
444            const Element *f = e->getField(field);
445            const char *fieldName = e->getFieldName(field);
446            // If this field is padding, skip it
447            if (fieldName[0] == '#') {
448                continue;
449            }
450
451            uint32_t offset = e->getFieldOffsetBytes(field);
452            const float *fd = reinterpret_cast<const float *>(&data[offset]);
453
454            int32_t slot = -1;
455            uint32_t arraySize = 1;
456            if (!isFragment) {
457                slot = sc->vtxUniformSlot(uidx);
458                arraySize = sc->vtxUniformSize(uidx);
459            } else {
460                slot = sc->fragUniformSlot(uidx);
461                arraySize = sc->fragUniformSize(uidx);
462            }
463            if (rsc->props.mLogShadersUniforms) {
464                LOGV("Uniform  slot=%i, offset=%i, constant=%i, field=%i, uidx=%i, name=%s", slot, offset, ct, field, uidx, fieldName);
465            }
466            uidx ++;
467            if (slot < 0) {
468                continue;
469            }
470
471            if (rsc->props.mLogShadersUniforms) {
472                logUniform(f, fd, arraySize);
473            }
474            setUniform(rsc, f, fd, slot, arraySize);
475        }
476    }
477}
478
479void RsdShader::setup(const android::renderscript::Context *rsc, RsdShaderCache *sc) {
480
481    setupUserConstants(rsc, sc, mType == GL_FRAGMENT_SHADER);
482    setupTextures(rsc, sc);
483}
484
485void RsdShader::initAttribAndUniformArray() {
486    mAttribCount = 0;
487    for (uint32_t ct=0; ct < mRSProgram->mHal.state.inputElementsCount; ct++) {
488        const Element *elem = mRSProgram->mHal.state.inputElements[ct].get();
489        for (uint32_t field=0; field < elem->getFieldCount(); field++) {
490            if (elem->getFieldName(field)[0] != '#') {
491                mAttribCount ++;
492            }
493        }
494    }
495
496    mUniformCount = 0;
497    for (uint32_t ct=0; ct < mRSProgram->mHal.state.constantsCount; ct++) {
498        const Element *elem = mRSProgram->mHal.state.constantTypes[ct]->getElement();
499
500        for (uint32_t field=0; field < elem->getFieldCount(); field++) {
501            if (elem->getFieldName(field)[0] != '#') {
502                mUniformCount ++;
503            }
504        }
505    }
506    mUniformCount += mRSProgram->mHal.state.texturesCount;
507
508    if (mAttribCount) {
509        mAttribNames = new String8[mAttribCount];
510    }
511    if (mUniformCount) {
512        mUniformNames = new String8[mUniformCount];
513        mUniformArraySizes = new uint32_t[mUniformCount];
514    }
515}
516
517void RsdShader::initAddUserElement(const Element *e, String8 *names, uint32_t *arrayLengths, uint32_t *count, const char *prefix) {
518    rsAssert(e->getFieldCount());
519    for (uint32_t ct=0; ct < e->getFieldCount(); ct++) {
520        const Element *ce = e->getField(ct);
521        if (ce->getFieldCount()) {
522            initAddUserElement(ce, names, arrayLengths, count, prefix);
523        } else if (e->getFieldName(ct)[0] != '#') {
524            String8 tmp(prefix);
525            tmp.append(e->getFieldName(ct));
526            names[*count].setTo(tmp.string());
527            if (arrayLengths) {
528                arrayLengths[*count] = e->getFieldArraySize(ct);
529            }
530            (*count)++;
531        }
532    }
533}
534