| // | |
| // Copyright 2017 The ANGLE Project Authors. All rights reserved. | |
| // Use of this source code is governed by a BSD-style license that can be | |
| // found in the LICENSE file. | |
| // | |
| // ImageFunctionHLSL: Class for writing implementations of ESSL image functions into HLSL output. | |
| // | |
| #include "compiler/translator/ImageFunctionHLSL.h" | |
| #include "compiler/translator/ImmutableStringBuilder.h" | |
| #include "compiler/translator/UtilsHLSL.h" | |
| namespace sh | |
| { | |
| // static | |
| ImmutableString ImageFunctionHLSL::GetImageReference( | |
| TInfoSinkBase &out, | |
| const ImageFunctionHLSL::ImageFunction &imageFunction) | |
| { | |
| static const ImmutableString kImageIndexStr("[index]"); | |
| if (imageFunction.readonly) | |
| { | |
| static const ImmutableString kReadonlyImagesStr("readonlyImages"); | |
| ImmutableString suffix( | |
| TextureGroupSuffix(imageFunction.image, imageFunction.imageInternalFormat)); | |
| out << " const uint index = imageIndex - readonlyImageIndexOffset" << suffix.data() | |
| << ";\n"; | |
| ImmutableStringBuilder imageRefBuilder(kReadonlyImagesStr.length() + suffix.length() + | |
| kImageIndexStr.length()); | |
| imageRefBuilder << kReadonlyImagesStr << suffix << kImageIndexStr; | |
| return imageRefBuilder; | |
| } | |
| else | |
| { | |
| static const ImmutableString kImagesStr("images"); | |
| ImmutableString suffix( | |
| RWTextureGroupSuffix(imageFunction.image, imageFunction.imageInternalFormat)); | |
| out << " const uint index = imageIndex - imageIndexOffset" << suffix.data() << ";\n"; | |
| ImmutableStringBuilder imageRefBuilder(kImagesStr.length() + suffix.length() + | |
| kImageIndexStr.length()); | |
| imageRefBuilder << kImagesStr << suffix << kImageIndexStr; | |
| return imageRefBuilder; | |
| } | |
| } | |
| void ImageFunctionHLSL::OutputImageFunctionArgumentList( | |
| TInfoSinkBase &out, | |
| const ImageFunctionHLSL::ImageFunction &imageFunction) | |
| { | |
| out << "uint imageIndex"; | |
| if (imageFunction.method == ImageFunctionHLSL::ImageFunction::Method::LOAD || | |
| imageFunction.method == ImageFunctionHLSL::ImageFunction::Method::STORE) | |
| { | |
| switch (imageFunction.image) | |
| { | |
| case EbtImage2D: | |
| case EbtIImage2D: | |
| case EbtUImage2D: | |
| out << ", int2 p"; | |
| break; | |
| case EbtImage3D: | |
| case EbtIImage3D: | |
| case EbtUImage3D: | |
| case EbtImageCube: | |
| case EbtIImageCube: | |
| case EbtUImageCube: | |
| case EbtImage2DArray: | |
| case EbtIImage2DArray: | |
| case EbtUImage2DArray: | |
| out << ", int3 p"; | |
| break; | |
| default: | |
| UNREACHABLE(); | |
| } | |
| if (imageFunction.method == ImageFunctionHLSL::ImageFunction::Method::STORE) | |
| { | |
| switch (imageFunction.image) | |
| { | |
| case EbtImage2D: | |
| case EbtImage3D: | |
| case EbtImageCube: | |
| case EbtImage2DArray: | |
| out << ", float4 data"; | |
| break; | |
| case EbtIImage2D: | |
| case EbtIImage3D: | |
| case EbtIImageCube: | |
| case EbtIImage2DArray: | |
| out << ", int4 data"; | |
| break; | |
| case EbtUImage2D: | |
| case EbtUImage3D: | |
| case EbtUImageCube: | |
| case EbtUImage2DArray: | |
| out << ", uint4 data"; | |
| break; | |
| default: | |
| UNREACHABLE(); | |
| } | |
| } | |
| } | |
| } | |
| // static | |
| void ImageFunctionHLSL::OutputImageSizeFunctionBody( | |
| TInfoSinkBase &out, | |
| const ImageFunctionHLSL::ImageFunction &imageFunction, | |
| const ImmutableString &imageReference) | |
| { | |
| if (IsImage3D(imageFunction.image) || IsImage2DArray(imageFunction.image) || | |
| IsImageCube(imageFunction.image)) | |
| { | |
| // "depth" stores either the number of layers in an array texture or 3D depth | |
| out << " uint width; uint height; uint depth;\n" | |
| << " " << imageReference << ".GetDimensions(width, height, depth);\n"; | |
| } | |
| else if (IsImage2D(imageFunction.image)) | |
| { | |
| out << " uint width; uint height;\n" | |
| << " " << imageReference << ".GetDimensions(width, height);\n"; | |
| } | |
| else | |
| UNREACHABLE(); | |
| if (strcmp(imageFunction.getReturnType(), "int3") == 0) | |
| { | |
| out << " return int3(width, height, depth);\n"; | |
| } | |
| else | |
| { | |
| out << " return int2(width, height);\n"; | |
| } | |
| } | |
| // static | |
| void ImageFunctionHLSL::OutputImageLoadFunctionBody( | |
| TInfoSinkBase &out, | |
| const ImageFunctionHLSL::ImageFunction &imageFunction, | |
| const ImmutableString &imageReference) | |
| { | |
| if (IsImage3D(imageFunction.image) || IsImage2DArray(imageFunction.image) || | |
| IsImageCube(imageFunction.image)) | |
| { | |
| out << " return " << imageReference << "[uint3(p.x, p.y, p.z)];\n"; | |
| } | |
| else if (IsImage2D(imageFunction.image)) | |
| { | |
| out << " return " << imageReference << "[uint2(p.x, p.y)];\n"; | |
| } | |
| else | |
| UNREACHABLE(); | |
| } | |
| // static | |
| void ImageFunctionHLSL::OutputImageStoreFunctionBody( | |
| TInfoSinkBase &out, | |
| const ImageFunctionHLSL::ImageFunction &imageFunction, | |
| const ImmutableString &imageReference) | |
| { | |
| if (IsImage3D(imageFunction.image) || IsImage2DArray(imageFunction.image) || | |
| IsImage2D(imageFunction.image) || IsImageCube(imageFunction.image)) | |
| { | |
| out << " " << imageReference << "[p] = data;\n"; | |
| } | |
| else | |
| UNREACHABLE(); | |
| } | |
| ImmutableString ImageFunctionHLSL::ImageFunction::name() const | |
| { | |
| static const ImmutableString kGlImageName("gl_image"); | |
| ImmutableString suffix(nullptr); | |
| if (readonly) | |
| { | |
| suffix = ImmutableString(TextureTypeSuffix(image, imageInternalFormat)); | |
| } | |
| else | |
| { | |
| suffix = ImmutableString(RWTextureTypeSuffix(image, imageInternalFormat)); | |
| } | |
| ImmutableStringBuilder name(kGlImageName.length() + suffix.length() + 5u); | |
| name << kGlImageName << suffix; | |
| switch (method) | |
| { | |
| case Method::SIZE: | |
| name << "Size"; | |
| break; | |
| case Method::LOAD: | |
| name << "Load"; | |
| break; | |
| case Method::STORE: | |
| name << "Store"; | |
| break; | |
| default: | |
| UNREACHABLE(); | |
| } | |
| return name; | |
| } | |
| ImageFunctionHLSL::ImageFunction::DataType ImageFunctionHLSL::ImageFunction::getDataType( | |
| TLayoutImageInternalFormat format) const | |
| { | |
| switch (format) | |
| { | |
| case EiifRGBA32F: | |
| case EiifRGBA16F: | |
| case EiifR32F: | |
| return ImageFunction::DataType::FLOAT4; | |
| case EiifRGBA32UI: | |
| case EiifRGBA16UI: | |
| case EiifRGBA8UI: | |
| case EiifR32UI: | |
| return ImageFunction::DataType::UINT4; | |
| case EiifRGBA32I: | |
| case EiifRGBA16I: | |
| case EiifRGBA8I: | |
| case EiifR32I: | |
| return ImageFunction::DataType::INT4; | |
| case EiifRGBA8: | |
| return ImageFunction::DataType::UNORM_FLOAT4; | |
| case EiifRGBA8_SNORM: | |
| return ImageFunction::DataType::SNORM_FLOAT4; | |
| default: | |
| UNREACHABLE(); | |
| } | |
| return ImageFunction::DataType::NONE; | |
| } | |
| const char *ImageFunctionHLSL::ImageFunction::getReturnType() const | |
| { | |
| if (method == ImageFunction::Method::SIZE) | |
| { | |
| switch (image) | |
| { | |
| case EbtImage2D: | |
| case EbtIImage2D: | |
| case EbtUImage2D: | |
| case EbtImageCube: | |
| case EbtIImageCube: | |
| case EbtUImageCube: | |
| return "int2"; | |
| case EbtImage3D: | |
| case EbtIImage3D: | |
| case EbtUImage3D: | |
| case EbtImage2DArray: | |
| case EbtIImage2DArray: | |
| case EbtUImage2DArray: | |
| return "int3"; | |
| default: | |
| UNREACHABLE(); | |
| } | |
| } | |
| else if (method == ImageFunction::Method::LOAD) | |
| { | |
| switch (image) | |
| { | |
| case EbtImage2D: | |
| case EbtImage3D: | |
| case EbtImageCube: | |
| case EbtImage2DArray: | |
| return "float4"; | |
| case EbtIImage2D: | |
| case EbtIImage3D: | |
| case EbtIImageCube: | |
| case EbtIImage2DArray: | |
| return "int4"; | |
| case EbtUImage2D: | |
| case EbtUImage3D: | |
| case EbtUImageCube: | |
| case EbtUImage2DArray: | |
| return "uint4"; | |
| default: | |
| UNREACHABLE(); | |
| } | |
| } | |
| else if (method == ImageFunction::Method::STORE) | |
| { | |
| return "void"; | |
| } | |
| else | |
| { | |
| UNREACHABLE(); | |
| } | |
| return ""; | |
| } | |
| bool ImageFunctionHLSL::ImageFunction::operator<(const ImageFunction &rhs) const | |
| { | |
| return std::tie(image, type, method, readonly) < | |
| std::tie(rhs.image, rhs.type, rhs.method, rhs.readonly); | |
| } | |
| ImmutableString ImageFunctionHLSL::useImageFunction(const ImmutableString &name, | |
| const TBasicType &type, | |
| TLayoutImageInternalFormat imageInternalFormat, | |
| bool readonly) | |
| { | |
| ASSERT(IsImage(type)); | |
| ImageFunction imageFunction; | |
| imageFunction.image = type; | |
| imageFunction.imageInternalFormat = imageInternalFormat; | |
| imageFunction.readonly = readonly; | |
| imageFunction.type = imageFunction.getDataType(imageInternalFormat); | |
| if (name == "imageSize") | |
| { | |
| imageFunction.method = ImageFunction::Method::SIZE; | |
| } | |
| else if (name == "imageLoad") | |
| { | |
| imageFunction.method = ImageFunction::Method::LOAD; | |
| } | |
| else if (name == "imageStore") | |
| { | |
| imageFunction.method = ImageFunction::Method::STORE; | |
| } | |
| else | |
| UNREACHABLE(); | |
| mUsesImage.insert(imageFunction); | |
| return imageFunction.name(); | |
| } | |
| void ImageFunctionHLSL::imageFunctionHeader(TInfoSinkBase &out) | |
| { | |
| for (const ImageFunction &imageFunction : mUsesImage) | |
| { | |
| // Skip to generate image2D functions here, dynamically generate these | |
| // functions when linking, or after dispatch or draw. | |
| if (IsImage2D(imageFunction.image)) | |
| { | |
| mUsedImage2DFunctionNames.insert(imageFunction.name().data()); | |
| continue; | |
| } | |
| // Function header | |
| out << imageFunction.getReturnType() << " " << imageFunction.name() << "("; | |
| OutputImageFunctionArgumentList(out, imageFunction); | |
| out << ")\n" | |
| "{\n"; | |
| ImmutableString imageReference = GetImageReference(out, imageFunction); | |
| if (imageFunction.method == ImageFunction::Method::SIZE) | |
| { | |
| OutputImageSizeFunctionBody(out, imageFunction, imageReference); | |
| } | |
| else if (imageFunction.method == ImageFunction::Method::LOAD) | |
| { | |
| OutputImageLoadFunctionBody(out, imageFunction, imageReference); | |
| } | |
| else | |
| { | |
| OutputImageStoreFunctionBody(out, imageFunction, imageReference); | |
| } | |
| out << "}\n" | |
| "\n"; | |
| } | |
| } | |
| } // namespace sh |