1 // 2 // Copyright (c) 2014 The ANGLE Project Authors. All rights reserved. 3 // Use of this source code is governed by a BSD-style license that can be 4 // found in the LICENSE file. 5 // 6 // StructureHLSL.cpp: 7 // Definitions of methods for HLSL translation of GLSL structures. 8 // 9 10 #include "compiler/translator/StructureHLSL.h" 11 #include "common/utilities.h" 12 #include "compiler/translator/OutputHLSL.h" 13 #include "compiler/translator/Types.h" 14 #include "compiler/translator/util.h" 15 #include "compiler/translator/UtilsHLSL.h" 16 17 namespace sh 18 { 19 20 Std140PaddingHelper::Std140PaddingHelper(const std::map<TString, int> &structElementIndexes, 21 unsigned *uniqueCounter) 22 : mPaddingCounter(uniqueCounter), 23 mElementIndex(0), 24 mStructElementIndexes(structElementIndexes) 25 {} 26 27 TString Std140PaddingHelper::next() 28 { 29 unsigned value = (*mPaddingCounter)++; 30 return str(value); 31 } 32 33 int Std140PaddingHelper::prePadding(const TType &type) 34 { 35 if (type.getBasicType() == EbtStruct || type.isMatrix() || type.isArray()) 36 { 37 // no padding needed, HLSL will align the field to a new register 38 mElementIndex = 0; 39 return 0; 40 } 41 42 const GLenum glType = GLVariableType(type); 43 const int numComponents = gl::VariableComponentCount(glType); 44 45 if (numComponents >= 4) 46 { 47 // no padding needed, HLSL will align the field to a new register 48 mElementIndex = 0; 49 return 0; 50 } 51 52 if (mElementIndex + numComponents > 4) 53 { 54 // no padding needed, HLSL will align the field to a new register 55 mElementIndex = numComponents; 56 return 0; 57 } 58 59 const int alignment = numComponents == 3 ? 4 : numComponents; 60 const int paddingOffset = (mElementIndex % alignment); 61 const int paddingCount = (paddingOffset != 0 ? (alignment - paddingOffset) : 0); 62 63 mElementIndex += paddingCount; 64 mElementIndex += numComponents; 65 mElementIndex %= 4; 66 67 return paddingCount; 68 } 69 70 TString Std140PaddingHelper::prePaddingString(const TType &type) 71 { 72 int paddingCount = prePadding(type); 73 74 TString padding; 75 76 for (int paddingIndex = 0; paddingIndex < paddingCount; paddingIndex++) 77 { 78 padding += " float pad_" + next() + ";\n"; 79 } 80 81 return padding; 82 } 83 84 TString Std140PaddingHelper::postPaddingString(const TType &type, bool useHLSLRowMajorPacking) 85 { 86 if (!type.isMatrix() && !type.isArray() && type.getBasicType() != EbtStruct) 87 { 88 return ""; 89 } 90 91 int numComponents = 0; 92 TStructure *structure = type.getStruct(); 93 94 if (type.isMatrix()) 95 { 96 // This method can also be called from structureString, which does not use layout qualifiers. 97 // Thus, use the method parameter for determining the matrix packing. 98 // 99 // Note HLSL row major packing corresponds to GL API column-major, and vice-versa, since we 100 // wish to always transpose GL matrices to play well with HLSL's matrix array indexing. 101 // 102 const bool isRowMajorMatrix = !useHLSLRowMajorPacking; 103 const GLenum glType = GLVariableType(type); 104 numComponents = gl::MatrixComponentCount(glType, isRowMajorMatrix); 105 } 106 else if (structure) 107 { 108 const TString &structName = QualifiedStructNameString(*structure, 109 useHLSLRowMajorPacking, true); 110 numComponents = mStructElementIndexes.find(structName)->second; 111 112 if (numComponents == 0) 113 { 114 return ""; 115 } 116 } 117 else 118 { 119 const GLenum glType = GLVariableType(type); 120 numComponents = gl::VariableComponentCount(glType); 121 } 122 123 TString padding; 124 for (int paddingOffset = numComponents; paddingOffset < 4; paddingOffset++) 125 { 126 padding += " float pad_" + next() + ";\n"; 127 } 128 return padding; 129 } 130 131 StructureHLSL::StructureHLSL() 132 : mUniquePaddingCounter(0) 133 {} 134 135 Std140PaddingHelper StructureHLSL::getPaddingHelper() 136 { 137 return Std140PaddingHelper(mStd140StructElementIndexes, &mUniquePaddingCounter); 138 } 139 140 TString StructureHLSL::defineQualified(const TStructure &structure, bool useHLSLRowMajorPacking, bool useStd140Packing) 141 { 142 if (useStd140Packing) 143 { 144 Std140PaddingHelper padHelper = getPaddingHelper(); 145 return define(structure, useHLSLRowMajorPacking, useStd140Packing, &padHelper); 146 } 147 else 148 { 149 return define(structure, useHLSLRowMajorPacking, useStd140Packing, NULL); 150 } 151 } 152 153 TString StructureHLSL::defineNameless(const TStructure &structure) 154 { 155 return define(structure, false, false, NULL); 156 } 157 158 TString StructureHLSL::define(const TStructure &structure, bool useHLSLRowMajorPacking, 159 bool useStd140Packing, Std140PaddingHelper *padHelper) 160 { 161 const TFieldList &fields = structure.fields(); 162 const bool isNameless = (structure.name() == ""); 163 const TString &structName = QualifiedStructNameString(structure, useHLSLRowMajorPacking, 164 useStd140Packing); 165 const TString declareString = (isNameless ? "struct" : "struct " + structName); 166 167 TString string; 168 string += declareString + "\n" 169 "{\n"; 170 171 for (unsigned int i = 0; i < fields.size(); i++) 172 { 173 const TField &field = *fields[i]; 174 const TType &fieldType = *field.type(); 175 const TStructure *fieldStruct = fieldType.getStruct(); 176 const TString &fieldTypeString = fieldStruct ? 177 QualifiedStructNameString(*fieldStruct, useHLSLRowMajorPacking, 178 useStd140Packing) : 179 TypeString(fieldType); 180 181 if (padHelper) 182 { 183 string += padHelper->prePaddingString(fieldType); 184 } 185 186 string += " " + fieldTypeString + " " + DecorateField(field.name(), structure) + ArrayString(fieldType) + ";\n"; 187 188 if (padHelper) 189 { 190 string += padHelper->postPaddingString(fieldType, useHLSLRowMajorPacking); 191 } 192 } 193 194 // Nameless structs do not finish with a semicolon and newline, to leave room for an instance variable 195 string += (isNameless ? "} " : "};\n"); 196 197 return string; 198 } 199 200 void StructureHLSL::addConstructor(const TType &type, const TString &name, const TIntermSequence *parameters) 201 { 202 if (name == "") 203 { 204 return; // Nameless structures don't have constructors 205 } 206 207 if (type.getStruct() && mStructNames.find(name) != mStructNames.end()) 208 { 209 return; // Already added 210 } 211 212 TType ctorType = type; 213 ctorType.clearArrayness(); 214 ctorType.setPrecision(EbpHigh); 215 ctorType.setQualifier(EvqTemporary); 216 217 typedef std::vector<TType> ParameterArray; 218 ParameterArray ctorParameters; 219 220 const TStructure* structure = type.getStruct(); 221 if (structure) 222 { 223 mStructNames.insert(name); 224 225 // Add element index 226 storeStd140ElementIndex(*structure, false); 227 storeStd140ElementIndex(*structure, true); 228 229 const TString &structString = defineQualified(*structure, false, false); 230 231 if (std::find(mStructDeclarations.begin(), mStructDeclarations.end(), structString) == mStructDeclarations.end()) 232 { 233 // Add row-major packed struct for interface blocks 234 TString rowMajorString = "#pragma pack_matrix(row_major)\n" + 235 defineQualified(*structure, true, false) + 236 "#pragma pack_matrix(column_major)\n"; 237 238 TString std140String = defineQualified(*structure, false, true); 239 TString std140RowMajorString = "#pragma pack_matrix(row_major)\n" + 240 defineQualified(*structure, true, true) + 241 "#pragma pack_matrix(column_major)\n"; 242 243 mStructDeclarations.push_back(structString); 244 mStructDeclarations.push_back(rowMajorString); 245 mStructDeclarations.push_back(std140String); 246 mStructDeclarations.push_back(std140RowMajorString); 247 } 248 249 const TFieldList &fields = structure->fields(); 250 for (unsigned int i = 0; i < fields.size(); i++) 251 { 252 ctorParameters.push_back(*fields[i]->type()); 253 } 254 } 255 else if (parameters) 256 { 257 for (TIntermSequence::const_iterator parameter = parameters->begin(); parameter != parameters->end(); parameter++) 258 { 259 ctorParameters.push_back((*parameter)->getAsTyped()->getType()); 260 } 261 } 262 else UNREACHABLE(); 263 264 TString constructor; 265 266 if (ctorType.getStruct()) 267 { 268 constructor += name + " " + name + "_ctor("; 269 } 270 else // Built-in type 271 { 272 constructor += TypeString(ctorType) + " " + name + "("; 273 } 274 275 for (unsigned int parameter = 0; parameter < ctorParameters.size(); parameter++) 276 { 277 const TType &type = ctorParameters[parameter]; 278 279 constructor += TypeString(type) + " x" + str(parameter) + ArrayString(type); 280 281 if (parameter < ctorParameters.size() - 1) 282 { 283 constructor += ", "; 284 } 285 } 286 287 constructor += ")\n" 288 "{\n"; 289 290 if (ctorType.getStruct()) 291 { 292 constructor += " " + name + " structure = {"; 293 } 294 else 295 { 296 constructor += " return " + TypeString(ctorType) + "("; 297 } 298 299 if (ctorType.isMatrix() && ctorParameters.size() == 1) 300 { 301 int rows = ctorType.getRows(); 302 int cols = ctorType.getCols(); 303 const TType ¶meter = ctorParameters[0]; 304 305 if (parameter.isScalar()) 306 { 307 for (int col = 0; col < cols; col++) 308 { 309 for (int row = 0; row < rows; row++) 310 { 311 constructor += TString((row == col) ? "x0" : "0.0"); 312 313 if (row < rows - 1 || col < cols - 1) 314 { 315 constructor += ", "; 316 } 317 } 318 } 319 } 320 else if (parameter.isMatrix()) 321 { 322 for (int col = 0; col < cols; col++) 323 { 324 for (int row = 0; row < rows; row++) 325 { 326 if (row < parameter.getRows() && col < parameter.getCols()) 327 { 328 constructor += TString("x0") + "[" + str(col) + "][" + str(row) + "]"; 329 } 330 else 331 { 332 constructor += TString((row == col) ? "1.0" : "0.0"); 333 } 334 335 if (row < rows - 1 || col < cols - 1) 336 { 337 constructor += ", "; 338 } 339 } 340 } 341 } 342 else 343 { 344 ASSERT(rows == 2 && cols == 2 && parameter.isVector() && parameter.getNominalSize() == 4); 345 346 constructor += "x0"; 347 } 348 } 349 else 350 { 351 size_t remainingComponents = ctorType.getObjectSize(); 352 size_t parameterIndex = 0; 353 354 while (remainingComponents > 0) 355 { 356 const TType ¶meter = ctorParameters[parameterIndex]; 357 const size_t parameterSize = parameter.getObjectSize(); 358 bool moreParameters = parameterIndex + 1 < ctorParameters.size(); 359 360 constructor += "x" + str(parameterIndex); 361 362 if (ctorType.getStruct()) 363 { 364 ASSERT(remainingComponents == parameterSize || moreParameters); 365 ASSERT(parameterSize <= remainingComponents); 366 367 remainingComponents -= parameterSize; 368 } 369 else if (parameter.isScalar()) 370 { 371 remainingComponents -= parameter.getObjectSize(); 372 } 373 else if (parameter.isVector()) 374 { 375 if (remainingComponents == parameterSize || moreParameters) 376 { 377 ASSERT(parameterSize <= remainingComponents); 378 remainingComponents -= parameterSize; 379 } 380 else if (remainingComponents < static_cast<size_t>(parameter.getNominalSize())) 381 { 382 switch (remainingComponents) 383 { 384 case 1: constructor += ".x"; break; 385 case 2: constructor += ".xy"; break; 386 case 3: constructor += ".xyz"; break; 387 case 4: constructor += ".xyzw"; break; 388 default: UNREACHABLE(); 389 } 390 391 remainingComponents = 0; 392 } 393 else UNREACHABLE(); 394 } 395 else if (parameter.isMatrix()) 396 { 397 int column = 0; 398 while (remainingComponents > 0 && column < parameter.getCols()) 399 { 400 constructor += "[" + str(column) + "]"; 401 402 if (remainingComponents < static_cast<size_t>(parameter.getRows())) 403 { 404 switch (remainingComponents) 405 { 406 case 1: constructor += ".x"; break; 407 case 2: constructor += ".xy"; break; 408 case 3: constructor += ".xyz"; break; 409 default: UNREACHABLE(); 410 } 411 412 remainingComponents = 0; 413 } 414 else 415 { 416 remainingComponents -= parameter.getRows(); 417 418 if (remainingComponents > 0) 419 { 420 constructor += ", x" + str(parameterIndex); 421 } 422 } 423 424 column++; 425 } 426 } 427 else UNREACHABLE(); 428 429 if (moreParameters) 430 { 431 parameterIndex++; 432 } 433 434 if (remainingComponents) 435 { 436 constructor += ", "; 437 } 438 } 439 } 440 441 if (ctorType.getStruct()) 442 { 443 constructor += "};\n" 444 " return structure;\n" 445 "}\n"; 446 } 447 else 448 { 449 constructor += ");\n" 450 "}\n"; 451 } 452 453 mConstructors.insert(constructor); 454 } 455 456 std::string StructureHLSL::structsHeader() const 457 { 458 TInfoSinkBase out; 459 460 for (size_t structIndex = 0; structIndex < mStructDeclarations.size(); structIndex++) 461 { 462 out << mStructDeclarations[structIndex]; 463 } 464 465 for (Constructors::const_iterator constructor = mConstructors.begin(); 466 constructor != mConstructors.end(); 467 constructor++) 468 { 469 out << *constructor; 470 } 471 472 return out.str(); 473 } 474 475 void StructureHLSL::storeStd140ElementIndex(const TStructure &structure, bool useHLSLRowMajorPacking) 476 { 477 Std140PaddingHelper padHelper = getPaddingHelper(); 478 const TFieldList &fields = structure.fields(); 479 480 for (unsigned int i = 0; i < fields.size(); i++) 481 { 482 padHelper.prePadding(*fields[i]->type()); 483 } 484 485 // Add remaining element index to the global map, for use with nested structs in standard layouts 486 const TString &structName = QualifiedStructNameString(structure, useHLSLRowMajorPacking, true); 487 mStd140StructElementIndexes[structName] = padHelper.elementIndex(); 488 } 489 490 } 491