// // Copyright (c) 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/UtilsHLSL.h" namespace sh { // static void ImageFunctionHLSL::OutputImageFunctionArgumentList( TInfoSinkBase &out, const ImageFunctionHLSL::ImageFunction &imageFunction) { if (imageFunction.readonly) { out << TextureString(imageFunction.image, imageFunction.imageInternalFormat) << " tex"; } else { out << RWTextureString(imageFunction.image, imageFunction.imageInternalFormat) << " tex"; } 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 TString &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 TString &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 TString &imageReference) { if (IsImage3D(imageFunction.image) || IsImage2DArray(imageFunction.image) || IsImage2D(imageFunction.image) || IsImageCube(imageFunction.image)) { out << " " << imageReference << "[p] = data;\n"; } else UNREACHABLE(); } TString ImageFunctionHLSL::ImageFunction::name() const { TString name = "gl_image"; if (readonly) { name += TextureTypeSuffix(image, imageInternalFormat); } else { name += RWTextureTypeSuffix(image, imageInternalFormat); } switch (method) { case Method::SIZE: name += "Size"; break; case Method::LOAD: name += "Load"; break; case Method::STORE: name += "Store"; break; default: UNREACHABLE(); } return name; } 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, imageInternalFormat, readonly, method) < std::tie(rhs.image, rhs.imageInternalFormat, rhs.readonly, rhs.method); } TString ImageFunctionHLSL::useImageFunction(const TString &name, const TBasicType &type, TLayoutImageInternalFormat imageInternalFormat, bool readonly) { ASSERT(IsImage(type)); ImageFunction imageFunction; imageFunction.image = type; imageFunction.imageInternalFormat = imageInternalFormat; imageFunction.readonly = readonly; 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) { // Function header out << imageFunction.getReturnType() << " " << imageFunction.name() << "("; OutputImageFunctionArgumentList(out, imageFunction); out << ")\n" "{\n"; TString imageReference("tex"); 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