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