blob: 40b5e1f1e2ab4fd5fa5bd3a7f9f8bbec763a559a [file] [log] [blame]
//
// 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