1 2 # More Complex Interface Mapping MavenStyleProject - The Cascade 3 4 ---- 5 6 * [Contents](hat-00.md) 7 * House Keeping 8 * [Project Layout](hat-01-01-project-layout.md) 9 * [Building Babylon](hat-01-02-building-babylon.md) 10 * [Building HAT](hat-01-03-building-hat.md) 11 * Programming Model 12 * [Programming Model](hat-03-programming-model.md) 13 * Interface Mapping 14 * [Interface Mapping Overview](hat-04-01-interface-mapping.md) 15 * [Cascade Interface Mapping](hat-04-02-cascade-interface-mapping.md) 16 * Implementation Detail 17 * [Walkthrough Of Accelerator.compute()](hat-accelerator-compute.md) 18 * [How we minimize buffer transfers](hat-minimizing-buffer-transfers.md) 19 20 ---- 21 22 # More Complex Interface Mapping MavenStyleProject - The Cascade 23 24 Previously we showed probably the minimal useful mapping with S32Array 25 26 The HaarCascade example has multiple nested interfaces representing data 27 structures involving various nested structs and unions 28 29 ```java 30 public interface Cascade extends Buffer { 31 int width(); 32 void width(int width); 33 int height(); 34 void height(int height); 35 interface Feature extends Buffer.StructChild { 36 int id(); 37 float threshold(); 38 void id(int id); 39 void threshold(float threshold); 40 interface LinkOrValue extends Buffer.StructChild { 41 interface Anon extends Buffer.UnionChild { 42 int featureId(); 43 void featureId(int featureId); 44 float value(); 45 void value(float value); 46 } 47 boolean hasValue(); 48 void hasValue(boolean hasValue); 49 Anon anon(); 50 } 51 LinkOrValue left(); 52 LinkOrValue right(); 53 interface Rect extends Buffer.StructChild { 54 byte x(); 55 byte y(); 56 byte width(); 57 byte height(); 58 float weight(); 59 void x(byte x); 60 void y(byte y); 61 void width(byte width); 62 void height(byte height); 63 void weight(float height); 64 } 65 Rect rect(long idx); 66 } 67 int featureCount(); 68 void featureCount(int featureCount); 69 Feature feature(long idx); 70 interface Stage extends Buffer.StructChild { 71 float threshold(); 72 short firstTreeId(); 73 short treeCount(); 74 int id(); 75 void id(int id); 76 void threshold(float threshold); 77 void firstTreeId(short firstTreeId); 78 void treeCount(short treeCount); 79 } 80 81 int stageCount(); 82 void stageCount(int stageCount); 83 Stage stage(long idx); 84 interface Tree extends Buffer.StructChild { 85 void id(int id); 86 void firstFeatureId(short firstFeatureId); 87 void featureCount(short featureCount); 88 int id(); 89 short firstFeatureId(); 90 short featureCount(); 91 } 92 int treeCount(); 93 void treeCount(int treeCount); 94 Tree tree(long idx); 95 Schema<Cascade> schema = Schema.of(Cascade.class, cascade -> cascade 96 .fields("width", "height") 97 .arrayLen("featureCount") 98 .array("feature", feature -> feature 99 .field("id") 100 .field("threshold") 101 .fields("left", "right", linkOrValue -> linkOrValue 102 .field("hasValue") 103 .pad(3) 104 .field("anon", anon -> anon 105 .field("featureId") 106 .field("value") 107 ) 108 ) 109 .array("rect", 3, rect -> rect 110 .field("x") 111 .field("y") 112 .field("width") 113 .field("height"). 114 .field("weight")) 115 ) 116 .arrayLen("treeCount") 117 .array("tree", tree -> tree 118 .field("id") 119 .field("featureCount") 120 .field("firstFeatureId") 121 ) 122 .arrayLen("stageCount") 123 .array("stage", stage -> stage 124 .field("id") 125 .field("threshold") 126 .field("treeCount") 127 .field("firstTreeId")) 128 ); 129 } 130 ``` 131 132 Another great advantage of using interfaces is that we can choose 133 to re implement the interface in any was we see fit. 134 135 For example we load HaarCascades from XML files. 136 We therefore can create an implementation of the Cascade interface which just 137 loads the XML DOM... stores them in arrays and the interface methods just delegate to 138 the appropriately wrapped w3c.Node tree nodes ;) 139 140 If we know we are using Java backend we can actually 141 just pass the XMLCascade implementation directly to the backend... 142 143 Actually the Cascade `create` method takes an existing 144 implementation of a Cascade and clones it. 145 So we can just pass it an XMLHaarCascade ;) 146 147 So we build an XMLCascade then pass it to the `create` method of the iface 148 mapped Cascade 149 150 ```java 151 XMLHaarCascadeModel haarCascade = XMLHaarCascadeModel.load( 152 ViolaJonesRaw.class.getResourceAsStream("haarcascade_frontalface_default.xml")); 153 154 assert haarCascade instanceof Cascade; // Here it is just an interface 155 156 Cascade cascade = Cascade.create(accelerator, haarCascade); 157 158 // Now it can be used on the GPU 159 ``` 160 161 The implementation is currently hand crafted, but this could easily be automated. 162 163 ```java 164 import java.lang.invoke.MethodHandles; 165 166 static Cascade create(MethodHandles.Lookup lookup,BufferAllocator bufferAllocator, XMLHaarCascadeModel haarCascade) { 167 168 Cascade cascade = bufferAllocator.allocate(SegmentMapper.of(lookup, Cascade.class, 169 JAVA_INT.withName("width"), 170 JAVA_INT.withName("height"), 171 JAVA_INT.withName("featureCount"), 172 sequenceLayout(haarCascade.features.size(), Feature.layout.withName(Feature.class.getSimpleName())).withName("feature"), 173 JAVA_INT.withName("stageCount"), 174 sequenceLayout(haarCascade.stages.size(), Stage.layout.withName(Stage.class.getSimpleName())).withName("stage"), 175 JAVA_INT.withName("treeCount"), 176 sequenceLayout(haarCascade.trees.size(), Tree.layout.withName(Tree.class.getSimpleName())).withName("tree") 177 )); 178 cascade.width(haarCascade.width()); 179 cascade.height(haarCascade.height()); 180 cascade.featureCount(haarCascade.features.size()); 181 cascade.stageCount(haarCascade.stages.size()); 182 cascade.treeCount(haarCascade.trees.size()); 183 for (int idx = 0; idx < haarCascade.features.size(); idx++) { 184 Cascade.Feature cascadeFeature = cascade.feature(idx); 185 var haarfeature = haarCascade.features.get(idx); 186 cascadeFeature.id(haarfeature.id()); 187 cascadeFeature.threshold(haarfeature.threshold()); 188 Cascade.Feature.LinkOrValue cascadeLeft = cascadeFeature.left(); 189 cascadeLeft.hasValue(haarfeature.left.hasValue()); 190 if (haarfeature.left.hasValue()) { 191 cascadeLeft.anon().value(haarfeature.left.value()); 192 } else { 193 cascadeLeft.anon().value(haarfeature.left.featureId()); 194 } 195 Cascade.Feature.LinkOrValue cascadeRight = cascadeFeature.right(); 196 cascadeRight.hasValue(haarfeature.right.hasValue()); 197 if (haarfeature.right.hasValue()) { 198 cascadeRight.anon().value(haarfeature.right.value()); 199 } else { 200 cascadeRight.anon().featureId(haarfeature.right.featureId()); 201 } 202 for (int r = 0; r < 3; r++) { 203 var haarrect = haarfeature.rects[r]; 204 if (haarrect != null) { 205 Cascade.Feature.Rect cascadeRect = cascadeFeature.rect(r); 206 cascadeRect.x(haarrect.x()); 207 cascadeRect.y(haarrect.y()); 208 cascadeRect.width(haarrect.width()); 209 cascadeRect.height(haarrect.height()); 210 cascadeRect.weight(haarrect.weight()); 211 } 212 } 213 } 214 for (XMLHaarCascadeModel.Stage haarstage : haarCascade.stages) { 215 Cascade.Stage cascadeStage = cascade.stage(haarstage.id); 216 cascadeStage.id(haarstage.id()); 217 cascadeStage.threshold(haarstage.threshold()); 218 cascadeStage.firstTreeId(haarstage.firstTreeId()); 219 cascadeStage.treeCount(haarstage.treeCount()); 220 } 221 222 for (XMLHaarCascadeModel.Tree haarTree : haarCascade.trees) { 223 Cascade.Tree cascadeTree = cascade.tree(haarTree.id()); 224 cascadeTree.id(haarTree.id()); 225 cascadeTree.firstFeatureId(haarTree.firstFeatureId()); 226 cascadeTree.featureCount(haarTree.featureCount()); 227 } 228 return cascade; 229 } 230 ``` 231