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