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