1 //
2 // Copyright 2019 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 // DynamicImage2DHLSL.cpp: Implementation for link and run-time HLSL generation
7 //
8 
9 #include "libANGLE/renderer/d3d/DynamicImage2DHLSL.h"
10 
11 #include "common/string_utils.h"
12 #include "libANGLE/renderer/d3d/ProgramD3D.h"
13 #include "libANGLE/renderer/d3d/ShaderD3D.h"
14 
15 using namespace gl;
16 
17 namespace rx
18 {
19 
20 namespace
21 {
22 
23 enum Image2DHLSLGroup
24 {
25     IMAGE2D_R_FLOAT4,
26     IMAGE2D_MIN = IMAGE2D_R_FLOAT4,
27     IMAGE2D_R_UNORM,
28     IMAGE2D_R_SNORM,
29     IMAGE2D_R_UINT4,
30     IMAGE2D_R_INT4,
31     IMAGE2D_W_FLOAT4,
32     IMAGE2D_W_UNORM,
33     IMAGE2D_W_SNORM,
34     IMAGE2D_W_UINT4,
35     IMAGE2D_W_INT4,
36     IMAGE2D_UNKNOWN,
37     IMAGE2D_MAX = IMAGE2D_UNKNOWN
38 };
39 
40 enum Image2DMethod
41 {
42     IMAGE2DSIZE,
43     IMAGE2DLOAD,
44     IMAGE2DSTORE
45 };
46 
image2DHLSLGroup(const sh::ShaderVariable & uniform)47 Image2DHLSLGroup image2DHLSLGroup(const sh::ShaderVariable &uniform)
48 {
49     GLenum format = uniform.imageUnitFormat;
50     bool readonly = uniform.readonly;
51     switch (uniform.type)
52     {
53         case GL_IMAGE_2D:
54         {
55             switch (format)
56             {
57                 case GL_RGBA32F:
58                 case GL_RGBA16F:
59                 case GL_R32F:
60                     return readonly ? IMAGE2D_R_FLOAT4 : IMAGE2D_W_FLOAT4;
61                 case GL_RGBA8:
62                     return readonly ? IMAGE2D_R_UNORM : IMAGE2D_W_UNORM;
63                 case GL_RGBA8_SNORM:
64                     return readonly ? IMAGE2D_R_SNORM : IMAGE2D_W_SNORM;
65                 default:
66                     UNREACHABLE();
67                     return IMAGE2D_UNKNOWN;
68             }
69         }
70         case GL_INT_IMAGE_2D:
71         {
72             switch (format)
73             {
74                 case GL_RGBA32I:
75                 case GL_RGBA16I:
76                 case GL_RGBA8I:
77                 case GL_R32I:
78                     return readonly ? IMAGE2D_R_INT4 : IMAGE2D_W_INT4;
79                 default:
80                     UNREACHABLE();
81                     return IMAGE2D_UNKNOWN;
82             }
83         }
84         case GL_UNSIGNED_INT_IMAGE_2D:
85         {
86             switch (format)
87             {
88                 case GL_RGBA32UI:
89                 case GL_RGBA16UI:
90                 case GL_RGBA8UI:
91                 case GL_R32UI:
92                     return readonly ? IMAGE2D_R_UINT4 : IMAGE2D_W_UINT4;
93                 default:
94                     UNREACHABLE();
95                     return IMAGE2D_UNKNOWN;
96             }
97         }
98         default:
99             UNREACHABLE();
100             return IMAGE2D_UNKNOWN;
101     }
102 }
103 
Image2DHLSLGroupSuffix(Image2DHLSLGroup group)104 std::string Image2DHLSLGroupSuffix(Image2DHLSLGroup group)
105 {
106     switch (group)
107     {
108         case IMAGE2D_R_FLOAT4:
109             return "2D";
110         case IMAGE2D_R_UNORM:
111             return "2D_unorm_float4_";
112         case IMAGE2D_R_SNORM:
113             return "2D_snorm_float4_";
114         case IMAGE2D_R_UINT4:
115             return "2D_uint4_";
116         case IMAGE2D_R_INT4:
117             return "2D_int4_";
118         case IMAGE2D_W_FLOAT4:
119             return "RW2D_float4_";
120         case IMAGE2D_W_UNORM:
121             return "RW2D_unorm_float4_";
122         case IMAGE2D_W_SNORM:
123             return "RW2D_snorm_float4_";
124         case IMAGE2D_W_UINT4:
125             return "RW2D_uint4_";
126         case IMAGE2D_W_INT4:
127             return "RW2D_int4_";
128         default:
129             UNREACHABLE();
130     }
131 
132     return "<unknown group type>";
133 }
134 
Image2DHLSLTextureString(Image2DHLSLGroup group,gl::TextureType type)135 std::string Image2DHLSLTextureString(Image2DHLSLGroup group, gl::TextureType type)
136 {
137     std::string textureString;
138     switch (group)
139     {
140         case IMAGE2D_R_FLOAT4:
141         case IMAGE2D_R_UNORM:
142         case IMAGE2D_R_SNORM:
143         case IMAGE2D_R_UINT4:
144         case IMAGE2D_R_INT4:
145             break;
146         case IMAGE2D_W_FLOAT4:
147         case IMAGE2D_W_UNORM:
148         case IMAGE2D_W_SNORM:
149         case IMAGE2D_W_UINT4:
150         case IMAGE2D_W_INT4:
151             textureString += "RW";
152             break;
153         default:
154             UNREACHABLE();
155     }
156 
157     textureString += "Texture";
158 
159     switch (type)
160     {
161         case gl::TextureType::_2D:
162             textureString += "2D";
163             break;
164         case gl::TextureType::_3D:
165             textureString += "3D";
166             break;
167         case gl::TextureType::_2DArray:
168             textureString += "2DArray";
169             break;
170         default:
171             UNREACHABLE();
172     }
173 
174     switch (group)
175     {
176         case IMAGE2D_R_FLOAT4:
177         case IMAGE2D_W_FLOAT4:
178             textureString += "<float4>";
179             break;
180         case IMAGE2D_R_UNORM:
181         case IMAGE2D_W_UNORM:
182             textureString += "<unorm float4>";
183             break;
184         case IMAGE2D_R_SNORM:
185         case IMAGE2D_W_SNORM:
186             textureString += "<snorm float4>";
187             break;
188         case IMAGE2D_R_UINT4:
189         case IMAGE2D_W_UINT4:
190             textureString += "<uint4>";
191             break;
192         case IMAGE2D_R_INT4:
193         case IMAGE2D_W_INT4:
194             textureString += "<int4>";
195             break;
196         default:
197             UNREACHABLE();
198     }
199 
200     return textureString;
201 }
202 
Image2DHLSLGroupOffsetPrefix(Image2DHLSLGroup group)203 std::string Image2DHLSLGroupOffsetPrefix(Image2DHLSLGroup group)
204 {
205     switch (group)
206     {
207         case IMAGE2D_R_FLOAT4:
208         case IMAGE2D_R_UNORM:
209         case IMAGE2D_R_SNORM:
210         case IMAGE2D_R_UINT4:
211         case IMAGE2D_R_INT4:
212             return "readonlyImageIndexOffset";
213         case IMAGE2D_W_FLOAT4:
214         case IMAGE2D_W_UNORM:
215         case IMAGE2D_W_SNORM:
216         case IMAGE2D_W_UINT4:
217         case IMAGE2D_W_INT4:
218             return "imageIndexOffset";
219         default:
220             UNREACHABLE();
221     }
222 
223     return "<unknown group type>";
224 }
225 
Image2DHLSLGroupDeclarationPrefix(Image2DHLSLGroup group)226 std::string Image2DHLSLGroupDeclarationPrefix(Image2DHLSLGroup group)
227 {
228     switch (group)
229     {
230         case IMAGE2D_R_FLOAT4:
231         case IMAGE2D_R_UNORM:
232         case IMAGE2D_R_SNORM:
233         case IMAGE2D_R_UINT4:
234         case IMAGE2D_R_INT4:
235             return "readonlyImages";
236         case IMAGE2D_W_FLOAT4:
237         case IMAGE2D_W_UNORM:
238         case IMAGE2D_W_SNORM:
239         case IMAGE2D_W_UINT4:
240         case IMAGE2D_W_INT4:
241             return "images";
242         default:
243             UNREACHABLE();
244     }
245 
246     return "<unknown group type>";
247 }
248 
Image2DHLSLGroupRegisterSuffix(Image2DHLSLGroup group)249 std::string Image2DHLSLGroupRegisterSuffix(Image2DHLSLGroup group)
250 {
251     switch (group)
252     {
253         case IMAGE2D_R_FLOAT4:
254         case IMAGE2D_R_UNORM:
255         case IMAGE2D_R_SNORM:
256         case IMAGE2D_R_UINT4:
257         case IMAGE2D_R_INT4:
258             return "t";
259         case IMAGE2D_W_FLOAT4:
260         case IMAGE2D_W_UNORM:
261         case IMAGE2D_W_SNORM:
262         case IMAGE2D_W_UINT4:
263         case IMAGE2D_W_INT4:
264             return "u";
265         default:
266             UNREACHABLE();
267     }
268 
269     return "<unknown group type>";
270 }
271 
Image2DHLSLGroupFunctionName(Image2DHLSLGroup group,Image2DMethod method)272 std::string Image2DHLSLGroupFunctionName(Image2DHLSLGroup group, Image2DMethod method)
273 {
274     std::string name = "gl_image";
275     name += Image2DHLSLGroupSuffix(group);
276     switch (method)
277     {
278         case IMAGE2DSIZE:
279             name += "Size";
280             break;
281         case IMAGE2DLOAD:
282             name += "Load";
283             break;
284         case IMAGE2DSTORE:
285             name += "Store";
286             break;
287         default:
288             UNREACHABLE();
289     }
290 
291     return name;
292 }
293 
getImage2DGroupReturnType(Image2DHLSLGroup group,Image2DMethod method)294 std::string getImage2DGroupReturnType(Image2DHLSLGroup group, Image2DMethod method)
295 {
296     switch (method)
297     {
298         case IMAGE2DSIZE:
299             return "int2";
300         case IMAGE2DLOAD:
301             switch (group)
302             {
303                 case IMAGE2D_R_FLOAT4:
304                 case IMAGE2D_R_UNORM:
305                 case IMAGE2D_R_SNORM:
306                 case IMAGE2D_W_FLOAT4:
307                 case IMAGE2D_W_UNORM:
308                 case IMAGE2D_W_SNORM:
309                     return "float4";
310                 case IMAGE2D_R_UINT4:
311                 case IMAGE2D_W_UINT4:
312                     return "uint4";
313                 case IMAGE2D_R_INT4:
314                 case IMAGE2D_W_INT4:
315                     return "int4";
316                 default:
317                     UNREACHABLE();
318                     return "unknown group type";
319             }
320         case IMAGE2DSTORE:
321             return "void";
322         default:
323             UNREACHABLE();
324             return "unknown image method";
325     }
326 }
327 
getImageMetadata(Image2DHLSLGroup group)328 std::string getImageMetadata(Image2DHLSLGroup group)
329 {
330     switch (group)
331     {
332         case IMAGE2D_R_FLOAT4:
333         case IMAGE2D_R_UNORM:
334         case IMAGE2D_R_SNORM:
335         case IMAGE2D_R_UINT4:
336         case IMAGE2D_R_INT4:
337             return "readonlyImageMetadata[imageIndex - readonlyImageIndexStart]";
338         case IMAGE2D_W_FLOAT4:
339         case IMAGE2D_W_UNORM:
340         case IMAGE2D_W_SNORM:
341         case IMAGE2D_W_UINT4:
342         case IMAGE2D_W_INT4:
343             return "imageMetadata[imageIndex - imageIndexStart]";
344         default:
345             UNREACHABLE();
346             return "unknown image method";
347     }
348 }
349 
OutputImage2DFunctionArgumentList(std::ostringstream & out,Image2DHLSLGroup group,Image2DMethod method)350 void OutputImage2DFunctionArgumentList(std::ostringstream &out,
351                                        Image2DHLSLGroup group,
352                                        Image2DMethod method)
353 {
354     out << "uint imageIndex";
355 
356     if (method == IMAGE2DLOAD || method == IMAGE2DSTORE)
357     {
358         out << ", int2 p";
359         if (method == IMAGE2DSTORE)
360         {
361             switch (group)
362             {
363                 case IMAGE2D_R_FLOAT4:
364                 case IMAGE2D_R_UNORM:
365                 case IMAGE2D_R_SNORM:
366                 case IMAGE2D_W_FLOAT4:
367                 case IMAGE2D_W_UNORM:
368                 case IMAGE2D_W_SNORM:
369                     out << ", float4 data";
370                     break;
371                 case IMAGE2D_R_UINT4:
372                 case IMAGE2D_W_UINT4:
373                     out << ", uint4 data";
374                     break;
375                 case IMAGE2D_R_INT4:
376                 case IMAGE2D_W_INT4:
377                     out << ", int4 data";
378                     break;
379                 default:
380                     UNREACHABLE();
381             }
382         }
383     }
384 }
385 
OutputImage2DSizeFunction(std::ostringstream & out,Image2DHLSLGroup textureGroup,unsigned int totalCount,unsigned int texture2DCount,unsigned int texture3DCount,unsigned int texture2DArrayCount,const std::string & offsetStr,const std::string & declarationStr,bool getDimensionsIgnoresBaseLevel)386 void OutputImage2DSizeFunction(std::ostringstream &out,
387                                Image2DHLSLGroup textureGroup,
388                                unsigned int totalCount,
389                                unsigned int texture2DCount,
390                                unsigned int texture3DCount,
391                                unsigned int texture2DArrayCount,
392                                const std::string &offsetStr,
393                                const std::string &declarationStr,
394                                bool getDimensionsIgnoresBaseLevel)
395 {
396     out << getImage2DGroupReturnType(textureGroup, IMAGE2DSIZE) << " "
397         << Image2DHLSLGroupFunctionName(textureGroup, IMAGE2DSIZE) << "(";
398     OutputImage2DFunctionArgumentList(out, textureGroup, IMAGE2DSIZE);
399     out << ")\n"
400            "{\n";
401     out << "    uint width, height;\n";
402 
403     if (texture2DCount > 0)
404     {
405         if (texture2DCount == totalCount)
406         {
407             out << "    const uint index = imageIndex -  " << offsetStr << "2D;\n";
408             if (getDimensionsIgnoresBaseLevel)
409             {
410                 out << "    uint levelCount;\n";
411                 out << "    const uint level = " << getImageMetadata(textureGroup) << ".level;\n";
412                 out << "    " << declarationStr
413                     << "2D[index].GetDimensions(level, width, height, levelCount);\n";
414             }
415             else
416             {
417                 out << "    " << declarationStr << "2D[index].GetDimensions(width, height);\n";
418             }
419         }
420         else
421         {
422             out << "    if (imageIndex >= " << offsetStr << "2D && imageIndex < " << offsetStr
423                 << "2D + " << texture2DCount << ")\n";
424             out << "    {\n";
425             out << "        const uint index = imageIndex -  " << offsetStr << "2D;\n";
426             out << "        " << declarationStr << "2D[index].GetDimensions(width, height);\n";
427             out << "    }\n";
428         }
429     }
430 
431     if (texture3DCount > 0)
432     {
433         if (texture3DCount == totalCount)
434         {
435             out << "    const uint index = imageIndex -  " << offsetStr << "3D;\n";
436             out << "    uint depth;\n";
437             out << "    " << declarationStr << "3D[index].GetDimensions(width, height, depth);\n";
438         }
439         else
440         {
441             if (texture2DArrayCount == 0)
442             {
443                 out << "    else\n";
444             }
445             else
446             {
447                 if (texture2DCount == 0)
448                 {
449                     out << "    if ";
450                 }
451                 else
452                 {
453                     out << "    else if";
454                 }
455                 out << "(imageIndex >= " << offsetStr << "3D && imageIndex < " << offsetStr
456                     << "3D + " << texture3DCount << ")\n";
457             }
458             out << "    {\n";
459             out << "        const uint index = imageIndex -  " << offsetStr << "3D;\n";
460             out << "        uint depth;\n";
461             out << "        " << declarationStr
462                 << "3D[index].GetDimensions(width, height, depth);\n";
463             out << "    }\n";
464         }
465     }
466 
467     if (texture2DArrayCount > 0)
468     {
469         if (texture2DArrayCount == totalCount)
470         {
471             out << "    const uint index = imageIndex -  " << offsetStr << "2DArray;\n";
472             out << "    uint depth;\n";
473             out << "    " << declarationStr
474                 << "2DArray[index].GetDimensions(width, height, depth);\n";
475         }
476         else
477         {
478             out << "    else\n";
479             out << "    {\n";
480             out << "        const uint index = imageIndex -  " << offsetStr << "2DArray;\n";
481             out << "        uint depth;\n";
482             out << "        " << declarationStr
483                 << "2DArray[index].GetDimensions(width, height, depth);\n";
484             out << "    }\n";
485         }
486     }
487     out << "    return int2(width, height);\n";
488 
489     out << "}\n";
490 }
491 
OutputImage2DLoadFunction(std::ostringstream & out,Image2DHLSLGroup textureGroup,unsigned int totalCount,unsigned int texture2DCount,unsigned int texture3DCount,unsigned int texture2DArrayCount,const std::string & offsetStr,const std::string & declarationStr)492 void OutputImage2DLoadFunction(std::ostringstream &out,
493                                Image2DHLSLGroup textureGroup,
494                                unsigned int totalCount,
495                                unsigned int texture2DCount,
496                                unsigned int texture3DCount,
497                                unsigned int texture2DArrayCount,
498                                const std::string &offsetStr,
499                                const std::string &declarationStr)
500 {
501     out << getImage2DGroupReturnType(textureGroup, IMAGE2DLOAD) << " "
502         << Image2DHLSLGroupFunctionName(textureGroup, IMAGE2DLOAD) << "(";
503     OutputImage2DFunctionArgumentList(out, textureGroup, IMAGE2DLOAD);
504     out << ")\n"
505            "{\n";
506 
507     out << "    " << getImage2DGroupReturnType(textureGroup, IMAGE2DLOAD) << " result;\n";
508 
509     if (texture2DCount > 0)
510     {
511         if (texture2DCount == totalCount)
512         {
513             out << "    const uint index = imageIndex -  " << offsetStr << "2D;\n";
514             out << "    result = " << declarationStr << "2D[index][uint2(p.x, p.y)];\n";
515         }
516         else
517         {
518             out << "    if (imageIndex >= " << offsetStr << "2D && imageIndex < " << offsetStr
519                 << "2D + " << texture2DCount << ")\n";
520             out << "    {\n";
521             out << "        const uint index = imageIndex -  " << offsetStr << "2D;\n";
522             out << "        result = " << declarationStr << "2D[index][uint2(p.x, p.y)];\n";
523             out << "    }\n";
524         }
525     }
526 
527     if (texture3DCount > 0)
528     {
529         if (texture3DCount == totalCount)
530         {
531             out << "    const uint index = imageIndex -  " << offsetStr << "3D;\n";
532             out << "    result = " << declarationStr << "3D[index][uint3(p.x, p.y, "
533                 << getImageMetadata(textureGroup) << ".layer)];\n";
534         }
535         else
536         {
537             if (texture2DArrayCount == 0)
538             {
539                 out << "    else\n";
540             }
541             else
542             {
543                 if (texture2DCount == 0)
544                 {
545                     out << "    if ";
546                 }
547                 else
548                 {
549                     out << "    else if";
550                 }
551                 out << "(imageIndex >= " << offsetStr << "3D && imageIndex < " << offsetStr
552                     << "3D + " << texture3DCount << ")\n";
553             }
554             out << "    {\n";
555             out << "        const uint index = imageIndex -  " << offsetStr << "3D;\n";
556             out << "        result = " << declarationStr << "3D[index][uint3(p.x, p.y, "
557                 << getImageMetadata(textureGroup) << ".layer)];\n";
558             out << "    }\n";
559         }
560     }
561 
562     if (texture2DArrayCount > 0)
563     {
564         if (texture2DArrayCount == totalCount)
565         {
566             out << "    const uint index = imageIndex -  " << offsetStr << "2DArray;\n";
567             out << "    result = " << declarationStr << "2DArray[index][uint3(p.x, p.y, "
568                 << getImageMetadata(textureGroup) << ".layer)];\n";
569         }
570         else
571         {
572             out << "    else\n";
573             out << "    {\n";
574             out << "        const uint index = imageIndex -  " << offsetStr << "2DArray;\n";
575             out << "        result = " << declarationStr << "2DArray[index][uint3(p.x, p.y, "
576                 << getImageMetadata(textureGroup) << ".layer)];\n";
577             out << "    }\n";
578         }
579     }
580 
581     out << "    return result;\n";
582     out << "}\n";
583 }
584 
OutputImage2DStoreFunction(std::ostringstream & out,Image2DHLSLGroup textureGroup,unsigned int totalCount,unsigned int texture2DCount,unsigned int texture3DCount,unsigned int texture2DArrayCount,const std::string & offsetStr,const std::string & declarationStr)585 void OutputImage2DStoreFunction(std::ostringstream &out,
586                                 Image2DHLSLGroup textureGroup,
587                                 unsigned int totalCount,
588                                 unsigned int texture2DCount,
589                                 unsigned int texture3DCount,
590                                 unsigned int texture2DArrayCount,
591                                 const std::string &offsetStr,
592                                 const std::string &declarationStr)
593 {
594     out << getImage2DGroupReturnType(textureGroup, IMAGE2DSTORE) << " "
595         << Image2DHLSLGroupFunctionName(textureGroup, IMAGE2DSTORE) << "(";
596     OutputImage2DFunctionArgumentList(out, textureGroup, IMAGE2DSTORE);
597     out << ")\n"
598            "{\n";
599 
600     if (texture2DCount > 0)
601     {
602         if (texture2DCount == totalCount)
603         {
604             out << "    const uint index = imageIndex -  " << offsetStr << "2D;\n";
605             out << "    " << declarationStr << "2D[index][uint2(p.x, p.y)] = data;\n";
606         }
607         else
608         {
609             out << "    if (imageIndex >= " << offsetStr << "2D && imageIndex < " << offsetStr
610                 << "2D + " << texture2DCount << ")\n";
611             out << "    {\n";
612             out << "        const uint index = imageIndex -  " << offsetStr << "2D;\n";
613             out << "        " << declarationStr << "2D[index][uint2(p.x, p.y)] = data;\n";
614             out << "    }\n";
615         }
616     }
617 
618     if (texture3DCount > 0)
619     {
620         if (texture3DCount == totalCount)
621         {
622             out << "    const uint index = imageIndex -  " << offsetStr << "3D;\n";
623             out << "    " << declarationStr << "3D[index][uint3(p.x, p.y, "
624                 << getImageMetadata(textureGroup) << ".layer)] = data;\n";
625         }
626         else
627         {
628             if (texture2DArrayCount == 0)
629             {
630                 out << "    else\n";
631             }
632             else
633             {
634                 if (texture2DCount == 0)
635                 {
636                     out << "    if ";
637                 }
638                 else
639                 {
640                     out << "    else if";
641                 }
642                 out << "(imageIndex >= " << offsetStr << "3D && imageIndex < " << offsetStr
643                     << "3D + " << texture3DCount << ")\n";
644             }
645             out << "    {\n";
646             out << "        const uint index = imageIndex -  " << offsetStr << "3D;\n";
647             out << "        " << declarationStr << "3D[index][uint3(p.x, p.y, "
648                 << getImageMetadata(textureGroup) << ".layer)] = data;\n";
649             out << "    }\n";
650         }
651     }
652 
653     if (texture2DArrayCount > 0)
654     {
655         if (texture2DArrayCount == totalCount)
656         {
657             out << "    const uint index = imageIndex -  " << offsetStr << "2DArray;\n";
658             out << "    " << declarationStr << "2DArray[index][uint3(p.x, p.y, "
659                 << getImageMetadata(textureGroup) << ".layer)] = data;\n";
660         }
661         else
662         {
663             out << "    else\n";
664             out << "    {\n";
665             out << "        const uint index = imageIndex -  " << offsetStr << "2DArray;\n";
666             out << "        " << declarationStr << "2DArray[index][uint3(p.x, p.y, "
667                 << getImageMetadata(textureGroup) << ".layer)] = data;\n";
668             out << "    }\n";
669         }
670     }
671 
672     out << "}\n";
673 }
674 
GetImage2DRegisterIndex(Image2DHLSLGroup textureGroup,unsigned int * groupTextureRegisterIndex,unsigned int * groupRWTextureRegisterIndex)675 unsigned int *GetImage2DRegisterIndex(Image2DHLSLGroup textureGroup,
676                                       unsigned int *groupTextureRegisterIndex,
677                                       unsigned int *groupRWTextureRegisterIndex)
678 {
679     switch (textureGroup)
680     {
681         case IMAGE2D_R_FLOAT4:
682         case IMAGE2D_R_UNORM:
683         case IMAGE2D_R_SNORM:
684         case IMAGE2D_R_UINT4:
685         case IMAGE2D_R_INT4:
686             return groupTextureRegisterIndex;
687         case IMAGE2D_W_FLOAT4:
688         case IMAGE2D_W_UNORM:
689         case IMAGE2D_W_SNORM:
690         case IMAGE2D_W_UINT4:
691         case IMAGE2D_W_INT4:
692             return groupRWTextureRegisterIndex;
693         default:
694             UNREACHABLE();
695             return nullptr;
696     }
697 }
698 
OutputHLSLImage2DUniformGroup(ProgramD3D & programD3D,const gl::ProgramState & programData,gl::ShaderType shaderType,std::ostringstream & out,const Image2DHLSLGroup textureGroup,const std::vector<sh::ShaderVariable> & group,const gl::ImageUnitTextureTypeMap & image2DBindLayout,unsigned int * groupTextureRegisterIndex,unsigned int * groupRWTextureRegisterIndex,unsigned int * image2DTexture3D,unsigned int * image2DTexture2DArray,unsigned int * image2DTexture2D)699 void OutputHLSLImage2DUniformGroup(ProgramD3D &programD3D,
700                                    const gl::ProgramState &programData,
701                                    gl::ShaderType shaderType,
702                                    std::ostringstream &out,
703                                    const Image2DHLSLGroup textureGroup,
704                                    const std::vector<sh::ShaderVariable> &group,
705                                    const gl::ImageUnitTextureTypeMap &image2DBindLayout,
706                                    unsigned int *groupTextureRegisterIndex,
707                                    unsigned int *groupRWTextureRegisterIndex,
708                                    unsigned int *image2DTexture3D,
709                                    unsigned int *image2DTexture2DArray,
710                                    unsigned int *image2DTexture2D)
711 {
712     if (group.empty())
713     {
714         return;
715     }
716 
717     unsigned int texture2DCount = 0, texture3DCount = 0, texture2DArrayCount = 0;
718     for (const sh::ShaderVariable &uniform : group)
719     {
720         if (!programD3D.hasNamedUniform(uniform.name))
721         {
722             continue;
723         }
724         for (unsigned int index = 0; index < uniform.getArraySizeProduct(); index++)
725         {
726             switch (image2DBindLayout.at(uniform.binding + index))
727             {
728                 case gl::TextureType::_2D:
729                     texture2DCount++;
730                     break;
731                 case gl::TextureType::_3D:
732                     texture3DCount++;
733                     break;
734                 case gl::TextureType::_2DArray:
735                 case gl::TextureType::CubeMap:
736                     texture2DArrayCount++;
737                     break;
738                 default:
739                     UNREACHABLE();
740             }
741         }
742     }
743 
744     unsigned int totalCount            = texture2DCount + texture3DCount + texture2DArrayCount;
745     unsigned int *image2DRegisterIndex = GetImage2DRegisterIndex(
746         textureGroup, groupTextureRegisterIndex, groupRWTextureRegisterIndex);
747     unsigned int texture2DRegisterIndex      = *image2DRegisterIndex;
748     unsigned int texture3DRegisterIndex      = texture2DRegisterIndex + texture2DCount;
749     unsigned int texture2DArrayRegisterIndex = texture3DRegisterIndex + texture3DCount;
750     *image2DRegisterIndex += totalCount;
751 
752     std::string offsetStr =
753         Image2DHLSLGroupOffsetPrefix(textureGroup) + Image2DHLSLGroupSuffix(textureGroup);
754     std::string declarationStr =
755         Image2DHLSLGroupDeclarationPrefix(textureGroup) + Image2DHLSLGroupSuffix(textureGroup);
756     std::string registerStr = Image2DHLSLGroupRegisterSuffix(textureGroup);
757     if (texture2DCount > 0)
758     {
759         out << "static const uint " << offsetStr << "2D = " << texture2DRegisterIndex << ";\n";
760         out << "uniform " << Image2DHLSLTextureString(textureGroup, gl::TextureType::_2D) << " "
761             << declarationStr << "2D[" << texture2DCount << "]"
762             << " : register(" << registerStr << texture2DRegisterIndex << ");\n";
763     }
764     if (texture3DCount > 0)
765     {
766         out << "static const uint " << offsetStr << "3D = " << texture3DRegisterIndex << ";\n";
767         out << "uniform " << Image2DHLSLTextureString(textureGroup, gl::TextureType::_3D) << " "
768             << declarationStr << "3D[" << texture3DCount << "]"
769             << " : register(" << registerStr << texture3DRegisterIndex << ");\n";
770     }
771     if (texture2DArrayCount > 0)
772     {
773         out << "static const uint " << offsetStr << "2DArray = " << texture2DArrayRegisterIndex
774             << ";\n";
775         out << "uniform " << Image2DHLSLTextureString(textureGroup, gl::TextureType::_2DArray)
776             << " " << declarationStr << "2DArray[" << texture2DArrayCount << "]"
777             << " : register(" << registerStr << texture2DArrayRegisterIndex << ");\n";
778     }
779     for (const sh::ShaderVariable &uniform : group)
780     {
781         if (!programD3D.hasNamedUniform(uniform.name))
782         {
783             continue;
784         }
785 
786         out << "static const uint " << DecorateVariable(uniform.name)
787             << ArrayIndexString(uniform.arraySizes) << " = {";
788         for (unsigned int index = 0; index < uniform.getArraySizeProduct(); index++)
789         {
790             if (index > 0)
791             {
792                 out << ", ";
793             }
794             switch (image2DBindLayout.at(uniform.binding + index))
795             {
796                 case gl::TextureType::_2D:
797                 {
798                     out << texture2DRegisterIndex;
799                     programD3D.assignImage2DRegisters(texture2DRegisterIndex,
800                                                       uniform.binding + index, uniform.readonly);
801                     texture2DRegisterIndex++;
802                     break;
803                 }
804                 case gl::TextureType::_3D:
805                 {
806                     out << texture3DRegisterIndex;
807                     programD3D.assignImage2DRegisters(texture3DRegisterIndex,
808                                                       uniform.binding + index, uniform.readonly);
809                     texture3DRegisterIndex++;
810                     break;
811                 }
812                 case gl::TextureType::_2DArray:
813                 case gl::TextureType::CubeMap:
814                 {
815                     out << texture2DArrayRegisterIndex;
816                     programD3D.assignImage2DRegisters(texture2DArrayRegisterIndex,
817                                                       uniform.binding + index, uniform.readonly);
818                     texture2DArrayRegisterIndex++;
819                     break;
820                 }
821                 default:
822                     UNREACHABLE();
823             }
824         }
825         out << "};\n";
826     }
827 
828     gl::Shader *shaderGL                     = programData.getAttachedShader(shaderType);
829     const ShaderD3D *shaderD3D               = GetImplAs<ShaderD3D>(shaderGL);
830     const bool getDimensionsIgnoresBaseLevel = programD3D.usesGetDimensionsIgnoresBaseLevel();
831 
832     if (shaderD3D->useImage2DFunction(Image2DHLSLGroupFunctionName(textureGroup, IMAGE2DSIZE)))
833     {
834         OutputImage2DSizeFunction(out, textureGroup, totalCount, texture2DCount, texture3DCount,
835                                   texture2DArrayCount, offsetStr, declarationStr,
836                                   getDimensionsIgnoresBaseLevel);
837     }
838     if (shaderD3D->useImage2DFunction(Image2DHLSLGroupFunctionName(textureGroup, IMAGE2DLOAD)))
839     {
840         OutputImage2DLoadFunction(out, textureGroup, totalCount, texture2DCount, texture3DCount,
841                                   texture2DArrayCount, offsetStr, declarationStr);
842     }
843     if (shaderD3D->useImage2DFunction(Image2DHLSLGroupFunctionName(textureGroup, IMAGE2DSTORE)))
844     {
845         OutputImage2DStoreFunction(out, textureGroup, totalCount, texture2DCount, texture3DCount,
846                                    texture2DArrayCount, offsetStr, declarationStr);
847     }
848 }
849 
850 // kImage2DFunctionString must be the same as outputHLSL.
851 constexpr const char kImage2DFunctionString[] = "// @@ IMAGE2D DECLARATION FUNCTION STRING @@";
852 }  // anonymous namespace
853 
generateShaderForImage2DBindSignature(const d3d::Context * context,ProgramD3D & programD3D,const gl::ProgramState & programData,gl::ShaderType shaderType,std::vector<sh::ShaderVariable> & image2DUniforms,const gl::ImageUnitTextureTypeMap & image2DBindLayout)854 std::string generateShaderForImage2DBindSignature(
855     const d3d::Context *context,
856     ProgramD3D &programD3D,
857     const gl::ProgramState &programData,
858     gl::ShaderType shaderType,
859     std::vector<sh::ShaderVariable> &image2DUniforms,
860     const gl::ImageUnitTextureTypeMap &image2DBindLayout)
861 {
862     std::vector<std::vector<sh::ShaderVariable>> groupedImage2DUniforms(IMAGE2D_MAX + 1);
863     unsigned int image2DTexture2DCount = 0, image2DTexture3DCount = 0,
864                  image2DTexture2DArrayCount = 0;
865     for (sh::ShaderVariable &image2D : image2DUniforms)
866     {
867         for (unsigned int index = 0; index < image2D.getArraySizeProduct(); index++)
868         {
869             // Any image variable declared without a binding qualifier is initially bound to unit
870             // zero.
871             if (image2D.binding == -1)
872             {
873                 image2D.binding = 0;
874             }
875             switch (image2DBindLayout.at(image2D.binding + index))
876             {
877                 case gl::TextureType::_2D:
878                     image2DTexture2DCount++;
879                     break;
880                 case gl::TextureType::_3D:
881                     image2DTexture3DCount++;
882                     break;
883                 case gl::TextureType::_2DArray:
884                 case gl::TextureType::CubeMap:
885                     image2DTexture2DArrayCount++;
886                     break;
887                 default:
888                     UNREACHABLE();
889             }
890         }
891         Image2DHLSLGroup group = image2DHLSLGroup(image2D);
892         groupedImage2DUniforms[group].push_back(image2D);
893     }
894 
895     gl::Shader *shaderGL                     = programData.getAttachedShader(shaderType);
896     const ShaderD3D *shaderD3D               = GetImplAs<ShaderD3D>(shaderGL);
897     unsigned int groupTextureRegisterIndex   = shaderD3D->getReadonlyImage2DRegisterIndex();
898     unsigned int groupRWTextureRegisterIndex = shaderD3D->getImage2DRegisterIndex();
899     unsigned int image2DTexture3DIndex       = 0;
900     unsigned int image2DTexture2DArrayIndex  = image2DTexture3DCount;
901     unsigned int image2DTexture2DIndex       = image2DTexture3DCount + image2DTexture2DArrayCount;
902     std::ostringstream out;
903 
904     for (int groupId = IMAGE2D_MIN; groupId < IMAGE2D_MAX; ++groupId)
905     {
906         OutputHLSLImage2DUniformGroup(programD3D, programData, shaderType, out,
907                                       Image2DHLSLGroup(groupId), groupedImage2DUniforms[groupId],
908                                       image2DBindLayout, &groupTextureRegisterIndex,
909                                       &groupRWTextureRegisterIndex, &image2DTexture3DIndex,
910                                       &image2DTexture2DArrayIndex, &image2DTexture2DIndex);
911     }
912 
913     std::string shaderHLSL(programData.getAttachedShader(shaderType)->getTranslatedSource());
914     bool success = angle::ReplaceSubstring(&shaderHLSL, kImage2DFunctionString, out.str());
915     ASSERT(success);
916 
917     return shaderHLSL;
918 }
919 
920 }  // namespace rx
921