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