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 
17 package android.renderscript;
18 
19 
20 import java.io.IOException;
21 import java.io.InputStream;
22 import java.io.UnsupportedEncodingException;
23 
24 import android.content.res.Resources;
25 import 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  **/
35 public 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;
TextureType(int id)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;
ProgramParam(int id)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 
Program(long id, RenderScript rs)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      */
getConstantCount()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      */
getConstant(int slot)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      */
getTextureCount()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      */
getTextureType(int slot)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      */
getTextureName(int slot)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      */
bindConstants(Allocation a, int slot)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      */
bindTexture(Allocation va, int slot)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      */
bindSampler(Sampler vs, int slot)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 
BaseProgramBuilder(RenderScript rs)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          */
setShader(String s)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          */
setShader(Resources resources, int resourceID)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          */
getCurrentConstantIndex()290         public int getCurrentConstantIndex() {
291             return mConstantCount - 1;
292         }
293 
294         /**
295          * Queries the index of the last added texture type
296          *
297          */
getCurrentTextureIndex()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          */
addConstant(Type t)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          */
addTexture(TextureType texType)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          */
addTexture(TextureType texType, String texName)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 
initProgram(Program p)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