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#include "rsContext.h"
18#include "rsProgramFragment.h"
19
20#include <GLES/gl.h>
21#include <GLES/glext.h>
22#include <GLES2/gl2.h>
23#include <GLES2/gl2ext.h>
24
25using namespace android;
26using namespace android::renderscript;
27
28
29ProgramFragment::ProgramFragment(Context *rsc, const uint32_t * params,
30                                 uint32_t paramLength) :
31    Program(rsc)
32{
33    mAllocFile = __FILE__;
34    mAllocLine = __LINE__;
35    rsAssert(paramLength = 5);
36
37    mEnvModes[0] = (RsTexEnvMode)params[0];
38    mTextureFormats[0] = params[1];
39    mEnvModes[1] = (RsTexEnvMode)params[2];
40    mTextureFormats[1] = params[3];
41    mPointSpriteEnable = params[4] != 0;
42
43    mTextureEnableMask = 0;
44    if (mEnvModes[0]) {
45        mTextureEnableMask |= 1;
46    }
47    if (mEnvModes[1]) {
48        mTextureEnableMask |= 2;
49    }
50    init(rsc);
51}
52
53ProgramFragment::ProgramFragment(Context *rsc, const char * shaderText,
54                                 uint32_t shaderLength, const uint32_t * params,
55                                 uint32_t paramLength) :
56    Program(rsc, shaderText, shaderLength, params, paramLength)
57{
58    mAllocFile = __FILE__;
59    mAllocLine = __LINE__;
60
61    init(rsc);
62    mTextureEnableMask = (1 << mTextureCount) -1;
63}
64
65
66ProgramFragment::~ProgramFragment()
67{
68}
69
70void ProgramFragment::setupGL(const Context *rsc, ProgramFragmentState *state)
71{
72    if ((state->mLast.get() == this) && !mDirty) {
73        return;
74    }
75    state->mLast.set(this);
76
77    for (uint32_t ct=0; ct < MAX_TEXTURE; ct++) {
78        glActiveTexture(GL_TEXTURE0 + ct);
79        if (!(mTextureEnableMask & (1 << ct)) || !mTextures[ct].get()) {
80            glDisable(GL_TEXTURE_2D);
81            continue;
82        }
83
84        glEnable(GL_TEXTURE_2D);
85        if (rsc->checkVersion1_1()) {
86            if (mPointSpriteEnable) {
87                glEnable(GL_POINT_SPRITE_OES);
88            } else {
89                glDisable(GL_POINT_SPRITE_OES);
90            }
91            glTexEnvi(GL_POINT_SPRITE_OES, GL_COORD_REPLACE_OES, mPointSpriteEnable);
92        }
93        mTextures[ct]->uploadCheck(rsc);
94        glBindTexture(GL_TEXTURE_2D, mTextures[ct]->getTextureID());
95
96        switch(mEnvModes[ct]) {
97        case RS_TEX_ENV_MODE_NONE:
98            rsAssert(0);
99            break;
100        case RS_TEX_ENV_MODE_REPLACE:
101            glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
102            break;
103        case RS_TEX_ENV_MODE_MODULATE:
104            glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
105            break;
106        case RS_TEX_ENV_MODE_DECAL:
107            glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);
108            break;
109        }
110
111        if (mSamplers[ct].get()) {
112            mSamplers[ct]->setupGL(rsc, mTextures[ct]->getType()->getIsNp2());
113        } else {
114            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
115            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
116            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
117            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
118        }
119
120        // Gross hack.
121        if (ct == 2) {
122            glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
123
124            glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_ADD);
125            glTexEnvi(GL_TEXTURE_ENV, GL_SRC0_RGB, GL_PREVIOUS);
126            glTexEnvi(GL_TEXTURE_ENV, GL_SRC1_RGB, GL_TEXTURE);
127            glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR);
128            glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR);
129
130            glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_ADD);
131            glTexEnvi(GL_TEXTURE_ENV, GL_SRC0_ALPHA, GL_PREVIOUS);
132            glTexEnvi(GL_TEXTURE_ENV, GL_SRC1_ALPHA, GL_TEXTURE);
133            glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);
134            glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_ALPHA, GL_SRC_ALPHA);
135        }
136    }
137    glActiveTexture(GL_TEXTURE0);
138    mDirty = false;
139    rsc->checkError("ProgramFragment::setupGL");
140}
141
142void ProgramFragment::setupGL2(const Context *rsc, ProgramFragmentState *state, ShaderCache *sc)
143{
144
145    //LOGE("sgl2 frag1 %x", glGetError());
146    if ((state->mLast.get() == this) && !mDirty) {
147        //return;
148    }
149    state->mLast.set(this);
150
151    rsc->checkError("ProgramFragment::setupGL2 start");
152    for (uint32_t ct=0; ct < MAX_TEXTURE; ct++) {
153        glActiveTexture(GL_TEXTURE0 + ct);
154        if (!(mTextureEnableMask & (1 << ct)) || !mTextures[ct].get()) {
155            continue;
156        }
157
158        mTextures[ct]->uploadCheck(rsc);
159        glBindTexture(GL_TEXTURE_2D, mTextures[ct]->getTextureID());
160        rsc->checkError("ProgramFragment::setupGL2 tex bind");
161        if (mSamplers[ct].get()) {
162            mSamplers[ct]->setupGL(rsc, mTextures[ct]->getType()->getIsNp2());
163        } else {
164            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
165            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
166            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
167            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
168            rsc->checkError("ProgramFragment::setupGL2 tex env");
169        }
170
171        glUniform1i(sc->fragUniformSlot(ct), ct);
172        rsc->checkError("ProgramFragment::setupGL2 uniforms");
173    }
174
175    glActiveTexture(GL_TEXTURE0);
176    mDirty = false;
177    rsc->checkError("ProgramFragment::setupGL2");
178}
179
180void ProgramFragment::loadShader(Context *rsc) {
181    Program::loadShader(rsc, GL_FRAGMENT_SHADER);
182}
183
184void ProgramFragment::createShader()
185{
186    mShader.setTo("precision mediump float;\n");
187    mShader.append("varying vec4 varColor;\n");
188    mShader.append("varying vec4 varTex0;\n");
189
190    if (mUserShader.length() > 1) {
191        for (uint32_t ct=0; ct < mTextureCount; ct++) {
192            char buf[256];
193            sprintf(buf, "uniform sampler2D uni_Tex%i;\n", ct);
194            mShader.append(buf);
195        }
196
197        mShader.append(mUserShader);
198    } else {
199        uint32_t mask = mTextureEnableMask;
200        uint32_t texNum = 0;
201        while (mask) {
202            if (mask & 1) {
203                char buf[64];
204                mShader.append("uniform sampler2D uni_Tex");
205                sprintf(buf, "%i", texNum);
206                mShader.append(buf);
207                mShader.append(";\n");
208            }
209            mask >>= 1;
210            texNum++;
211        }
212
213
214        mShader.append("void main() {\n");
215        mShader.append("  vec4 col = varColor;\n");
216
217        if (mTextureEnableMask) {
218            if (mPointSpriteEnable) {
219                mShader.append("  vec2 t0 = gl_PointCoord;\n");
220            } else {
221                mShader.append("  vec2 t0 = varTex0.xy;\n");
222            }
223        }
224
225        mask = mTextureEnableMask;
226        texNum = 0;
227        while (mask) {
228            if (mask & 1) {
229                switch(mEnvModes[texNum]) {
230                case RS_TEX_ENV_MODE_NONE:
231                    rsAssert(0);
232                    break;
233                case RS_TEX_ENV_MODE_REPLACE:
234                    switch(mTextureFormats[texNum]) {
235                    case 1:
236                        mShader.append("  col.a = texture2D(uni_Tex0, t0).a;\n");
237                        break;
238                    case 2:
239                        mShader.append("  col.rgba = texture2D(uni_Tex0, t0).rgba;\n");
240                        break;
241                    case 3:
242                        mShader.append("  col.rgb = texture2D(uni_Tex0, t0).rgb;\n");
243                        break;
244                    case 4:
245                        mShader.append("  col.rgba = texture2D(uni_Tex0, t0).rgba;\n");
246                        break;
247                    }
248                    break;
249                case RS_TEX_ENV_MODE_MODULATE:
250                    switch(mTextureFormats[texNum]) {
251                    case 1:
252                        mShader.append("  col.a *= texture2D(uni_Tex0, t0).a;\n");
253                        break;
254                    case 2:
255                        mShader.append("  col.rgba *= texture2D(uni_Tex0, t0).rgba;\n");
256                        break;
257                    case 3:
258                        mShader.append("  col.rgb *= texture2D(uni_Tex0, t0).rgb;\n");
259                        break;
260                    case 4:
261                        mShader.append("  col.rgba *= texture2D(uni_Tex0, t0).rgba;\n");
262                        break;
263                    }
264                    break;
265                case RS_TEX_ENV_MODE_DECAL:
266                    mShader.append("  col = texture2D(uni_Tex0, t0);\n");
267                    break;
268                }
269
270            }
271            mask >>= 1;
272            texNum++;
273        }
274
275        //mShader.append("  col.a = 1.0;\n");
276        //mShader.append("  col.r = 0.5;\n");
277
278        mShader.append("  gl_FragColor = col;\n");
279        mShader.append("}\n");
280    }
281}
282
283void ProgramFragment::init(Context *rsc)
284{
285    mUniformCount = 2;
286    mUniformNames[0].setTo("uni_Tex0");
287    mUniformNames[1].setTo("uni_Tex1");
288
289    createShader();
290}
291
292ProgramFragmentState::ProgramFragmentState()
293{
294    mPF = NULL;
295}
296
297ProgramFragmentState::~ProgramFragmentState()
298{
299    delete mPF;
300
301}
302
303void ProgramFragmentState::init(Context *rsc, int32_t w, int32_t h)
304{
305    uint32_t tmp[5] = {
306        RS_TEX_ENV_MODE_NONE, 0,
307        RS_TEX_ENV_MODE_NONE, 0,
308        0
309    };
310    ProgramFragment *pf = new ProgramFragment(rsc, tmp, 5);
311    mDefault.set(pf);
312    pf->init(rsc);
313}
314
315void ProgramFragmentState::deinit(Context *rsc)
316{
317    mDefault.clear();
318    mLast.clear();
319}
320
321
322namespace android {
323namespace renderscript {
324
325RsProgramFragment rsi_ProgramFragmentCreate(Context *rsc,
326                                            const uint32_t * params,
327                                            uint32_t paramLength)
328{
329    ProgramFragment *pf = new ProgramFragment(rsc, params, paramLength);
330    pf->incUserRef();
331    return pf;
332}
333
334RsProgramFragment rsi_ProgramFragmentCreate2(Context *rsc, const char * shaderText,
335                             uint32_t shaderLength, const uint32_t * params,
336                             uint32_t paramLength)
337{
338    ProgramFragment *pf = new ProgramFragment(rsc, shaderText, shaderLength, params, paramLength);
339    pf->incUserRef();
340    return pf;
341}
342
343}
344}
345
346