• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2023 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 package com.android.internal.widget.remotecompose.core.operations;
17 
18 import static com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation.BYTE;
19 import static com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation.FLOAT_ARRAY;
20 import static com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation.INT;
21 import static com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation.INT_ARRAY;
22 import static com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation.SHORT;
23 import static com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation.UTF8;
24 
25 import android.annotation.NonNull;
26 import android.annotation.Nullable;
27 
28 import com.android.internal.widget.remotecompose.core.Operation;
29 import com.android.internal.widget.remotecompose.core.Operations;
30 import com.android.internal.widget.remotecompose.core.RemoteContext;
31 import com.android.internal.widget.remotecompose.core.VariableSupport;
32 import com.android.internal.widget.remotecompose.core.WireBuffer;
33 import com.android.internal.widget.remotecompose.core.documentation.DocumentationBuilder;
34 import com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation;
35 import com.android.internal.widget.remotecompose.core.serialize.MapSerializer;
36 import com.android.internal.widget.remotecompose.core.serialize.Serializable;
37 
38 import java.util.Arrays;
39 import java.util.HashMap;
40 import java.util.List;
41 
42 /**
43  * Operation to deal with bitmap data On getting an Image during a draw call the bitmap is
44  * compressed and saved in playback the image is decompressed
45  */
46 public class ShaderData extends Operation implements VariableSupport, Serializable {
47     private static final int OP_CODE = Operations.DATA_SHADER;
48     private static final String CLASS_NAME = "ShaderData";
49     int mShaderTextId; // the actual text of a shader
50     int mShaderID; // allows shaders to be referenced by number
51     @Nullable HashMap<String, float[]> mUniformRawFloatMap = null;
52     @Nullable HashMap<String, float[]> mUniformFloatMap = null;
53     @Nullable HashMap<String, int[]> mUniformIntMap;
54     @Nullable HashMap<String, Integer> mUniformBitmapMap = null;
55     private boolean mShaderValid = false;
56 
ShaderData( int shaderID, int shaderTextId, @Nullable HashMap<String, float[]> floatMap, @Nullable HashMap<String, int[]> intMap, @Nullable HashMap<String, Integer> bitmapMap)57     public ShaderData(
58             int shaderID,
59             int shaderTextId,
60             @Nullable HashMap<String, float[]> floatMap,
61             @Nullable HashMap<String, int[]> intMap,
62             @Nullable HashMap<String, Integer> bitmapMap) {
63         mShaderID = shaderID;
64         mShaderTextId = shaderTextId;
65         if (floatMap != null) {
66             mUniformFloatMap = new HashMap<>();
67             mUniformRawFloatMap = new HashMap<>();
68 
69             for (String name : floatMap.keySet()) {
70                 mUniformRawFloatMap.put(name, floatMap.get(name));
71                 mUniformFloatMap.put(name, floatMap.get(name));
72             }
73         }
74 
75         if (intMap != null) {
76             mUniformIntMap = new HashMap<>();
77             for (String name : intMap.keySet()) {
78                 mUniformIntMap.put(name, intMap.get(name));
79             }
80         }
81         if (bitmapMap != null) {
82             mUniformBitmapMap = new HashMap<>();
83             for (String name : bitmapMap.keySet()) {
84                 mUniformBitmapMap.put(name, bitmapMap.get(name));
85             }
86         }
87     }
88 
getShaderTextId()89     public int getShaderTextId() {
90         return mShaderTextId;
91     }
92 
93     /**
94      * get names of all known floats
95      *
96      * @return Names of all uniform floats or empty array
97      */
98     @NonNull
getUniformFloatNames()99     public String[] getUniformFloatNames() {
100         if (mUniformFloatMap == null) return new String[0];
101         return mUniformFloatMap.keySet().toArray(new String[0]);
102     }
103 
104     /**
105      * Get float values associated with the name
106      *
107      * @param name name of uniform
108      * @return value of uniform
109      */
getUniformFloats(@onNull String name)110     public @NonNull float[] getUniformFloats(@NonNull String name) {
111         return mUniformFloatMap != null ? mUniformFloatMap.get(name) : new float[0];
112     }
113 
114     /**
115      * get the name of all know uniform integers
116      *
117      * @return Name of all integer uniforms
118      */
119     @NonNull
getUniformIntegerNames()120     public String[] getUniformIntegerNames() {
121         if (mUniformIntMap == null) return new String[0];
122         return mUniformIntMap.keySet().toArray(new String[0]);
123     }
124 
125     /**
126      * Get Int value associated with the name
127      *
128      * @param name Name of uniform
129      * @return value of uniform
130      */
getUniformInts(@onNull String name)131     public @NonNull int[] getUniformInts(@NonNull String name) {
132         return mUniformIntMap != null ? mUniformIntMap.get(name) : new int[0];
133     }
134 
135     /**
136      * get list of uniform Bitmaps
137      *
138      * @return Name of all bitmap uniforms
139      */
140     @NonNull
getUniformBitmapNames()141     public String[] getUniformBitmapNames() {
142         if (mUniformBitmapMap == null) return new String[0];
143         return mUniformBitmapMap.keySet().toArray(new String[0]);
144     }
145 
146     /**
147      * Get a bitmap stored under that name
148      *
149      * @param name Name of bitmap uniform
150      * @return Bitmap ID
151      */
getUniformBitmapId(@onNull String name)152     public int getUniformBitmapId(@NonNull String name) {
153         return mUniformBitmapMap != null
154                 ? mUniformBitmapMap.get(name)
155                 : -1; // TODO: what is the proper return value here? -- bbade@
156     }
157 
158     @Override
write(@onNull WireBuffer buffer)159     public void write(@NonNull WireBuffer buffer) {
160         apply(
161                 buffer,
162                 mShaderID,
163                 mShaderTextId,
164                 mUniformFloatMap,
165                 mUniformIntMap,
166                 mUniformBitmapMap);
167     }
168 
169     @NonNull
170     @Override
toString()171     public String toString() {
172         return "SHADER DATA " + mShaderID;
173     }
174 
175     @Override
updateVariables(@onNull RemoteContext context)176     public void updateVariables(@NonNull RemoteContext context) {
177         if (mUniformRawFloatMap == null) {
178             return;
179         }
180         for (String name : mUniformRawFloatMap.keySet()) { // TODO: potential npe
181             float[] value = mUniformRawFloatMap.get(name);
182             float[] out = null;
183             for (int i = 0; i < value.length; i++) {
184                 if (Float.isNaN(value[i])) {
185                     if (out == null) { // need to copy
186                         out = Arrays.copyOf(value, value.length);
187                     }
188                     out[i] = context.getFloat(Utils.idFromNan(value[i]));
189                 }
190             }
191             mUniformFloatMap.put(name, out == null ? value : out);
192         }
193     }
194 
195     @Override
registerListening(@onNull RemoteContext context)196     public void registerListening(@NonNull RemoteContext context) {
197         if (mUniformFloatMap == null) {
198             return;
199         }
200         for (String name : mUniformRawFloatMap.keySet()) { // TODO: potential npe
201             float[] value = mUniformRawFloatMap.get(name);
202             for (float v : value) {
203                 if (Float.isNaN(v)) {
204                     context.listensTo(Utils.idFromNan(v), this);
205                 }
206             }
207         }
208     }
209 
210     /**
211      * The name of the class
212      *
213      * @return the name
214      */
215     @NonNull
name()216     public static String name() {
217         return CLASS_NAME;
218     }
219 
220     /**
221      * The OP_CODE for this command
222      *
223      * @return the opcode
224      */
id()225     public static int id() {
226         return OP_CODE;
227     }
228 
229     /**
230      * Writes out the operation to the buffer
231      *
232      * @param buffer buffer to write into
233      * @param shaderID id of shader
234      * @param shaderTextId id of text of shader
235      * @param floatMap the map of float uniforms
236      * @param intMap the map of int uniforms
237      * @param bitmapMap the map of bitmap uniforms
238      */
apply( @onNull WireBuffer buffer, int shaderID, int shaderTextId, @Nullable HashMap<String, float[]> floatMap, @Nullable HashMap<String, int[]> intMap, @Nullable HashMap<String, Integer> bitmapMap)239     public static void apply(
240             @NonNull WireBuffer buffer,
241             int shaderID,
242             int shaderTextId,
243             @Nullable HashMap<String, float[]> floatMap,
244             @Nullable HashMap<String, int[]> intMap,
245             @Nullable HashMap<String, Integer> bitmapMap) {
246         buffer.start(OP_CODE);
247         buffer.writeInt(shaderID);
248 
249         buffer.writeInt(shaderTextId);
250         int floatSize = (floatMap == null) ? 0 : floatMap.size();
251         int intSize = (intMap == null) ? 0 : intMap.size();
252         int bitmapSize = (bitmapMap == null) ? 0 : bitmapMap.size();
253         int sizes = floatSize | (intSize << 8) | (bitmapSize << 16);
254         buffer.writeInt(sizes);
255 
256         if (floatSize > 0) {
257 
258             for (String name : floatMap.keySet()) {
259                 buffer.writeUTF8(name);
260                 float[] values = floatMap.get(name);
261                 buffer.writeInt(values.length);
262 
263                 for (float value : values) {
264                     buffer.writeFloat(value);
265                 }
266             }
267         }
268 
269         if (intSize > 0) {
270             for (String name : intMap.keySet()) {
271                 buffer.writeUTF8(name);
272                 int[] values = intMap.get(name);
273                 buffer.writeInt(values.length);
274                 for (int value : values) {
275                     buffer.writeInt(value);
276                 }
277             }
278         }
279         if (bitmapSize > 0) {
280             for (String name : bitmapMap.keySet()) {
281                 buffer.writeUTF8(name);
282                 int value = bitmapMap.get(name);
283                 buffer.writeInt(value);
284             }
285         }
286     }
287 
288     /**
289      * Read this operation and add it to the list of operations
290      *
291      * @param buffer the buffer to read
292      * @param operations the list of operations that will be added to
293      */
read(@onNull WireBuffer buffer, @NonNull List<Operation> operations)294     public static void read(@NonNull WireBuffer buffer, @NonNull List<Operation> operations) {
295         int shaderID = buffer.readInt();
296         int shaderTextId = buffer.readInt();
297         HashMap<String, float[]> floatMap = null;
298         HashMap<String, int[]> intMap = null;
299         HashMap<String, Integer> bitmapMap = null;
300 
301         int sizes = buffer.readInt();
302 
303         int floatMapSize = sizes & 0xFF;
304         if (floatMapSize > 0) {
305             floatMap = new HashMap<>();
306             for (int i = 0; i < floatMapSize; i++) {
307                 String name = buffer.readUTF8();
308                 int len = buffer.readInt();
309                 float[] val = new float[len];
310 
311                 for (int j = 0; j < len; j++) {
312                     val[j] = buffer.readFloat();
313                 }
314 
315                 floatMap.put(name, val);
316             }
317         }
318         int intMapSize = (sizes >> 8) & 0xFF;
319 
320         if (intMapSize > 0) {
321 
322             intMap = new HashMap<>();
323             for (int i = 0; i < intMapSize; i++) {
324                 String name = buffer.readUTF8();
325                 int len = buffer.readInt();
326                 int[] val = new int[len];
327                 for (int j = 0; j < len; j++) {
328                     val[j] = buffer.readInt();
329                 }
330                 intMap.put(name, val);
331             }
332         }
333         int bitmapMapSize = (sizes >> 16) & 0xFF;
334 
335         if (bitmapMapSize > 0) {
336             bitmapMap = new HashMap<>();
337             for (int i = 0; i < bitmapMapSize; i++) {
338                 String name = buffer.readUTF8();
339                 int val = buffer.readInt();
340                 bitmapMap.put(name, val);
341             }
342         }
343         operations.add(new ShaderData(shaderID, shaderTextId, floatMap, intMap, bitmapMap));
344     }
345 
346     /**
347      * Populate the documentation with a description of this operation
348      *
349      * @param doc to append the description to.
350      */
documentation(@onNull DocumentationBuilder doc)351     public static void documentation(@NonNull DocumentationBuilder doc) {
352         doc.operation("Data Operations", OP_CODE, CLASS_NAME)
353                 .description("Shader")
354                 .field(DocumentedOperation.INT, "shaderID", "id of shader")
355                 .field(BYTE, " floatSize", "number of float uniforms")
356                 .field(BYTE, " intSize", "number of int uniform")
357                 .field(SHORT, " intSize", "number of int uniform")
358                 .field(UTF8, "floatName", "name of float uniform")
359                 .field(INT, "length", "length")
360                 .field(FLOAT_ARRAY, "VALUE", "float uniform (max 4)")
361                 .field(UTF8, "IntName", "id of shader text")
362                 .field(INT, "length", "length of uniform")
363                 .field(INT_ARRAY, "VALUE", "int uniform (max 4)")
364                 .field(UTF8, "bitmapName", "name of bitmap")
365                 .field(INT, "VALUE", "id of bitmap");
366     }
367 
368     @Override
apply(@onNull RemoteContext context)369     public void apply(@NonNull RemoteContext context) {
370         if (mShaderValid) {
371             context.loadShader(mShaderID, this);
372         }
373     }
374 
375     @NonNull
376     @Override
deepToString(@onNull String indent)377     public String deepToString(@NonNull String indent) {
378         return indent + toString();
379     }
380 
381     /**
382      * Enable or disable the shader
383      *
384      * @param shaderValid if true shader can be used
385      */
enable(boolean shaderValid)386     public void enable(boolean shaderValid) {
387         mShaderValid = shaderValid;
388     }
389 
390     @Override
serialize(MapSerializer serializer)391     public void serialize(MapSerializer serializer) {
392         serializer
393                 .addType(CLASS_NAME)
394                 .add("shaderTextId", mShaderTextId)
395                 .add("shaderID", mShaderID)
396                 .add("uniformRawFloatMap", mUniformRawFloatMap)
397                 .add("uniformFloatMap", mUniformFloatMap)
398                 .add("uniformBitmapMap", mUniformBitmapMap);
399     }
400 }
401