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 com.android.internal.widget.remotecompose.core.CompanionOperation; 19 import com.android.internal.widget.remotecompose.core.Operation; 20 import com.android.internal.widget.remotecompose.core.Operations; 21 import com.android.internal.widget.remotecompose.core.RemoteContext; 22 import com.android.internal.widget.remotecompose.core.VariableSupport; 23 import com.android.internal.widget.remotecompose.core.WireBuffer; 24 25 import java.util.Arrays; 26 import java.util.HashMap; 27 import java.util.List; 28 29 /** 30 * Operation to deal with bitmap data 31 * On getting an Image during a draw call the bitmap is compressed and saved 32 * in playback the image is decompressed 33 */ 34 public class ShaderData implements Operation, VariableSupport { 35 int mShaderTextId; // the actual text of a shader 36 int mShaderID; // allows shaders to be referenced by number 37 HashMap<String, float[]> mUniformRawFloatMap = null; 38 HashMap<String, float[]> mUniformFloatMap = null; 39 HashMap<String, int[]> mUniformIntMap = null; 40 HashMap<String, Integer> mUniformBitmapMap = null; 41 42 public static final int MAX_IMAGE_DIMENSION = 8000; 43 44 public static final Companion COMPANION = new Companion(); 45 ShaderData(int shaderID, int shaderTextId, HashMap<String, float[]> floatMap, HashMap<String, int[]> intMap, HashMap<String, Integer> bitmapMap)46 public ShaderData(int shaderID, 47 int shaderTextId, 48 HashMap<String, float[]> floatMap, 49 HashMap<String, int[]> intMap, 50 HashMap<String, Integer> bitmapMap) { 51 mShaderID = shaderID; 52 mShaderTextId = shaderTextId; 53 if (floatMap != null) { 54 mUniformFloatMap = new HashMap<>(); 55 mUniformRawFloatMap = new HashMap<>(); 56 57 for (String name : floatMap.keySet()) { 58 mUniformRawFloatMap.put(name, floatMap.get(name)); 59 mUniformFloatMap.put(name, floatMap.get(name)); 60 } 61 } 62 63 if (intMap != null) { 64 mUniformIntMap = new HashMap<>(); 65 for (String name : intMap.keySet()) { 66 mUniformIntMap.put(name, intMap.get(name)); 67 } 68 } 69 if (bitmapMap != null) { 70 mUniformBitmapMap = new HashMap<>(); 71 for (String name : bitmapMap.keySet()) { 72 mUniformBitmapMap.put(name, bitmapMap.get(name)); 73 } 74 } 75 76 } 77 getShaderTextId()78 public int getShaderTextId() { 79 return mShaderTextId; 80 } 81 82 /** 83 * get names of all known floats 84 * @return 85 */ getUniformFloatNames()86 public String[] getUniformFloatNames() { 87 if (mUniformFloatMap == null) return new String[0]; 88 return mUniformFloatMap.keySet().toArray(new String[0]); 89 } 90 91 /** 92 * Get float values associated with the name 93 * @param name 94 * @return 95 */ getUniformFloats(String name)96 public float[] getUniformFloats(String name) { 97 return mUniformFloatMap.get(name); 98 } 99 100 /** 101 * get the name of all know uniform integers 102 * @return 103 */ getUniformIntegerNames()104 public String[] getUniformIntegerNames() { 105 if (mUniformIntMap == null) return new String[0]; 106 return mUniformIntMap.keySet().toArray(new String[0]); 107 } 108 109 /** 110 * Get Int value associated with the name 111 * @param name 112 * @return 113 */ getUniformInts(String name)114 public int[] getUniformInts(String name) { 115 return mUniformIntMap.get(name); 116 } 117 118 /** 119 * get list of uniform Bitmaps 120 * @return 121 */ getUniformBitmapNames()122 public String[] getUniformBitmapNames() { 123 if (mUniformBitmapMap == null) return new String[0]; 124 return mUniformBitmapMap.keySet().toArray(new String[0]); 125 } 126 127 /** 128 * Get a bitmap stored under that name 129 * @param name 130 * @return 131 */ getUniformBitmapId(String name)132 public int getUniformBitmapId(String name) { 133 return mUniformBitmapMap.get(name); 134 } 135 136 @Override write(WireBuffer buffer)137 public void write(WireBuffer buffer) { 138 COMPANION.apply(buffer, mShaderID, mShaderTextId, 139 mUniformFloatMap, mUniformIntMap, mUniformBitmapMap); 140 } 141 142 @Override toString()143 public String toString() { 144 return "SHADER DATA " + mShaderID; 145 } 146 147 @Override updateVariables(RemoteContext context)148 public void updateVariables(RemoteContext context) { 149 for (String name : mUniformRawFloatMap.keySet()) { 150 float[] value = mUniformRawFloatMap.get(name); 151 float[] out = null; 152 for (int i = 0; i < value.length; i++) { 153 if (Float.isNaN(value[i])) { 154 if (out == null) { // need to copy 155 out = Arrays.copyOf(value, value.length); 156 } 157 out[i] = context.getFloat(Utils.idFromNan(value[i])); 158 } 159 } 160 mUniformFloatMap.put(name, out == null ? value : out); 161 } 162 } 163 164 @Override registerListening(RemoteContext context)165 public void registerListening(RemoteContext context) { 166 for (String name : mUniformRawFloatMap.keySet()) { 167 float[] value = mUniformRawFloatMap.get(name); 168 for (int i = 0; i < value.length; i++) { 169 if (Float.isNaN(value[i])) { 170 context.listensTo(Utils.idFromNan(value[i]), this); 171 } 172 } 173 } 174 } 175 176 public static class Companion implements CompanionOperation { Companion()177 private Companion() { 178 } 179 180 @Override name()181 public String name() { 182 return "BitmapData"; 183 } 184 185 @Override id()186 public int id() { 187 return Operations.DATA_SHADER; 188 } 189 190 /** 191 * Writes out the operation to the buffer 192 * @param buffer 193 * @param shaderID 194 * @param shaderTextId 195 * @param floatMap 196 * @param intMap 197 * @param bitmapMap 198 */ apply(WireBuffer buffer, int shaderID, int shaderTextId, HashMap<String, float[]> floatMap, HashMap<String, int[]> intMap, HashMap<String, Integer> bitmapMap)199 public void apply(WireBuffer buffer, int shaderID, int shaderTextId, 200 HashMap<String, float[]> floatMap, 201 HashMap<String, int[]> intMap, 202 HashMap<String, Integer> bitmapMap) { 203 buffer.start(Operations.DATA_SHADER); 204 buffer.writeInt(shaderID); 205 206 buffer.writeInt(shaderTextId); 207 int floatSize = (floatMap == null) ? 0 : floatMap.size(); 208 int intSize = (intMap == null) ? 0 : intMap.size(); 209 int bitmapSize = (bitmapMap == null) ? 0 : bitmapMap.size(); 210 int sizes = floatSize | (intSize << 8) | (bitmapSize << 16); 211 buffer.writeInt(sizes); 212 213 if (floatSize > 0) { 214 215 for (String name : floatMap.keySet()) { 216 buffer.writeUTF8(name); 217 float[] values = floatMap.get(name); 218 buffer.writeInt(values.length); 219 220 for (int i = 0; i < values.length; i++) { 221 buffer.writeFloat(values[i]); 222 } 223 } 224 } 225 226 if (intSize > 0) { 227 for (String name : intMap.keySet()) { 228 buffer.writeUTF8(name); 229 int[] values = intMap.get(name); 230 buffer.writeInt(values.length); 231 for (int i = 0; i < values.length; i++) { 232 buffer.writeInt(values[i]); 233 } 234 } 235 } 236 if (bitmapSize > 0) { 237 for (String name : bitmapMap.keySet()) { 238 buffer.writeUTF8(name); 239 int value = bitmapMap.get(name); 240 buffer.writeInt(value); 241 } 242 } 243 } 244 245 @Override read(WireBuffer buffer, List<Operation> operations)246 public void read(WireBuffer buffer, List<Operation> operations) { 247 int shaderID = buffer.readInt(); 248 int shaderTextId = buffer.readInt(); 249 HashMap<String, float[]> floatMap = null; 250 HashMap<String, int[]> intMap = null; 251 HashMap<String, Integer> bitmapMap = null; 252 253 int sizes = buffer.readInt(); 254 255 int floatMapSize = sizes & 0xFF; 256 if (floatMapSize > 0) { 257 floatMap = new HashMap<>(); 258 for (int i = 0; i < floatMapSize; i++) { 259 String name = buffer.readUTF8(); 260 int len = buffer.readInt(); 261 float[] val = new float[len]; 262 263 for (int j = 0; j < len; j++) { 264 val[j] = buffer.readFloat(); 265 } 266 267 floatMap.put(name, val); 268 } 269 } 270 int intMapSize = (sizes >> 8) & 0xFF; 271 272 if (intMapSize > 0) { 273 274 intMap = new HashMap<>(); 275 for (int i = 0; i < intMapSize; i++) { 276 String name = buffer.readUTF8(); 277 int len = buffer.readInt(); 278 int[] val = new int[len]; 279 for (int j = 0; j < len; j++) { 280 val[j] = buffer.readInt(); 281 } 282 intMap.put(name, val); 283 } 284 } 285 int bitmapMapSize = (sizes >> 16) & 0xFF; 286 287 if (bitmapMapSize > 0) { 288 bitmapMap = new HashMap<>(); 289 for (int i = 0; i < bitmapMapSize; i++) { 290 String name = buffer.readUTF8(); 291 int val = buffer.readInt(); 292 bitmapMap.put(name, val); 293 } 294 } 295 operations.add(new ShaderData(shaderID, shaderTextId, 296 floatMap, intMap, bitmapMap)); 297 } 298 } 299 300 @Override apply(RemoteContext context)301 public void apply(RemoteContext context) { 302 context.loadShader(mShaderID, this); 303 } 304 305 @Override deepToString(String indent)306 public String deepToString(String indent) { 307 return indent + toString(); 308 } 309 } 310