HLSL: phase 1: add RWTexture and RWBuffer

There's a lot to do for RWTexture and RWBuffer, so it will be broken up into
several PRs.  This is #1.

This adds RWTexture and RWBuffer support, with the following limitations:
  * Only 4 component formats supported
  * No operator[] yet

Those will be added in other PRs.

This PR supports declarations and the Load & GetDimensions methods.  New tests are
added.
diff --git a/hlsl/hlslGrammar.cpp b/hlsl/hlslGrammar.cpp
index b41618c..626d299 100755
--- a/hlsl/hlslGrammar.cpp
+++ b/hlsl/hlslGrammar.cpp
@@ -460,8 +460,14 @@
         // further, it can create an anonymous instance of the block
         if (peekTokenClass(EHTokSemicolon))
             parseContext.declareBlock(loc, type);
-    } else
+    } else {
+        // Some qualifiers are set when parsing the type.  Merge those with
+        // whatever comes from acceptQualifier.
+        assert(qualifier.layoutFormat == ElfNone);
+        qualifier.layoutFormat = type.getQualifier().layoutFormat;
+
         type.getQualifier() = qualifier;
+    }
 
     return true;
 }
@@ -827,6 +833,13 @@
 //      | TEXTURECUBEARRAY
 //      | TEXTURE2DMS
 //      | TEXTURE2DMSARRAY
+//      | RWBUFFER
+//      | RWTEXTURE1D
+//      | RWTEXTURE1DARRAY
+//      | RWTEXTURE2D
+//      | RWTEXTURE2DARRAY
+//      | RWTEXTURE3D
+
 bool HlslGrammar::acceptTextureType(TType& type)
 {
     const EHlslTokenClass textureType = peek();
@@ -834,6 +847,7 @@
     TSamplerDim dim = EsdNone;
     bool array = false;
     bool ms    = false;
+    bool image = false;
 
     switch (textureType) {
     case EHTokBuffer:            dim = EsdBuffer;                      break;
@@ -846,6 +860,12 @@
     case EHTokTextureCubearray:  dim = EsdCube; array = true;          break;
     case EHTokTexture2DMS:       dim = Esd2D; ms = true;               break;
     case EHTokTexture2DMSarray:  dim = Esd2D; array = true; ms = true; break;
+    case EHTokRWBuffer:          dim = EsdBuffer; image=true;          break;
+    case EHTokRWTexture1d:       dim = Esd1D; array=false; image=true; break;
+    case EHTokRWTexture1darray:  dim = Esd1D; array=true;  image=true; break;
+    case EHTokRWTexture2d:       dim = Esd2D; array=false; image=true; break;
+    case EHTokRWTexture2darray:  dim = Esd2D; array=true;  image=true; break;
+    case EHTokRWTexture3d:       dim = Esd3D; array=false; image=true; break;
     default:
         return false;  // not a texture declaration
     }
@@ -856,7 +876,7 @@
     
     TIntermTyped* msCount = nullptr;
 
-    // texture type: required for multisample types!
+    // texture type: required for multisample types and RWBuffer/RWTextures!
     if (acceptTokenClass(EHTokLeftAngle)) {
         if (! acceptType(txType)) {
             expected("scalar or vector type");
@@ -911,22 +931,45 @@
     } else if (ms) {
         expected("texture type for multisample");
         return false;
+    } else if (image) {
+        expected("type for RWTexture/RWBuffer");
+        return false;
     }
 
     TArraySizes* arraySizes = nullptr;
-    const bool shadow = txType.isScalar() || (txType.isVector() && txType.getVectorSize() == 1);
+    const bool shadow = !image && (txType.isScalar() || (txType.isVector() && txType.getVectorSize() == 1));
 
     TSampler sampler;
+    TLayoutFormat format = ElfNone;
 
-    // Buffers are combined.
-    if (dim == EsdBuffer) {
+    // RWBuffer and RWTexture (images) require a TLayoutFormat.  We handle only a limit set.
+    if (image) {
+        if (txType.getVectorSize() != 4)
+            expected("4 component image");
+
+        switch (txType.getBasicType()) {
+        case EbtFloat: format = ElfRgba32f;  break;
+        case EbtInt:   format = ElfRgba32i;  break;
+        case EbtUint:  format = ElfRgba32ui; break;
+        default:
+            expected("unknown basic type in image format");
+        }
+    }
+
+    // Non-image Buffers are combined
+    if (dim == EsdBuffer && !image) {
         sampler.set(txType.getBasicType(), dim, array);
     } else {
         // DX10 textures are separated.  TODO: DX9.
-        sampler.setTexture(txType.getBasicType(), dim, array, shadow, ms);
+        if (image) {
+            sampler.setImage(txType.getBasicType(), dim, array, shadow, ms);
+        } else {
+            sampler.setTexture(txType.getBasicType(), dim, array, shadow, ms);
+        }
     }
     
     type.shallowCopy(TType(sampler, EvqUniform, arraySizes));
+    type.getQualifier().layoutFormat = format;
 
     return true;
 }
@@ -966,6 +1009,12 @@
     case EHTokTextureCubearray:       // ...
     case EHTokTexture2DMS:            // ...
     case EHTokTexture2DMSarray:       // ...
+    case EHTokRWTexture1d:            // ...
+    case EHTokRWTexture1darray:       // ...
+    case EHTokRWTexture2d:            // ...
+    case EHTokRWTexture2darray:       // ...
+    case EHTokRWTexture3d:            // ...
+    case EHTokRWBuffer:               // ...
         return acceptTextureType(type);
         break;