1/*
2 * Copyright (C) 2008 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
17package android.renderscript;
18
19
20import java.io.IOException;
21import java.io.InputStream;
22import java.io.UnsupportedEncodingException;
23
24import android.content.res.Resources;
25import android.util.Log;
26
27
28/**
29 *
30 * Program is a base class for all the objects that modify
31 * various stages of the graphics pipeline
32 *
33 **/
34public class Program extends BaseObj {
35    static final int MAX_INPUT = 8;
36    static final int MAX_OUTPUT = 8;
37    static final int MAX_CONSTANT = 8;
38    static final int MAX_TEXTURE = 8;
39
40    /**
41     *
42     * TextureType specifies what textures are attached to Program
43     * objects
44     *
45     **/
46    public enum TextureType {
47        TEXTURE_2D (0),
48        TEXTURE_CUBE (1);
49
50        int mID;
51        TextureType(int id) {
52            mID = id;
53        }
54    }
55
56    enum ProgramParam {
57        INPUT (0),
58        OUTPUT (1),
59        CONSTANT (2),
60        TEXTURE_TYPE (3);
61
62        int mID;
63        ProgramParam(int id) {
64            mID = id;
65        }
66    };
67
68    Element mInputs[];
69    Element mOutputs[];
70    Type mConstants[];
71    TextureType mTextures[];
72    String mTextureNames[];
73    int mTextureCount;
74    String mShader;
75
76    Program(int id, RenderScript rs) {
77        super(id, rs);
78    }
79
80    /**
81     * Program object can have zero or more constant allocations
82     * associated with it. This method returns the total count.
83     * @return number of constant input types
84     */
85    public int getConstantCount() {
86        return mConstants != null ? mConstants.length : 0;
87    }
88
89    /**
90     * Returns the type of the constant buffer used in the program
91     * object. It could be used to query internal elements or create
92     * an allocation to store constant data.
93     * @param slot index of the constant input type to return
94     * @return constant input type
95     */
96    public Type getConstant(int slot) {
97        if (slot < 0 || slot >= mConstants.length) {
98            throw new IllegalArgumentException("Slot ID out of range.");
99        }
100        return mConstants[slot];
101    }
102
103    /**
104     * Returns the number of textures used in this program object
105     * @return number of texture inputs
106     */
107    public int getTextureCount() {
108        return mTextureCount;
109    }
110
111    /**
112     * Returns the type of texture at a given slot. e.g. 2D or Cube
113     * @param slot index of the texture input
114     * @return texture input type
115     */
116    public TextureType getTextureType(int slot) {
117        if ((slot < 0) || (slot >= mTextureCount)) {
118            throw new IllegalArgumentException("Slot ID out of range.");
119        }
120        return mTextures[slot];
121    }
122
123    /**
124     * Returns the name of the texture input at a given slot. e.g.
125     * tex0, diffuse, spec
126     * @param slot index of the texture input
127     * @return texture input name
128     */
129    public String getTextureName(int slot) {
130        if ((slot < 0) || (slot >= mTextureCount)) {
131            throw new IllegalArgumentException("Slot ID out of range.");
132        }
133        return mTextureNames[slot];
134    }
135
136    /**
137     * Binds a constant buffer to be used as uniform inputs to the
138     * program
139     *
140     * @param a allocation containing uniform data
141     * @param slot index within the program's list of constant
142     *             buffer allocations
143     */
144    public void bindConstants(Allocation a, int slot) {
145        if (slot < 0 || slot >= mConstants.length) {
146            throw new IllegalArgumentException("Slot ID out of range.");
147        }
148        if (a != null &&
149            a.getType().getID(mRS) != mConstants[slot].getID(mRS)) {
150            throw new IllegalArgumentException("Allocation type does not match slot type.");
151        }
152        int id = a != null ? a.getID(mRS) : 0;
153        mRS.nProgramBindConstants(getID(mRS), slot, id);
154    }
155
156    /**
157     * Binds a texture to be used in the program
158     *
159     * @param va allocation containing texture data
160     * @param slot index within the program's list of textures
161     *
162     */
163    public void bindTexture(Allocation va, int slot)
164        throws IllegalArgumentException {
165        mRS.validate();
166        if ((slot < 0) || (slot >= mTextureCount)) {
167            throw new IllegalArgumentException("Slot ID out of range.");
168        }
169        if (va != null && va.getType().hasFaces() &&
170            mTextures[slot] != TextureType.TEXTURE_CUBE) {
171            throw new IllegalArgumentException("Cannot bind cubemap to 2d texture slot");
172        }
173
174        int id = va != null ? va.getID(mRS) : 0;
175        mRS.nProgramBindTexture(getID(mRS), slot, id);
176    }
177
178    /**
179     * Binds an object that describes how a texture at the
180     * corresponding location is sampled
181     *
182     * @param vs sampler for a corresponding texture
183     * @param slot index within the program's list of textures to
184     *             use the sampler on
185     *
186     */
187    public void bindSampler(Sampler vs, int slot)
188        throws IllegalArgumentException {
189        mRS.validate();
190        if ((slot < 0) || (slot >= mTextureCount)) {
191            throw new IllegalArgumentException("Slot ID out of range.");
192        }
193
194        int id = vs != null ? vs.getID(mRS) : 0;
195        mRS.nProgramBindSampler(getID(mRS), slot, id);
196    }
197
198
199    public static class BaseProgramBuilder {
200        RenderScript mRS;
201        Element mInputs[];
202        Element mOutputs[];
203        Type mConstants[];
204        Type mTextures[];
205        TextureType mTextureTypes[];
206        String mTextureNames[];
207        int mInputCount;
208        int mOutputCount;
209        int mConstantCount;
210        int mTextureCount;
211        String mShader;
212
213
214        protected BaseProgramBuilder(RenderScript rs) {
215            mRS = rs;
216            mInputs = new Element[MAX_INPUT];
217            mOutputs = new Element[MAX_OUTPUT];
218            mConstants = new Type[MAX_CONSTANT];
219            mInputCount = 0;
220            mOutputCount = 0;
221            mConstantCount = 0;
222            mTextureCount = 0;
223            mTextureTypes = new TextureType[MAX_TEXTURE];
224            mTextureNames = new String[MAX_TEXTURE];
225        }
226
227        /**
228         * Sets the GLSL shader code to be used in the program
229         *
230         * @param s GLSL shader string
231         * @return  self
232         */
233        public BaseProgramBuilder setShader(String s) {
234            mShader = s;
235            return this;
236        }
237
238        /**
239         * Sets the GLSL shader code to be used in the program
240         *
241         * @param resources application resources
242         * @param resourceID id of the file containing GLSL shader code
243         *
244         * @return  self
245         */
246        public BaseProgramBuilder setShader(Resources resources, int resourceID) {
247            byte[] str;
248            int strLength;
249            InputStream is = resources.openRawResource(resourceID);
250            try {
251                try {
252                    str = new byte[1024];
253                    strLength = 0;
254                    while(true) {
255                        int bytesLeft = str.length - strLength;
256                        if (bytesLeft == 0) {
257                            byte[] buf2 = new byte[str.length * 2];
258                            System.arraycopy(str, 0, buf2, 0, str.length);
259                            str = buf2;
260                            bytesLeft = str.length - strLength;
261                        }
262                        int bytesRead = is.read(str, strLength, bytesLeft);
263                        if (bytesRead <= 0) {
264                            break;
265                        }
266                        strLength += bytesRead;
267                    }
268                } finally {
269                    is.close();
270                }
271            } catch(IOException e) {
272                throw new Resources.NotFoundException();
273            }
274
275            try {
276                mShader = new String(str, 0, strLength, "UTF-8");
277            } catch (UnsupportedEncodingException e) {
278                Log.e("Renderscript shader creation", "Could not decode shader string");
279            }
280
281            return this;
282        }
283
284        /**
285         * Queries the index of the last added constant buffer type
286         *
287         */
288        public int getCurrentConstantIndex() {
289            return mConstantCount - 1;
290        }
291
292        /**
293         * Queries the index of the last added texture type
294         *
295         */
296        public int getCurrentTextureIndex() {
297            return mTextureCount - 1;
298        }
299
300        /**
301         * Adds constant (uniform) inputs to the program
302         *
303         * @param t Type that describes the layout of the Allocation
304         *          object to be used as constant inputs to the Program
305         * @return  self
306         */
307        public BaseProgramBuilder addConstant(Type t) throws IllegalStateException {
308            // Should check for consistant and non-conflicting names...
309            if(mConstantCount >= MAX_CONSTANT) {
310                throw new RSIllegalArgumentException("Max input count exceeded.");
311            }
312            if (t.getElement().isComplex()) {
313                throw new RSIllegalArgumentException("Complex elements not allowed.");
314            }
315            mConstants[mConstantCount] = t;
316            mConstantCount++;
317            return this;
318        }
319
320        /**
321         * Adds a texture input to the Program
322         *
323         * @param texType describes that the texture to append it (2D,
324         *                Cubemap, etc.)
325         * @return  self
326         */
327        public BaseProgramBuilder addTexture(TextureType texType) throws IllegalArgumentException {
328            addTexture(texType, "Tex" + mTextureCount);
329            return this;
330        }
331
332        /**
333         * Adds a texture input to the Program
334         *
335         * @param texType describes that the texture to append it (2D,
336         *                Cubemap, etc.)
337         * @param texName what the texture should be called in the
338         *                shader
339         * @return  self
340         */
341        public BaseProgramBuilder addTexture(TextureType texType, String texName)
342            throws IllegalArgumentException {
343            if(mTextureCount >= MAX_TEXTURE) {
344                throw new IllegalArgumentException("Max texture count exceeded.");
345            }
346            mTextureTypes[mTextureCount] = texType;
347            mTextureNames[mTextureCount] = texName;
348            mTextureCount ++;
349            return this;
350        }
351
352        protected void initProgram(Program p) {
353            p.mInputs = new Element[mInputCount];
354            System.arraycopy(mInputs, 0, p.mInputs, 0, mInputCount);
355            p.mOutputs = new Element[mOutputCount];
356            System.arraycopy(mOutputs, 0, p.mOutputs, 0, mOutputCount);
357            p.mConstants = new Type[mConstantCount];
358            System.arraycopy(mConstants, 0, p.mConstants, 0, mConstantCount);
359            p.mTextureCount = mTextureCount;
360            p.mTextures = new TextureType[mTextureCount];
361            System.arraycopy(mTextureTypes, 0, p.mTextures, 0, mTextureCount);
362            p.mTextureNames = new String[mTextureCount];
363            System.arraycopy(mTextureNames, 0, p.mTextureNames, 0, mTextureCount);
364        }
365    }
366
367}
368
369
370