yum-mirror/slang
Making it easier to work with shaders
git clone https://git.yummers.dev/yum-mirror/slang
a6deb5ed8
master
1// Stop warnings from Visual Studio 2#define _CRT_SECURE_NO_WARNINGS 1 3 4#include "shader-input-layout.h" 5 6#include "core/slang-token-reader.h" 7#include "core/slang-type-text-util.h" 8 9#include <slang-rhi.h> 10 11namespace renderer_test 12{ 13using namespace Slang ; 14 15// clang-format off 16#define SLANG_SCALAR_TYPES (x ) \ 17 x("int", INT32) \ 18 x("uint", UINT32) \ 19 x("float", FLOAT32) 20// clang-format on 21 22 23Format _getFormatFromName (const UnownedStringSlice & slice ) 24{ 25for (int i = 0 ;i < int (Format ::_Count );++ i ) 26 { 27const FormatInfo & info = getFormatInfo (Format (i )); 28if (slice == info .name ) 29 { 30return Format (i ); 31 } 32 } 33return Format ::Undefined ; 34} 35 36struct TypeInfo 37{ 38UnownedStringSlice name ; 39SlangScalarType type ; 40}; 41 42#define SLANG_SCALAR_TYPE_INFO (name ,value ) \ 43 {UnownedStringSlice::fromLiteral(name), SLANG_SCALAR_TYPE_##value}, 44static const TypeInfo g_scalarTypeInfos []= {SLANG_SCALAR_TYPES (SLANG_SCALAR_TYPE_INFO )}; 45#undef SLANG_SCALAR_TYPES 46#undef SLANG_SCALAR_TYPE_INFO 47 48static SlangScalarType _getScalarType (const UnownedStringSlice & slice ) 49{ 50for (const auto & info :g_scalarTypeInfos ) 51 { 52if (info .name == slice ) 53 { 54return info .type ; 55 } 56 } 57return SLANG_SCALAR_TYPE_NONE ; 58} 59 60void ShaderInputLayout ::AggVal ::addField (ShaderInputLayout ::Field const & field ) 61{ 62fields .add (field ); 63} 64 65void ShaderInputLayout ::ArrayVal ::addField (ShaderInputLayout ::Field const & field ) 66{ 67vals .add (field .val ); 68} 69 70class ShaderInputLayoutFormatException :public Exception 71{ 72public : 73ShaderInputLayoutFormatException (String message ) 74 :Exception (message ) 75 { 76 } 77}; 78 79struct ShaderInputLayoutParser 80{ 81ShaderInputLayout * layout ; 82RandomGenerator * rand ; 83 84ShaderInputLayoutParser (ShaderInputLayout * layout ,RandomGenerator * rand ) 85 :layout (layout ),rand (rand ) 86 { 87 } 88 89RefPtr < ShaderInputLayout ::ParentVal > parentVal ; 90List < RefPtr < ShaderInputLayout ::ParentVal >> parentValStack ; 91 92SlangResult parseOption ( 93Misc ::TokenReader & parser , 94String const & word , 95ShaderInputLayout ::TextureVal * val ) 96 { 97if (word == "depth" ) 98 { 99val -> textureDesc .isDepthTexture = true; 100 } 101else if (word == "arrayLength" ) 102 { 103parser .Read ("=" ); 104val -> textureDesc .arrayLength = parser .ReadInt (); 105 } 106else if (word == "size" ) 107 { 108parser .Read ("=" ); 109auto size = parser .ReadInt (); 110val -> textureDesc .size = size ; 111 } 112else if (word == "content" ) 113 { 114parser .Read ("=" ); 115auto contentWord = parser .ReadWord (); 116if (contentWord == "zero" ) 117val -> textureDesc .content = InputTextureContent ::Zero ; 118else if (contentWord == "one" ) 119val -> textureDesc .content = InputTextureContent ::One ; 120else if (contentWord == "chessboard" ) 121val -> textureDesc .content = InputTextureContent ::ChessBoard ; 122else 123val -> textureDesc .content = InputTextureContent ::Gradient ; 124 } 125else if (word == "sampleCount" ) 126 { 127parser .Read ("=" ); 128auto contentWord = parser .ReadWord (); 129if (contentWord == "one" ) 130val -> textureDesc .sampleCount = InputTextureSampleCount ::One ; 131else if (contentWord == "two" ) 132val -> textureDesc .sampleCount = InputTextureSampleCount ::Two ; 133else if (contentWord == "four" ) 134val -> textureDesc .sampleCount = InputTextureSampleCount ::Four ; 135else if (contentWord == "eight" ) 136val -> textureDesc .sampleCount = InputTextureSampleCount ::Eight ; 137else if (contentWord == "sixteen" ) 138val -> textureDesc .sampleCount = InputTextureSampleCount ::Sixteen ; 139else if (contentWord == "thirtyTwo" ) 140val -> textureDesc .sampleCount = InputTextureSampleCount ::ThirtyTwo ; 141else if (contentWord == "sixtyFour" ) 142val -> textureDesc .sampleCount = InputTextureSampleCount ::SixtyFour ; 143 } 144else if (word == "mipMaps" ) 145 { 146parser .Read ("=" ); 147val -> textureDesc .mipMapCount = int (parser .ReadInt ()); 148 } 149else if (word == "format" ) 150 { 151val -> textureDesc .format = parseFormatOption (parser ); 152 153if (val -> textureDesc .format == Format ::Undefined ) 154 { 155return SLANG_FAIL ; 156 } 157 } 158else 159 { 160return SLANG_FAIL ; 161 } 162return SLANG_OK ; 163 } 164 165SlangResult parseOption ( 166Misc ::TokenReader & parser , 167String const & word , 168ShaderInputLayout ::SamplerVal * val ) 169 { 170if (word == "depthCompare" ) 171 { 172val -> samplerDesc .isCompareSampler = true; 173 } 174else if (word == "filteringMode" ) 175 { 176parser .Read ("=" ); 177auto contentWord = parser .ReadWord (); 178if (contentWord == "point" ) 179 { 180val -> samplerDesc .filteringMode = TextureFilteringMode ::Point ; 181 } 182else 183 { 184val -> samplerDesc .filteringMode = TextureFilteringMode ::Linear ; 185 } 186 } 187else 188 { 189return SLANG_FAIL ; 190 } 191return SLANG_OK ; 192 } 193 194 195SlangResult parseOption ( 196Misc ::TokenReader & parser , 197String const & word , 198ShaderInputLayout ::CombinedTextureSamplerVal * val ) 199 { 200auto result = parseOption (parser ,word ,val -> textureVal ); 201if (SLANG_SUCCEEDED (result )) 202return result ; 203 204result = parseOption (parser ,word ,val -> samplerVal ); 205return result ; 206 } 207 208SlangResult parseOption ( 209Misc ::TokenReader & parser , 210String const & word , 211ShaderInputLayout ::DataValBase * val ) 212 { 213if (word == "data" ) 214 { 215parser .Read ("=" ); 216 217parser .Read ("[" ); 218uint32_t offset = 0 ; 219while (!parser .IsEnd ()&& !parser .LookAhead ("]" )) 220 { 221bool negate = false; 222if (parser .NextToken ().Type == Misc ::TokenType ::OpSub ) 223 { 224parser .ReadToken (); 225negate = true; 226 } 227 228if (parser .NextToken ().Type == Misc ::TokenType ::IntLiteral ) 229 { 230uint32_t value = parser .ReadUInt (); 231if (negate ) 232value = uint32_t (- int32_t (value )); 233val -> bufferData .add (value ); 234 } 235else 236 { 237auto floatNum = parser .ReadFloat (); 238if (negate ) 239floatNum = - floatNum ; 240val -> bufferData .add (* (unsigned int * )& floatNum ); 241 } 242offset += 4 ; 243 } 244parser .Read ("]" ); 245 } 246else 247 { 248return SLANG_FAIL ; 249 } 250return SLANG_OK ; 251 } 252 253SlangResult parseOption ( 254Misc ::TokenReader & parser , 255String const & word , 256ShaderInputLayout ::BufferVal * val ) 257 { 258if (word == "stride" ) 259 { 260parser .Read ("=" ); 261val -> bufferDesc .stride = parser .ReadInt (); 262 } 263else if (word == "count" ) 264 { 265parser .Read ("=" ); 266val -> bufferDesc .elementCount = parser .ReadInt (); 267 } 268else if (word == "counter" ) 269 { 270parser .Read ("=" ); 271val -> bufferDesc .counter = parser .ReadInt (); 272 } 273else if (word == "random" ) 274 { 275parser .Read ("(" ); 276// Read the type 277String type = parser .ReadWord (); 278SlangScalarType scalarType = _getScalarType (type .getUnownedSlice ()); 279if (scalarType == SLANG_SCALAR_TYPE_NONE ) 280 { 281StringBuilder scalarTypeNames ; 282for (const auto & info :g_scalarTypeInfos ) 283 { 284if (scalarTypeNames .getLength ()!= 0 ) 285 { 286scalarTypeNames <<", " ; 287 } 288scalarTypeNames <<info .name ; 289 } 290 291throw ShaderInputLayoutFormatException ( 292StringBuilder () 293 <<"Expecting " <<scalarTypeNames <<" " <<parser .NextToken ().Position .Line ); 294 } 295 296parser .Read ("," ); 297const int size = int (parser .ReadUInt ()); 298 299switch (scalarType ) 300 { 301case SLANG_SCALAR_TYPE_INT32 : 302 { 303bool hasRange = false; 304 305int32_t minValue = -0x7fffffff - 1 ; 306int32_t maxValue = 0x7fffffff ; 307 308if (parser .LookAhead ("," )) 309 { 310hasRange = true; 311parser .ReadToken (); 312minValue = parser .ReadInt (); 313 314if (parser .LookAhead ("," )) 315 { 316parser .ReadToken (); 317maxValue = parser .ReadInt (); 318 } 319 } 320SLANG_ASSERT (minValue <=maxValue ); 321maxValue = (maxValue >=minValue ) ?maxValue :minValue ; 322 323// Generate the data 324val -> bufferData .setCount (size ); 325 326int32_t * dst = (int32_t * )val -> bufferData .getBuffer (); 327for (int i = 0 ;i < size ;++ i ) 328 { 329dst [i ]= hasRange ?rand -> nextInt32InRange (minValue ,maxValue ) 330 :rand -> nextInt32 (); 331 } 332break ; 333 } 334case SLANG_SCALAR_TYPE_UINT32 : 335 { 336bool hasRange = false; 337uint32_t minValue = 0 ; 338uint32_t maxValue = 0xffffffff ; 339 340if (parser .LookAhead ("," )) 341 { 342parser .ReadToken (); 343minValue = parser .ReadUInt (); 344 345hasRange = true; 346 347if (parser .LookAhead ("," )) 348 { 349parser .ReadToken (); 350maxValue = parser .ReadUInt (); 351 } 352 } 353 354SLANG_ASSERT (minValue <=maxValue ); 355maxValue = (maxValue >=minValue ) ?maxValue :minValue ; 356 357// Generate the data 358val -> bufferData .setCount (size ); 359 360uint32_t * dst = (uint32_t * )val -> bufferData .getBuffer (); 361for (int i = 0 ;i < size ;++ i ) 362 { 363dst [i ]= hasRange ?rand -> nextUInt32InRange (minValue ,maxValue ) 364 :rand -> nextUInt32 (); 365 } 366 367break ; 368 } 369case SLANG_SCALAR_TYPE_FLOAT32 : 370 { 371float minValue = -1.0f ; 372float maxValue = 1.0f ; 373 374if (parser .LookAhead ("," )) 375 { 376parser .ReadToken (); 377minValue = parser .ReadFloat (); 378 379if (parser .LookAhead ("," )) 380 { 381parser .ReadToken (); 382maxValue = parser .ReadFloat (); 383 } 384 } 385 386SLANG_ASSERT (minValue <=maxValue ); 387maxValue = (maxValue >=minValue ) ?maxValue :minValue ; 388 389// Generate the data 390val -> bufferData .setCount (size ); 391 392float * dst = (float * )val -> bufferData .getBuffer (); 393for (int i = 0 ;i < size ;++ i ) 394 { 395dst [i ]= (rand -> nextUnitFloat32 ()* (maxValue - minValue ))+ minValue ; 396 } 397break ; 398 } 399 } 400 401// Read the range 402 403parser .Read (")" ); 404 } 405else if (word == "format" ) 406 { 407val -> bufferDesc .format = parseFormatOption (parser ); 408 } 409else 410 { 411return parseOption (parser ,word ,static_cast < ShaderInputLayout ::DataValBase *> (val )); 412 } 413return SLANG_OK ; 414 } 415 416SlangResult parseOption ( 417Misc ::TokenReader & parser , 418String const & word , 419ShaderInputLayout ::ObjectVal * val ) 420 { 421if (word == "type" ) 422 { 423parser .Read ("=" ); 424val -> typeName = parser .ReadWord (); 425 } 426else 427 { 428return SLANG_FAIL ; 429 } 430return SLANG_OK ; 431 } 432 433Format parseFormatOption (Misc ::TokenReader & parser ) 434 { 435parser .Read ("=" ); 436auto formatWord = parser .ReadWord (); 437 438return _getFormatFromName (formatWord .getUnownedSlice ()); 439 } 440 441template < typename T > 442void maybeParseOptions (Misc ::TokenReader & parser ,T * val ) 443 { 444// parse options 445if (parser .LookAhead ("(" )) 446 { 447parser .Read ("(" ); 448while (!parser .IsEnd ()&& !parser .LookAhead (")" )) 449 { 450auto word = parser .ReadWord (); 451if (SLANG_FAILED (parseOption (parser ,word ,val ))) 452 { 453throw ShaderInputLayoutFormatException ( 454String ("Unsupported option '" )+ word + String ("' at line " )+ 455String (parser .NextToken ().Position .Line )); 456 } 457 458if (parser .LookAhead ("," )) 459parser .Read ("," ); 460else 461break ; 462 } 463parser .Read (")" ); 464 } 465 } 466 467RefPtr < ShaderInputLayout ::Val > parseNumericValExpr ( 468Misc ::TokenReader & parser , 469bool negate = false) 470 { 471switch (parser .NextToken ().Type ) 472 { 473case Misc ::TokenType ::IntLiteral : 474 { 475RefPtr < ShaderInputLayout ::DataVal > val = new ShaderInputLayout ::DataVal ; 476 477uint32_t value = parser .ReadUInt (); 478if (negate ) 479value = uint32_t (- int32_t (value )); 480val -> bufferData .add (value ); 481 482return val ; 483 } 484break ; 485 486case Misc ::TokenType ::DoubleLiteral : 487 { 488RefPtr < ShaderInputLayout ::DataVal > val = new ShaderInputLayout ::DataVal ; 489 490float floatValue = parser .ReadFloat (); 491if (negate ) 492floatValue = - floatValue ; 493 494uint32_t value = 0 ; 495memcpy (& value ,& floatValue ,sizeof (floatValue )); 496val -> bufferData .add (value ); 497 498return val ; 499 } 500break ; 501 502default : 503throw ShaderInputLayoutFormatException ( 504String ("Expected a numeric literal but found '" )+ parser .NextToken ().Content + 505String ("' at line" )+ String (parser .NextToken ().Position .Line )); 506 } 507 } 508 509String parseTypeName (Misc ::TokenReader & parser ) 510 { 511String typeName = parser .ReadWord (); 512if (parser .AdvanceIf ("<" )) 513 { 514StringBuilder sb ; 515sb <<typeName <<"<" ; 516for (;;) 517 { 518if (parser .LookAhead (Misc ::TokenType ::IntLiteral )) 519sb <<parser .ReadInt (); 520else 521sb <<parseTypeName (parser ); 522if (!parser .AdvanceIf ("," )) 523break ; 524sb <<"," ; 525 } 526sb <<">" ; 527parser .Read (">" ); 528return sb .produceString (); 529 } 530return typeName ; 531 } 532 533RefPtr < ShaderInputLayout ::Val > parseValExpr (Misc ::TokenReader & parser ) 534 { 535typedef Misc ::TokenType TokenType ; 536 537switch (parser .NextToken ().Type ) 538 { 539case TokenType ::OpSub : 540 { 541parser .ReadToken (); 542return parseNumericValExpr (parser , true); 543 } 544break ; 545 546case TokenType ::IntLiteral : 547case TokenType ::DoubleLiteral : 548return parseNumericValExpr (parser ); 549 550case TokenType ::LBrace : 551 { 552// aggregate 553parser .ReadToken (); 554RefPtr < ShaderInputLayout ::AggVal > val = new ShaderInputLayout ::AggVal ; 555 556while (!parser .IsEnd ()&& !parser .LookAhead (TokenType ::RBrace )) 557 { 558ShaderInputLayout ::Field field ; 559 560if (parser .LookAhead (TokenType ::Identifier )&& 561parser .NextToken (1 ).Type == TokenType ::Colon ) 562 { 563field .name = parser .ReadWord (); 564parser .Read (TokenType ::Colon ); 565 } 566 567field .val = parseValExpr (parser ); 568 569val -> fields .add (field ); 570 571if (parser .LookAhead (TokenType ::RBrace )) 572break ; 573 574parser .Read (TokenType ::Comma ); 575 } 576parser .Read (TokenType ::RBrace ); 577 578 579return val ; 580 } 581break ; 582 583case TokenType ::LBracket : 584 { 585// array 586parser .ReadToken (); 587RefPtr < ShaderInputLayout ::ArrayVal > val = new ShaderInputLayout ::ArrayVal ; 588 589while (!parser .IsEnd ()&& !parser .LookAhead (TokenType ::RBracket )) 590 { 591val -> vals .add (parseValExpr (parser )); 592 593if (parser .LookAhead (TokenType ::RBracket )) 594break ; 595 596parser .Read (TokenType ::Comma ); 597 } 598parser .Read (TokenType ::RBracket ); 599 600return val ; 601 } 602break ; 603 604case TokenType ::Identifier : 605 { 606if (parser .AdvanceIf ("new" )) 607 { 608RefPtr < ShaderInputLayout ::ObjectVal > val = new ShaderInputLayout ::ObjectVal ; 609 610if (parser .NextToken ().Type == TokenType ::Identifier ) 611 { 612val -> typeName = parseTypeName (parser ); 613 } 614 615val -> contentVal = parseValExpr (parser ); 616return val ; 617 } 618else if (parser .AdvanceIf ("out" )) 619 { 620auto val = parseValExpr (parser ); 621val -> isOutput = true; 622return val ; 623 } 624else if (parser .AdvanceIf ("specialize" )) 625 { 626RefPtr < ShaderInputLayout ::SpecializeVal > val = 627new ShaderInputLayout ::SpecializeVal (); 628 629parser .Read (Misc ::TokenType ::LParent ); 630while (!parser .IsEnd ()&& parser .NextToken ().Type != Misc ::TokenType ::RParent ) 631 { 632val -> typeArgs .add (parseTypeName (parser )); 633if (!parser .AdvanceIf ("," )) 634break ; 635 } 636parser .Read (Misc ::TokenType ::RParent ); 637val -> contentVal = parseValExpr (parser ); 638return val ; 639 } 640else if (parser .AdvanceIf ("dynamic" )) 641 { 642RefPtr < ShaderInputLayout ::SpecializeVal > val = 643new ShaderInputLayout ::SpecializeVal (); 644val -> typeArgs .add ("__Dynamic" ); 645val -> contentVal = parseValExpr (parser ); 646return val ; 647 } 648else 649 { 650// We assume that any other word is introducing one of the other 651// cases for a parse-able value. 652return parseVal (parser ); 653 } 654 } 655break ; 656 657default : 658throw ShaderInputLayoutFormatException ( 659String ("Unexpected '" )+ parser .NextToken ().Content + String ("' at line " )+ 660String (parser .NextToken ().Position .Line )); 661 } 662 } 663 664RefPtr < ShaderInputLayout ::Val > parseVal (Misc ::TokenReader & parser ) 665 { 666auto nextToken = parser .NextToken (); 667auto word = nextToken .Content ; 668if (parser .AdvanceIf ("begin_array" )) 669 { 670RefPtr < ShaderInputLayout ::ArrayVal > val = new ShaderInputLayout ::ArrayVal ; 671pushParentVal (val ); 672return val ; 673 } 674else if (parser .AdvanceIf ("begin_object" )) 675 { 676RefPtr < ShaderInputLayout ::ObjectVal > val = new ShaderInputLayout ::ObjectVal ; 677maybeParseOptions (parser ,val .Ptr ()); 678 679RefPtr < ShaderInputLayout ::AggVal > contentVal = new ShaderInputLayout ::AggVal ; 680val -> contentVal = contentVal ; 681pushParentVal (contentVal ); 682 683return val ; 684 } 685else if (parser .AdvanceIf ("uniform" )) 686 { 687RefPtr < ShaderInputLayout ::DataVal > val = new ShaderInputLayout ::DataVal ; 688maybeParseOptions (parser ,val .Ptr ()); 689return val ; 690 } 691else if (parser .AdvanceIf ("cbuffer" )) 692 { 693// A `cbuffer` is basically just an object where the content of 694// the object is being provided by `uniform` data instead. 695 696RefPtr < ShaderInputLayout ::ObjectVal > objVal = new ShaderInputLayout ::ObjectVal ; 697 698RefPtr < ShaderInputLayout ::DataVal > dataVal = new ShaderInputLayout ::DataVal ; 699maybeParseOptions (parser ,dataVal .Ptr ()); 700 701objVal -> contentVal = dataVal ; 702 703return objVal ; 704 } 705else if (parser .AdvanceIf ("ubuffer" )) 706 { 707RefPtr < ShaderInputLayout ::BufferVal > val = new ShaderInputLayout ::BufferVal ; 708val -> bufferDesc .type = InputBufferType ::StorageBuffer ; 709maybeParseOptions (parser ,val .Ptr ()); 710return val ; 711 } 712else if (parser .AdvanceIf ("Texture1D" )) 713 { 714RefPtr < ShaderInputLayout ::TextureVal > val = new ShaderInputLayout ::TextureVal ; 715val -> textureDesc .dimension = 1 ; 716maybeParseOptions (parser ,val .Ptr ()); 717return val ; 718 } 719else if (parser .AdvanceIf ("RWTextureBuffer" )) 720 { 721RefPtr < ShaderInputLayout ::BufferVal > val = new ShaderInputLayout ::BufferVal ; 722val -> bufferDesc .type = InputBufferType ::StorageBuffer ; 723maybeParseOptions (parser ,val .Ptr ()); 724return val ; 725 } 726else if (parser .AdvanceIf ("Texture2D" )) 727 { 728RefPtr < ShaderInputLayout ::TextureVal > val = new ShaderInputLayout ::TextureVal ; 729val -> textureDesc .dimension = 2 ; 730maybeParseOptions (parser ,val .Ptr ()); 731return val ; 732 } 733else if (parser .AdvanceIf ("Texture3D" )) 734 { 735RefPtr < ShaderInputLayout ::TextureVal > val = new ShaderInputLayout ::TextureVal ; 736val -> textureDesc .dimension = 3 ; 737maybeParseOptions (parser ,val .Ptr ()); 738return val ; 739 } 740else if (parser .AdvanceIf ("TextureCube" )) 741 { 742RefPtr < ShaderInputLayout ::TextureVal > val = new ShaderInputLayout ::TextureVal ; 743val -> textureDesc .dimension = 2 ; 744val -> textureDesc .isCube = true; 745maybeParseOptions (parser ,val .Ptr ()); 746return val ; 747 } 748else if (parser .AdvanceIf ("RWTexture1D" )) 749 { 750RefPtr < ShaderInputLayout ::TextureVal > val = new ShaderInputLayout ::TextureVal ; 751val -> textureDesc .dimension = 1 ; 752val -> textureDesc .isRWTexture = true; 753maybeParseOptions (parser ,val .Ptr ()); 754return val ; 755 } 756else if (parser .AdvanceIf ("RWTexture2D" )) 757 { 758RefPtr < ShaderInputLayout ::TextureVal > val = new ShaderInputLayout ::TextureVal ; 759val -> textureDesc .dimension = 2 ; 760val -> textureDesc .isRWTexture = true; 761maybeParseOptions (parser ,val .Ptr ()); 762return val ; 763 } 764else if (parser .AdvanceIf ("RWTexture3D" )) 765 { 766RefPtr < ShaderInputLayout ::TextureVal > val = new ShaderInputLayout ::TextureVal ; 767val -> textureDesc .dimension = 3 ; 768val -> textureDesc .isRWTexture = true; 769maybeParseOptions (parser ,val .Ptr ()); 770return val ; 771 } 772else if (parser .AdvanceIf ("RWTextureCube" )) 773 { 774RefPtr < ShaderInputLayout ::TextureVal > val = new ShaderInputLayout ::TextureVal ; 775val -> textureDesc .dimension = 2 ; 776val -> textureDesc .isCube = true; 777val -> textureDesc .isRWTexture = true; 778maybeParseOptions (parser ,val .Ptr ()); 779return val ; 780 } 781else if (parser .AdvanceIf ("Sampler" )) 782 { 783RefPtr < ShaderInputLayout ::SamplerVal > val = new ShaderInputLayout ::SamplerVal ; 784maybeParseOptions (parser ,val .Ptr ()); 785return val ; 786 } 787else if (parser .AdvanceIf ("TextureSampler1D" )) 788 { 789RefPtr < ShaderInputLayout ::CombinedTextureSamplerVal > val = 790new ShaderInputLayout ::CombinedTextureSamplerVal ; 791val -> textureVal = new ShaderInputLayout ::TextureVal ; 792val -> samplerVal = new ShaderInputLayout ::SamplerVal ; 793val -> textureVal -> textureDesc .dimension = 1 ; 794maybeParseOptions (parser ,val .Ptr ()); 795return val ; 796 } 797else if (parser .AdvanceIf ("TextureSampler2D" )) 798 { 799RefPtr < ShaderInputLayout ::CombinedTextureSamplerVal > val = 800new ShaderInputLayout ::CombinedTextureSamplerVal ; 801val -> textureVal = new ShaderInputLayout ::TextureVal ; 802val -> samplerVal = new ShaderInputLayout ::SamplerVal ; 803val -> textureVal -> textureDesc .dimension = 2 ; 804maybeParseOptions (parser ,val .Ptr ()); 805return val ; 806 } 807else if (parser .AdvanceIf ("TextureSampler3D" )) 808 { 809RefPtr < ShaderInputLayout ::CombinedTextureSamplerVal > val = 810new ShaderInputLayout ::CombinedTextureSamplerVal ; 811val -> textureVal = new ShaderInputLayout ::TextureVal ; 812val -> samplerVal = new ShaderInputLayout ::SamplerVal ; 813val -> textureVal -> textureDesc .dimension = 3 ; 814maybeParseOptions (parser ,val .Ptr ()); 815return val ; 816 } 817else if (parser .AdvanceIf ("TextureSamplerCube" )) 818 { 819RefPtr < ShaderInputLayout ::CombinedTextureSamplerVal > val = 820new ShaderInputLayout ::CombinedTextureSamplerVal ; 821val -> textureVal = new ShaderInputLayout ::TextureVal ; 822val -> samplerVal = new ShaderInputLayout ::SamplerVal ; 823val -> textureVal -> textureDesc .dimension = 2 ; 824val -> textureVal -> textureDesc .isCube = true; 825maybeParseOptions (parser ,val .Ptr ()); 826return val ; 827 } 828else if (parser .AdvanceIf ("AccelerationStructure" )) 829 { 830RefPtr < ShaderInputLayout ::AccelerationStructureVal > val = 831new ShaderInputLayout ::AccelerationStructureVal (); 832return val ; 833 } 834else 835 { 836throw ShaderInputLayoutFormatException ( 837String ("Unknown shader input type '" )+ word + String ("' at line: " )+ 838String (nextToken .Position .Line )); 839 } 840parser .ReadToken (); 841return nullptr ; 842 } 843 844String parseName (Misc ::TokenReader & parser ) 845 { 846typedef Misc ::Token Token ; 847typedef Misc ::TokenType TokenType ; 848 849StringBuilder builder ; 850 851Token nameToken = parser .ReadToken (); 852if (nameToken .Type != TokenType ::Identifier ) 853 { 854throw ShaderInputLayoutFormatException ( 855StringBuilder () <<"Invalid input syntax at line " 856 <<parser .NextToken ().Position .Line ); 857 } 858builder <<nameToken .Content ; 859 860for (;;) 861 { 862Token token = parser .NextToken (0 ); 863 864if (token .Type == TokenType ::LBracket ) 865 { 866parser .ReadToken (); 867int index = parser .ReadInt (); 868SLANG_ASSERT (index >=0 ); 869parser .ReadMatchingToken (TokenType ::RBracket ); 870 871builder <<"[" <<index <<"]" ; 872 } 873else if (token .Type == TokenType ::Dot ) 874 { 875parser .ReadToken (); 876Token identifierToken = parser .ReadMatchingToken (TokenType ::Identifier ); 877 878builder <<"." <<identifierToken .Content ; 879 } 880else 881 { 882return builder ; 883 } 884 } 885 } 886 887void parseFieldBindings (Misc ::TokenReader & parser ,ShaderInputLayout ::Field & ioField ) 888 { 889// parse bindings 890if (parser .LookAhead (":" )) 891 { 892parser .Read (":" ); 893while (!parser .IsEnd ()) 894 { 895if (parser .AdvanceIf ("out" )) 896 { 897ioField .val -> isOutput = true; 898 } 899else if (parser .AdvanceIf ("name" )) 900 { 901// Optionally consume '=' 902if (parser .NextToken ().Type == Misc ::TokenType ::OpAssign ) 903 { 904parser .ReadToken (); 905 } 906 907ioField .name = parseName (parser ); 908 } 909else 910 { 911fprintf ( 912stderr , 913"Invalid TEST_INPUT syntax '%s'\n" , 914parser .NextToken ().Content .getBuffer ()); 915break ; 916 } 917 918if (parser .LookAhead ("," )) 919parser .Read ("," ); 920 } 921 } 922 } 923 924void pushParentVal (ShaderInputLayout ::ParentVal * val ) 925 { 926parentValStack .add (parentVal ); 927parentVal = val ; 928 } 929 930void parseValEntry (Misc ::TokenReader & parser ) 931 { 932auto parentForNewVal = parentVal ; 933 934ShaderInputLayout ::Field field ; 935field .val = parseVal (parser ); 936parseFieldBindings (parser ,field ); 937 938parentForNewVal -> addField (field ); 939 } 940 941void parseSetEntry (Misc ::TokenReader & parser ) 942 { 943auto parentForNewVal = parentVal ; 944 945ShaderInputLayout ::Field field ; 946field .name = parseName (parser ); 947parser .Read (Misc ::TokenType ::OpAssign ); 948field .val = parseValExpr (parser ); 949 950parentForNewVal -> addField (field ); 951 } 952 953void parseTypeConformance (Misc ::TokenReader & parser ) 954 { 955ShaderInputLayout ::TypeConformanceVal conformance ; 956conformance .derivedTypeName = parseTypeName (parser ); 957parser .Read (":" ); 958conformance .baseTypeName = parseTypeName (parser ); 959if (parser .AdvanceIf ("=" )) 960conformance .idOverride = parser .ReadInt (); 961layout -> typeConformances .add (conformance ); 962 } 963 964void parseLine (Misc ::TokenReader & parser ) 965 { 966if (parser .LookAhead ("entryPointSpecializationArg" )|| parser .LookAhead ("type" )|| 967parser .LookAhead ("entryPointExistentialType" )) 968 { 969parser .ReadToken (); 970StringBuilder typeExp ; 971while (!parser .IsEnd ()) 972typeExp <<parser .ReadToken ().Content ; 973layout -> entryPointSpecializationArgs .add (typeExp ); 974 } 975else if ( 976parser .LookAhead ("globalSpecializationArg" )|| parser .LookAhead ("global_type" )|| 977parser .LookAhead ("globalExistentialType" )) 978 { 979parser .ReadToken (); 980StringBuilder typeExp ; 981while (!parser .IsEnd ()) 982typeExp <<parser .ReadToken ().Content ; 983layout -> globalSpecializationArgs .add (typeExp ); 984 } 985else if (parser .AdvanceIf ("render_targets" )) 986 { 987layout -> numRenderTargets = parser .ReadInt (); 988 } 989else if (parser .AdvanceIf ("end" )) 990 { 991parentVal = parentValStack .getLast (); 992parentValStack .removeLast (); 993 } 994else if (parser .AdvanceIf ("set" )) 995 { 996parseSetEntry (parser ); 997 } 998else if (parser .AdvanceIf ("type_conformance" )) 999 { 1000parseTypeConformance (parser ); 1001 } 1002else 1003 { 1004parseValEntry (parser ); 1005 } 1006 } 1007 1008RefPtr < ShaderInputLayout ::AggVal > parse (const char * source ) 1009 { 1010RefPtr < ShaderInputLayout ::AggVal > rootVal = new ShaderInputLayout ::AggVal ; 1011parentVal = rootVal ; 1012 1013auto lines = Misc ::Split (source ,'\n' ); 1014int lineNum = 0 ; 1015for (auto & line :lines ) 1016 { 1017lineNum ++ ; 1018if (!line .startsWith ("//" )) 1019continue ; 1020line = line .getUnownedSlice ().tail (2 ).trim (); 1021if (line .startsWith ("TEST_INPUT:" )) 1022 { 1023auto lineContent = line .subString (11 ,line .getLength ()- 11 ); 1024Misc ::TokenReader parser (lineContent ); 1025try 1026 { 1027parseLine (parser ); 1028 } 1029catch (const Misc ::TextFormatException & ) 1030 { 1031StringBuilder msg ; 1032msg <<"Invalid input syntax at line " <<lineNum <<": " <<line ; 1033throw ShaderInputLayoutFormatException (msg ); 1034 } 1035 } 1036 } 1037 1038// TODO: check that stack has been maintained correctly... 1039 1040return rootVal ; 1041 } 1042}; 1043 1044void ShaderInputLayout ::parse (RandomGenerator * rand ,const char * source ) 1045{ 1046rootVal = nullptr ; 1047globalSpecializationArgs .clear (); 1048entryPointSpecializationArgs .clear (); 1049 1050ShaderInputLayoutParser parser (this ,rand ); 1051rootVal = parser .parse (source ); 1052} 1053 1054/* static */ SlangResult ShaderInputLayout ::writeBinding ( 1055 slang::TypeLayoutReflection * typeLayout , 1056const void * data , 1057size_t sizeInBytes , 1058WriterHelper writer ) 1059{ 1060typedef slang::TypeReflection ::ScalarType ScalarType ; 1061 1062 slang::TypeReflection ::ScalarType scalarType = slang::TypeReflection ::ScalarType ::None ; 1063 1064 slang::TypeLayoutReflection * elementTypeLayout = nullptr ; 1065 1066if (typeLayout ) 1067 { 1068switch (typeLayout -> getKind ()) 1069 { 1070 1071// case slang::TypeReflection::Kind::Struct: 1072case slang::TypeReflection ::Kind ::Array : 1073case slang::TypeReflection ::Kind ::Matrix : 1074case slang::TypeReflection ::Kind ::Vector : 1075 { 1076elementTypeLayout = typeLayout -> getElementTypeLayout (); 1077break ; 1078 } 1079case slang::TypeReflection ::Kind ::Scalar : 1080 { 1081elementTypeLayout = typeLayout ; 1082break ; 1083 } 1084case slang::TypeReflection ::Kind ::Resource : 1085 { 1086elementTypeLayout = typeLayout -> getElementTypeLayout (); 1087break ; 1088 } 1089case slang::TypeReflection ::Kind ::TextureBuffer : 1090case slang::TypeReflection ::Kind ::ShaderStorageBuffer : 1091 { 1092elementTypeLayout = typeLayout -> getElementTypeLayout (); 1093break ; 1094 } 1095 } 1096 } 1097 1098if (elementTypeLayout ) 1099 { 1100scalarType = elementTypeLayout -> getScalarType (); 1101 } 1102 1103if (scalarType != ScalarType ::None && scalarType != ScalarType ::Void ) 1104 { 1105UnownedStringSlice text = TypeTextUtil ::getScalarTypeName (scalarType ); 1106// Write out the type 1107writer .put ("type: " ); 1108writer .put (text ); 1109writer .put ("\n" ); 1110 } 1111 1112switch (scalarType ) 1113 { 1114// TODO(JS): 1115// Bool is here, because it's not clear across APIs how bool is laid out in memory 1116default : 1117case ScalarType ::None : 1118case ScalarType ::Void : 1119case ScalarType ::Bool : 1120 { 1121auto ptr = (const uint32_t * )data ; 1122const size_t size = sizeInBytes /sizeof (ptr [0 ]); 1123for (size_t i = 0 ;i < size ;++ i ) 1124 { 1125uint32_t v = ptr [i ]; 1126writer ."%X\n" ,v ); 1127 } 1128break ; 1129 } 1130case ScalarType ::Float16 : 1131 { 1132auto ptr = (const uint16_t * )data ; 1133const size_t size = sizeInBytes /sizeof (ptr [0 ]); 1134for (size_t i = 0 ;i < size ;++ i ) 1135 { 1136const float v = HalfToFloat (ptr [i ]); 1137writer ."%f\n" ,v ); 1138 } 1139break ; 1140 } 1141case ScalarType ::UInt32 : 1142 { 1143auto ptr = (const uint32_t * )data ; 1144const size_t size = sizeInBytes /sizeof (ptr [0 ]); 1145for (size_t i = 0 ;i < size ;++ i ) 1146 { 1147uint32_t v = ptr [i ]; 1148writer ."%u\n" ,v ); 1149 } 1150break ; 1151 } 1152case ScalarType ::Int32 : 1153 { 1154auto ptr = (const int32_t * )data ; 1155const size_t size = sizeInBytes /sizeof (ptr [0 ]); 1156for (size_t i = 0 ;i < size ;++ i ) 1157 { 1158int32_t v = ptr [i ]; 1159writer ."%i\n" ,v ); 1160 } 1161break ; 1162 } 1163case ScalarType ::Int64 : 1164 { 1165auto ptr = (const int64_t * )data ; 1166const size_t size = sizeInBytes /sizeof (ptr [0 ]); 1167for (size_t i = 0 ;i < size ;++ i ) 1168 { 1169int64_t v = ptr [i ]; 1170writer ."%" PRId64 "\n" ,v ); 1171 } 1172break ; 1173 } 1174case ScalarType ::UInt64 : 1175 { 1176auto ptr = (const uint64_t * )data ; 1177const size_t size = sizeInBytes /sizeof (ptr [0 ]); 1178for (size_t i = 0 ;i < size ;++ i ) 1179 { 1180uint64_t v = ptr [i ]; 1181writer ."%" PRIu64 "\n" ,v ); 1182 } 1183break ; 1184 } 1185case ScalarType ::Float32 : 1186 { 1187auto ptr = (const float * )data ; 1188const size_t size = sizeInBytes /sizeof (ptr [0 ]); 1189for (size_t i = 0 ;i < size ;++ i ) 1190 { 1191const float v = ptr [i ]; 1192writer ."%f\n" ,v ); 1193 } 1194break ; 1195 } 1196case ScalarType ::Float64 : 1197 { 1198auto ptr = (const double * )data ; 1199const size_t size = sizeInBytes /sizeof (ptr [0 ]); 1200for (size_t i = 0 ;i < size ;++ i ) 1201 { 1202const double v = ptr [i ]; 1203writer ."%f\n" ,v ); 1204 } 1205break ; 1206 } 1207 } 1208 1209return SLANG_OK ; 1210} 1211 1212void loadDataIntoHalf (uint16_t & out ,const uint8_t & in ) 1213{ 1214out = FloatToHalf ((float (in ) /255.0f )); 1215} 1216void loadDataIntoFloat (float & out ,const uint8_t & in ) 1217{ 1218out = (float (in ) /255.0f ); 1219} 1220template < typename T > 1221void loadDataIntoUint (T & out ,const uint8_t & in ) 1222{ 1223out = T (in ); 1224} 1225template < typename T > 1226void loadDataIntoInt (T & out ,const uint8_t & in ) 1227{ 1228out = T (in ); 1229} 1230 1231// T for type to return, F for function pointer to operate on uint8->T 1232template < typename T ,typename F > 1233void generateTextureDataWithTargetTStorage ( 1234TextureData & output , 1235const InputTextureDesc & desc , 1236const rhi::FormatInfo & formatInfo , 1237F loadUint8ToT ) 1238{ 1239// the following function assumes input of 0 or 1 since our testing framework only tests with 0 1240// or 1 1241TextureData work ; 1242generateTextureDataRGB8 (work ,desc ); 1243 1244output .init (desc .format ); 1245 1246output .m_textureSize = work .m_textureSize ; 1247output .m_mipLevels = work .m_mipLevels ; 1248output .m_arraySize = work .m_arraySize ; 1249 1250List < TextureData ::Slice >& dstSlices = output .m_slices ; 1251 1252Index numSlices = work .m_slices .getCount (); 1253dstSlices .setCount (numSlices ); 1254 1255for (int i = 0 ;i < numSlices ;++ i ) 1256 { 1257const TextureData ::Slice & srcSlice = work .m_slices [i ]; 1258 1259const Index pixelCount = srcSlice .valuesCount ; 1260const uint8_t * srcPixels = (const uint8_t * )srcSlice .values ; 1261 1262T * dstPixels = (T * )output .setSliceCount (i ,pixelCount ); 1263switch (formatInfo .channelCount ) 1264 { 1265case 1 : 1266 { 1267for (Index j = 0 ;j < pixelCount ;++ j ,srcPixels += 4 ,dstPixels += 1 ) 1268 { 1269// Copy out r 1270loadUint8ToT (dstPixels [0 ],srcPixels [0 ]); 1271 } 1272break ; 1273 } 1274case 2 : 1275 { 1276for (Index j = 0 ;j < pixelCount ;++ j ,srcPixels += 4 ,dstPixels += 2 ) 1277 { 1278// Copy out rg 1279loadUint8ToT (dstPixels [0 ],srcPixels [0 ]); 1280loadUint8ToT (dstPixels [1 ],srcPixels [1 ]); 1281 } 1282break ; 1283 } 1284case 3 : 1285 { 1286for (Index j = 0 ;j < pixelCount ;++ j ,srcPixels += 4 ,dstPixels += 3 ) 1287 { 1288// Copy out rgb 1289loadUint8ToT (dstPixels [0 ],srcPixels [0 ]); 1290loadUint8ToT (dstPixels [1 ],srcPixels [1 ]); 1291loadUint8ToT (dstPixels [2 ],srcPixels [2 ]); 1292 } 1293break ; 1294 } 1295case 4 : 1296 { 1297for (Index j = 0 ;j < pixelCount ;++ j ,srcPixels += 4 ,dstPixels += 4 ) 1298 { 1299// Copy out rgba 1300loadUint8ToT (dstPixels [0 ],srcPixels [0 ]); 1301loadUint8ToT (dstPixels [1 ],srcPixels [1 ]); 1302loadUint8ToT (dstPixels [2 ],srcPixels [2 ]); 1303loadUint8ToT (dstPixels [3 ],srcPixels [3 ]); 1304 } 1305break ; 1306 } 1307 } 1308 } 1309} 1310void generateTextureData (TextureData & output ,const InputTextureDesc & desc ) 1311{ 1312const FormatInfo & formatInfo = getFormatInfo (desc .format ); 1313 1314switch (desc .format ) 1315 { 1316case Format ::RGBA8Unorm : 1317 { 1318generateTextureDataRGB8 (output ,desc ); 1319break ; 1320 } 1321case Format ::R16Float : 1322case Format ::RG16Float : 1323case Format ::RGBA16Float : 1324 { 1325generateTextureDataWithTargetTStorage < uint16_t > ( 1326output , 1327desc , 1328formatInfo , 1329loadDataIntoHalf ); 1330break ; 1331 } 1332case Format ::R64Uint : 1333 { 1334generateTextureDataWithTargetTStorage < uint64_t > ( 1335output , 1336desc , 1337formatInfo , 1338loadDataIntoUint < uint64_t > ); 1339break ; 1340 } 1341case Format ::R32Float : 1342case Format ::RG32Float : 1343case Format ::RGB32Float : 1344case Format ::RGBA32Float : 1345case Format ::D32Float : 1346 { 1347generateTextureDataWithTargetTStorage < float > ( 1348output , 1349desc , 1350formatInfo , 1351loadDataIntoFloat ); 1352break ; 1353 } 1354case Format ::R32Uint : 1355case Format ::RG32Uint : 1356case Format ::RGB32Uint : 1357case Format ::RGBA32Uint : 1358 { 1359generateTextureDataWithTargetTStorage < uint32_t > ( 1360output , 1361desc , 1362formatInfo , 1363loadDataIntoUint < uint32_t > ); 1364break ; 1365 } 1366case Format ::R16Uint : 1367case Format ::RG16Uint : 1368case Format ::RGBA16Uint : 1369 { 1370generateTextureDataWithTargetTStorage < uint16_t > ( 1371output , 1372desc , 1373formatInfo , 1374loadDataIntoUint < uint16_t > ); 1375break ; 1376 } 1377case Format ::R8Uint : 1378case Format ::RG8Uint : 1379case Format ::RGBA8Uint : 1380 { 1381generateTextureDataWithTargetTStorage < uint8_t > ( 1382output , 1383desc , 1384formatInfo , 1385loadDataIntoUint < uint8_t > ); 1386break ; 1387 } 1388case Format ::R64Sint : 1389 { 1390generateTextureDataWithTargetTStorage < int64_t > ( 1391output , 1392desc , 1393formatInfo , 1394loadDataIntoInt < int64_t > ); 1395break ; 1396 } 1397case Format ::R32Sint : 1398case Format ::RG32Sint : 1399case Format ::RGB32Sint : 1400case Format ::RGBA32Sint : 1401 { 1402generateTextureDataWithTargetTStorage < int32_t > ( 1403output , 1404desc , 1405formatInfo , 1406loadDataIntoInt < int32_t > ); 1407break ; 1408 } 1409case Format ::R16Sint : 1410case Format ::RG16Sint : 1411case Format ::RGBA16Sint : 1412 { 1413generateTextureDataWithTargetTStorage < int16_t > ( 1414output , 1415desc , 1416formatInfo , 1417loadDataIntoInt < int16_t > ); 1418break ; 1419 } 1420case Format ::R8Sint : 1421case Format ::RG8Sint : 1422case Format ::RGBA8Sint : 1423 { 1424generateTextureDataWithTargetTStorage < int8_t > ( 1425output , 1426desc , 1427formatInfo , 1428loadDataIntoInt < int8_t > ); 1429break ; 1430 } 1431default : 1432 { 1433SLANG_ASSERT (!"Unhandled format" ); 1434break ; 1435 } 1436 } 1437} 1438 1439template < typename F > 1440void _iteratePixels (int dimension ,int size ,unsigned int * buffer ,F f ) 1441{ 1442if (dimension == 1 ) 1443for (int i = 0 ;i < size ;i ++ ) 1444buffer [i ]= f (i ,0 ,0 ); 1445else if (dimension == 2 ) 1446for (int i = 0 ;i < size ;i ++ ) 1447for (int j = 0 ;j < size ;j ++ ) 1448buffer [i * size + j ]= f (j ,i ,0 ); 1449else if (dimension == 3 ) 1450for (int i = 0 ;i < size ;i ++ ) 1451for (int j = 0 ;j < size ;j ++ ) 1452for (int k = 0 ;k < size ;k ++ ) 1453buffer [i * size * size + j * size + k ]= f (k ,j ,i ); 1454}; 1455 1456void generateTextureDataRGB8 (TextureData & output ,const InputTextureDesc & inputDesc ) 1457{ 1458int arrLen = inputDesc .arrayLength ; 1459if (arrLen == 0 ) 1460arrLen = 1 ; 1461 1462output .init (Format ::RGBA8Unorm ); 1463 1464enum class SimpleScalarType 1465 { 1466kUint , 1467kInt , 1468kFloat , 1469 }; 1470SimpleScalarType type ; 1471const rhi::FormatInfo & formatInfo = getFormatInfo (inputDesc .format ); 1472switch (formatInfo .channelType ) 1473 { 1474case SLANG_SCALAR_TYPE_UINT64 : 1475case SLANG_SCALAR_TYPE_UINT32 : 1476case SLANG_SCALAR_TYPE_UINT16 : 1477case SLANG_SCALAR_TYPE_UINT8 : 1478type = SimpleScalarType ::kUint ; 1479break ; 1480case SLANG_SCALAR_TYPE_INT64 : 1481case SLANG_SCALAR_TYPE_INT32 : 1482case SLANG_SCALAR_TYPE_INT16 : 1483case SLANG_SCALAR_TYPE_INT8 : 1484type = SimpleScalarType ::kInt ; 1485break ; 1486case SLANG_SCALAR_TYPE_FLOAT64 : 1487case SLANG_SCALAR_TYPE_FLOAT32 : 1488case SLANG_SCALAR_TYPE_FLOAT16 : 1489type = SimpleScalarType ::kFloat ; 1490break ; 1491default : 1492type = SimpleScalarType ::kUint ; 1493break ; 1494 } 1495// List<List<unsigned int>>& dataBuffer = output.dataBuffer; 1496int arraySize = arrLen ; 1497if (inputDesc .isCube ) 1498arraySize *=6 ; 1499output .m_arraySize = arraySize ; 1500output .m_textureSize = inputDesc .size ; 1501 1502const Index maxMipLevels = Math ::Log2Floor (output .m_textureSize )+ 1 ; 1503Index mipLevels = (inputDesc .mipMapCount <=0 ) ?maxMipLevels :inputDesc .mipMapCount ; 1504mipLevels = (mipLevels > maxMipLevels ) ?maxMipLevels :mipLevels ; 1505 1506output .m_mipLevels = int (mipLevels ); 1507output .m_slices .setCount (output .m_mipLevels * output .m_arraySize ); 1508 1509int slice = 0 ; 1510for (int i = 0 ;i < arraySize ;i ++ ) 1511 { 1512for (int j = 0 ;j < output .m_mipLevels ;j ++ ) 1513 { 1514int size = output .m_textureSize >>j ; 1515int bufferLen = size ; 1516if (inputDesc .dimension == 2 ) 1517bufferLen *=size ; 1518else if (inputDesc .dimension == 3 ) 1519bufferLen *=size * size ; 1520 1521uint32_t * dst = (uint32_t * )output .setSliceCount (slice ,bufferLen ); 1522 1523if (type == SimpleScalarType ::kFloat ) 1524_iteratePixels ( 1525inputDesc .dimension , 1526size , 1527dst , 1528 [& ](int x ,int y ,int z )-> unsigned int 1529 { 1530if (inputDesc .content == InputTextureContent ::Zero ) 1531 { 1532return 0x0 ; 1533 } 1534else if (inputDesc .content == InputTextureContent ::One ) 1535 { 1536return 0xFFFFFFFF ; 1537 } 1538else if (inputDesc .content == InputTextureContent ::Gradient ) 1539 { 1540unsigned char r = (unsigned char )(x / (float )(size - 1 )* 255.0f ); 1541unsigned char g = (unsigned char )(y / (float )(size - 1 )* 255.0f ); 1542unsigned char b = (unsigned char )(z / (float )(size - 1 )* 255.0f ); 1543return 0xFF000000 + r + (g <<8 )+ (b <<16 ); 1544 } 1545else if (inputDesc .content == InputTextureContent ::ChessBoard ) 1546 { 1547unsigned int xSig = x < (size >>1 ) ?1 :0 ; 1548unsigned int ySig = y < (size >>1 ) ?1 :0 ; 1549unsigned int zSig = z < (size >>1 ) ?1 :0 ; 1550auto sig = xSig ^ySig ^zSig ; 1551if (sig ) 1552return 0xFFFFFFFF ; 1553else 1554return 0xFF808080 ; 1555 } 1556return 0x0 ; 1557 }); 1558else if (type == SimpleScalarType ::kUint || type == SimpleScalarType ::kInt ) 1559_iteratePixels ( 1560inputDesc .dimension , 1561size , 1562dst , 1563 [& ](int x ,int y ,int z )-> unsigned int 1564 { 1565if (inputDesc .content == InputTextureContent ::Zero ) 1566 { 1567return 0x0 ; 1568 } 1569else if (inputDesc .content == InputTextureContent ::One ) 1570 { 1571return 0x01010101 ; 1572 } 1573else if (inputDesc .content == InputTextureContent ::Gradient ) 1574 { 1575unsigned char r = (unsigned char )(x / (float )(size - 1 )); 1576unsigned char g = (unsigned char )(y / (float )(size - 1 )); 1577unsigned char b = (unsigned char )(z / (float )(size - 1 )); 1578return 0x01000000 + r + (g <<8 )+ (b <<16 ); 1579 } 1580else if (inputDesc .content == InputTextureContent ::ChessBoard ) 1581 { 1582unsigned int xSig = x < (size >>1 ) ?1 :0 ; 1583unsigned int ySig = y < (size >>1 ) ?1 :0 ; 1584unsigned int zSig = z < (size >>1 ) ?1 :0 ; 1585auto sig = xSig ^ySig ^zSig ; 1586if (sig ) 1587return 0x01010101 ; 1588else 1589return 0x0 ; 1590 } 1591return 0x0 ; 1592 }); 1593slice ++ ; 1594 } 1595 } 1596} 1597}// namespace renderer_test