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