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