blob: d57e8f0ca5bb12f6137a935e3010b68576e2fae4 [file] [log] [blame]
//
// Copyright 2019 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.
//
// DynamicImage2DHLSL.cpp: Implementation for link and run-time HLSL generation
//
#include "libANGLE/renderer/d3d/DynamicImage2DHLSL.h"
#include "common/string_utils.h"
#include "libANGLE/renderer/d3d/ProgramD3D.h"
#include "libANGLE/renderer/d3d/ShaderD3D.h"
using namespace gl;
namespace rx
{
namespace
{
enum Image2DHLSLGroup
{
IMAGE2D_R_FLOAT4,
IMAGE2D_MIN = IMAGE2D_R_FLOAT4,
IMAGE2D_R_UNORM,
IMAGE2D_R_SNORM,
IMAGE2D_R_UINT4,
IMAGE2D_R_INT4,
IMAGE2D_W_FLOAT4,
IMAGE2D_W_UNORM,
IMAGE2D_W_SNORM,
IMAGE2D_W_UINT4,
IMAGE2D_W_INT4,
IMAGE2D_UNKNOWN,
IMAGE2D_MAX = IMAGE2D_UNKNOWN
};
enum Image2DMethod
{
IMAGE2DSIZE,
IMAGE2DLOAD,
IMAGE2DSTORE
};
Image2DHLSLGroup image2DHLSLGroup(const sh::ShaderVariable &uniform)
{
GLenum format = uniform.imageUnitFormat;
bool readonly = uniform.readonly;
switch (uniform.type)
{
case GL_IMAGE_2D:
{
switch (format)
{
case GL_RGBA32F:
case GL_RGBA16F:
case GL_R32F:
return readonly ? IMAGE2D_R_FLOAT4 : IMAGE2D_W_FLOAT4;
case GL_RGBA8:
return readonly ? IMAGE2D_R_UNORM : IMAGE2D_W_UNORM;
case GL_RGBA8_SNORM:
return readonly ? IMAGE2D_R_SNORM : IMAGE2D_W_SNORM;
default:
UNREACHABLE();
return IMAGE2D_UNKNOWN;
}
}
case GL_INT_IMAGE_2D:
{
switch (format)
{
case GL_RGBA32I:
case GL_RGBA16I:
case GL_RGBA8I:
case GL_R32I:
return readonly ? IMAGE2D_R_INT4 : IMAGE2D_W_INT4;
default:
UNREACHABLE();
return IMAGE2D_UNKNOWN;
}
}
case GL_UNSIGNED_INT_IMAGE_2D:
{
switch (format)
{
case GL_RGBA32UI:
case GL_RGBA16UI:
case GL_RGBA8UI:
case GL_R32UI:
return readonly ? IMAGE2D_R_UINT4 : IMAGE2D_W_UINT4;
default:
UNREACHABLE();
return IMAGE2D_UNKNOWN;
}
}
default:
UNREACHABLE();
return IMAGE2D_UNKNOWN;
}
}
std::string Image2DHLSLGroupSuffix(Image2DHLSLGroup group)
{
switch (group)
{
case IMAGE2D_R_FLOAT4:
return "2D";
case IMAGE2D_R_UNORM:
return "2D_unorm_float4_";
case IMAGE2D_R_SNORM:
return "2D_snorm_float4_";
case IMAGE2D_R_UINT4:
return "2D_uint4_";
case IMAGE2D_R_INT4:
return "2D_int4_";
case IMAGE2D_W_FLOAT4:
return "RW2D_float4_";
case IMAGE2D_W_UNORM:
return "RW2D_unorm_float4_";
case IMAGE2D_W_SNORM:
return "RW2D_snorm_float4_";
case IMAGE2D_W_UINT4:
return "RW2D_uint4_";
case IMAGE2D_W_INT4:
return "RW2D_int4_";
default:
UNREACHABLE();
}
return "<unknown group type>";
}
std::string Image2DHLSLTextureString(Image2DHLSLGroup group, gl::TextureType type)
{
std::string textureString;
switch (group)
{
case IMAGE2D_R_FLOAT4:
case IMAGE2D_R_UNORM:
case IMAGE2D_R_SNORM:
case IMAGE2D_R_UINT4:
case IMAGE2D_R_INT4:
break;
case IMAGE2D_W_FLOAT4:
case IMAGE2D_W_UNORM:
case IMAGE2D_W_SNORM:
case IMAGE2D_W_UINT4:
case IMAGE2D_W_INT4:
textureString += "RW";
break;
default:
UNREACHABLE();
}
textureString += "Texture";
switch (type)
{
case gl::TextureType::_2D:
textureString += "2D";
break;
case gl::TextureType::_3D:
textureString += "3D";
break;
case gl::TextureType::_2DArray:
textureString += "2DArray";
break;
default:
UNREACHABLE();
}
switch (group)
{
case IMAGE2D_R_FLOAT4:
case IMAGE2D_W_FLOAT4:
textureString += "<float4>";
break;
case IMAGE2D_R_UNORM:
case IMAGE2D_W_UNORM:
textureString += "<unorm float4>";
break;
case IMAGE2D_R_SNORM:
case IMAGE2D_W_SNORM:
textureString += "<snorm float4>";
break;
case IMAGE2D_R_UINT4:
case IMAGE2D_W_UINT4:
textureString += "<uint4>";
break;
case IMAGE2D_R_INT4:
case IMAGE2D_W_INT4:
textureString += "<int4>";
break;
default:
UNREACHABLE();
}
return textureString;
}
std::string Image2DHLSLGroupOffsetPrefix(Image2DHLSLGroup group)
{
switch (group)
{
case IMAGE2D_R_FLOAT4:
case IMAGE2D_R_UNORM:
case IMAGE2D_R_SNORM:
case IMAGE2D_R_UINT4:
case IMAGE2D_R_INT4:
return "readonlyImageIndexOffset";
case IMAGE2D_W_FLOAT4:
case IMAGE2D_W_UNORM:
case IMAGE2D_W_SNORM:
case IMAGE2D_W_UINT4:
case IMAGE2D_W_INT4:
return "imageIndexOffset";
default:
UNREACHABLE();
}
return "<unknown group type>";
}
std::string Image2DHLSLGroupDeclarationPrefix(Image2DHLSLGroup group)
{
switch (group)
{
case IMAGE2D_R_FLOAT4:
case IMAGE2D_R_UNORM:
case IMAGE2D_R_SNORM:
case IMAGE2D_R_UINT4:
case IMAGE2D_R_INT4:
return "readonlyImages";
case IMAGE2D_W_FLOAT4:
case IMAGE2D_W_UNORM:
case IMAGE2D_W_SNORM:
case IMAGE2D_W_UINT4:
case IMAGE2D_W_INT4:
return "images";
default:
UNREACHABLE();
}
return "<unknown group type>";
}
std::string Image2DHLSLGroupRegisterSuffix(Image2DHLSLGroup group)
{
switch (group)
{
case IMAGE2D_R_FLOAT4:
case IMAGE2D_R_UNORM:
case IMAGE2D_R_SNORM:
case IMAGE2D_R_UINT4:
case IMAGE2D_R_INT4:
return "t";
case IMAGE2D_W_FLOAT4:
case IMAGE2D_W_UNORM:
case IMAGE2D_W_SNORM:
case IMAGE2D_W_UINT4:
case IMAGE2D_W_INT4:
return "u";
default:
UNREACHABLE();
}
return "<unknown group type>";
}
std::string Image2DHLSLGroupFunctionName(Image2DHLSLGroup group, Image2DMethod method)
{
std::string name = "gl_image";
name += Image2DHLSLGroupSuffix(group);
switch (method)
{
case IMAGE2DSIZE:
name += "Size";
break;
case IMAGE2DLOAD:
name += "Load";
break;
case IMAGE2DSTORE:
name += "Store";
break;
default:
UNREACHABLE();
}
return name;
}
std::string getImage2DGroupReturnType(Image2DHLSLGroup group, Image2DMethod method)
{
switch (method)
{
case IMAGE2DSIZE:
return "int2";
case IMAGE2DLOAD:
switch (group)
{
case IMAGE2D_R_FLOAT4:
case IMAGE2D_R_UNORM:
case IMAGE2D_R_SNORM:
case IMAGE2D_W_FLOAT4:
case IMAGE2D_W_UNORM:
case IMAGE2D_W_SNORM:
return "float4";
case IMAGE2D_R_UINT4:
case IMAGE2D_W_UINT4:
return "uint4";
case IMAGE2D_R_INT4:
case IMAGE2D_W_INT4:
return "int4";
default:
UNREACHABLE();
return "unknown group type";
}
case IMAGE2DSTORE:
return "void";
default:
UNREACHABLE();
return "unknown image method";
}
}
std::string getImageMetadata(Image2DHLSLGroup group)
{
switch (group)
{
case IMAGE2D_R_FLOAT4:
case IMAGE2D_R_UNORM:
case IMAGE2D_R_SNORM:
case IMAGE2D_R_UINT4:
case IMAGE2D_R_INT4:
return "readonlyImageMetadata[imageIndex - readonlyImageIndexStart]";
case IMAGE2D_W_FLOAT4:
case IMAGE2D_W_UNORM:
case IMAGE2D_W_SNORM:
case IMAGE2D_W_UINT4:
case IMAGE2D_W_INT4:
return "imageMetadata[imageIndex - imageIndexStart]";
default:
UNREACHABLE();
return "unknown image method";
}
}
void OutputImage2DFunctionArgumentList(std::ostringstream &out,
Image2DHLSLGroup group,
Image2DMethod method)
{
out << "uint imageIndex";
if (method == IMAGE2DLOAD || method == IMAGE2DSTORE)
{
out << ", int2 p";
if (method == IMAGE2DSTORE)
{
switch (group)
{
case IMAGE2D_R_FLOAT4:
case IMAGE2D_R_UNORM:
case IMAGE2D_R_SNORM:
case IMAGE2D_W_FLOAT4:
case IMAGE2D_W_UNORM:
case IMAGE2D_W_SNORM:
out << ", float4 data";
break;
case IMAGE2D_R_UINT4:
case IMAGE2D_W_UINT4:
out << ", uint4 data";
break;
case IMAGE2D_R_INT4:
case IMAGE2D_W_INT4:
out << ", int4 data";
break;
default:
UNREACHABLE();
}
}
}
}
void 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)
{
out << getImage2DGroupReturnType(textureGroup, IMAGE2DSIZE) << " "
<< Image2DHLSLGroupFunctionName(textureGroup, IMAGE2DSIZE) << "(";
OutputImage2DFunctionArgumentList(out, textureGroup, IMAGE2DSIZE);
out << ")\n"
"{\n";
out << " uint width, height;\n";
if (texture2DCount > 0)
{
if (texture2DCount == totalCount)
{
out << " const uint index = imageIndex - " << offsetStr << "2D;\n";
if (getDimensionsIgnoresBaseLevel)
{
out << " uint levelCount;\n";
out << " const uint level = " << getImageMetadata(textureGroup) << ".level;\n";
out << " " << declarationStr
<< "2D[index].GetDimensions(level, width, height, levelCount);\n";
}
else
{
out << " " << declarationStr << "2D[index].GetDimensions(width, height);\n";
}
}
else
{
out << " if (imageIndex >= " << offsetStr << "2D && imageIndex < " << offsetStr
<< "2D + " << texture2DCount << ")\n";
out << " {\n";
out << " const uint index = imageIndex - " << offsetStr << "2D;\n";
out << " " << declarationStr << "2D[index].GetDimensions(width, height);\n";
out << " }\n";
}
}
if (texture3DCount > 0)
{
if (texture3DCount == totalCount)
{
out << " const uint index = imageIndex - " << offsetStr << "3D;\n";
out << " uint depth;\n";
out << " " << declarationStr << "3D[index].GetDimensions(width, height, depth);\n";
}
else
{
if (texture2DArrayCount == 0)
{
out << " else\n";
}
else
{
if (texture2DCount == 0)
{
out << " if ";
}
else
{
out << " else if";
}
out << "(imageIndex >= " << offsetStr << "3D && imageIndex < " << offsetStr
<< "3D + " << texture3DCount << ")\n";
}
out << " {\n";
out << " const uint index = imageIndex - " << offsetStr << "3D;\n";
out << " uint depth;\n";
out << " " << declarationStr
<< "3D[index].GetDimensions(width, height, depth);\n";
out << " }\n";
}
}
if (texture2DArrayCount > 0)
{
if (texture2DArrayCount == totalCount)
{
out << " const uint index = imageIndex - " << offsetStr << "2DArray;\n";
out << " uint depth;\n";
out << " " << declarationStr
<< "2DArray[index].GetDimensions(width, height, depth);\n";
}
else
{
out << " else\n";
out << " {\n";
out << " const uint index = imageIndex - " << offsetStr << "2DArray;\n";
out << " uint depth;\n";
out << " " << declarationStr
<< "2DArray[index].GetDimensions(width, height, depth);\n";
out << " }\n";
}
}
out << " return int2(width, height);\n";
out << "}\n";
}
void 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)
{
out << getImage2DGroupReturnType(textureGroup, IMAGE2DLOAD) << " "
<< Image2DHLSLGroupFunctionName(textureGroup, IMAGE2DLOAD) << "(";
OutputImage2DFunctionArgumentList(out, textureGroup, IMAGE2DLOAD);
out << ")\n"
"{\n";
out << " " << getImage2DGroupReturnType(textureGroup, IMAGE2DLOAD) << " result;\n";
if (texture2DCount > 0)
{
if (texture2DCount == totalCount)
{
out << " const uint index = imageIndex - " << offsetStr << "2D;\n";
out << " result = " << declarationStr << "2D[index][uint2(p.x, p.y)];\n";
}
else
{
out << " if (imageIndex >= " << offsetStr << "2D && imageIndex < " << offsetStr
<< "2D + " << texture2DCount << ")\n";
out << " {\n";
out << " const uint index = imageIndex - " << offsetStr << "2D;\n";
out << " result = " << declarationStr << "2D[index][uint2(p.x, p.y)];\n";
out << " }\n";
}
}
if (texture3DCount > 0)
{
if (texture3DCount == totalCount)
{
out << " const uint index = imageIndex - " << offsetStr << "3D;\n";
out << " result = " << declarationStr << "3D[index][uint3(p.x, p.y, "
<< getImageMetadata(textureGroup) << ".layer)];\n";
}
else
{
if (texture2DArrayCount == 0)
{
out << " else\n";
}
else
{
if (texture2DCount == 0)
{
out << " if ";
}
else
{
out << " else if";
}
out << "(imageIndex >= " << offsetStr << "3D && imageIndex < " << offsetStr
<< "3D + " << texture3DCount << ")\n";
}
out << " {\n";
out << " const uint index = imageIndex - " << offsetStr << "3D;\n";
out << " result = " << declarationStr << "3D[index][uint3(p.x, p.y, "
<< getImageMetadata(textureGroup) << ".layer)];\n";
out << " }\n";
}
}
if (texture2DArrayCount > 0)
{
if (texture2DArrayCount == totalCount)
{
out << " const uint index = imageIndex - " << offsetStr << "2DArray;\n";
out << " result = " << declarationStr << "2DArray[index][uint3(p.x, p.y, "
<< getImageMetadata(textureGroup) << ".layer)];\n";
}
else
{
out << " else\n";
out << " {\n";
out << " const uint index = imageIndex - " << offsetStr << "2DArray;\n";
out << " result = " << declarationStr << "2DArray[index][uint3(p.x, p.y, "
<< getImageMetadata(textureGroup) << ".layer)];\n";
out << " }\n";
}
}
out << " return result;\n";
out << "}\n";
}
void 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)
{
out << getImage2DGroupReturnType(textureGroup, IMAGE2DSTORE) << " "
<< Image2DHLSLGroupFunctionName(textureGroup, IMAGE2DSTORE) << "(";
OutputImage2DFunctionArgumentList(out, textureGroup, IMAGE2DSTORE);
out << ")\n"
"{\n";
if (texture2DCount > 0)
{
if (texture2DCount == totalCount)
{
out << " const uint index = imageIndex - " << offsetStr << "2D;\n";
out << " " << declarationStr << "2D[index][uint2(p.x, p.y)] = data;\n";
}
else
{
out << " if (imageIndex >= " << offsetStr << "2D && imageIndex < " << offsetStr
<< "2D + " << texture2DCount << ")\n";
out << " {\n";
out << " const uint index = imageIndex - " << offsetStr << "2D;\n";
out << " " << declarationStr << "2D[index][uint2(p.x, p.y)] = data;\n";
out << " }\n";
}
}
if (texture3DCount > 0)
{
if (texture3DCount == totalCount)
{
out << " const uint index = imageIndex - " << offsetStr << "3D;\n";
out << " " << declarationStr << "3D[index][uint3(p.x, p.y, "
<< getImageMetadata(textureGroup) << ".layer)] = data;\n";
}
else
{
if (texture2DArrayCount == 0)
{
out << " else\n";
}
else
{
if (texture2DCount == 0)
{
out << " if ";
}
else
{
out << " else if";
}
out << "(imageIndex >= " << offsetStr << "3D && imageIndex < " << offsetStr
<< "3D + " << texture3DCount << ")\n";
}
out << " {\n";
out << " const uint index = imageIndex - " << offsetStr << "3D;\n";
out << " " << declarationStr << "3D[index][uint3(p.x, p.y, "
<< getImageMetadata(textureGroup) << ".layer)] = data;\n";
out << " }\n";
}
}
if (texture2DArrayCount > 0)
{
if (texture2DArrayCount == totalCount)
{
out << " const uint index = imageIndex - " << offsetStr << "2DArray;\n";
out << " " << declarationStr << "2DArray[index][uint3(p.x, p.y, "
<< getImageMetadata(textureGroup) << ".layer)] = data;\n";
}
else
{
out << " else\n";
out << " {\n";
out << " const uint index = imageIndex - " << offsetStr << "2DArray;\n";
out << " " << declarationStr << "2DArray[index][uint3(p.x, p.y, "
<< getImageMetadata(textureGroup) << ".layer)] = data;\n";
out << " }\n";
}
}
out << "}\n";
}
unsigned int *GetImage2DRegisterIndex(Image2DHLSLGroup textureGroup,
unsigned int *groupTextureRegisterIndex,
unsigned int *groupRWTextureRegisterIndex)
{
switch (textureGroup)
{
case IMAGE2D_R_FLOAT4:
case IMAGE2D_R_UNORM:
case IMAGE2D_R_SNORM:
case IMAGE2D_R_UINT4:
case IMAGE2D_R_INT4:
return groupTextureRegisterIndex;
case IMAGE2D_W_FLOAT4:
case IMAGE2D_W_UNORM:
case IMAGE2D_W_SNORM:
case IMAGE2D_W_UINT4:
case IMAGE2D_W_INT4:
return groupRWTextureRegisterIndex;
default:
UNREACHABLE();
return nullptr;
}
}
void 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)
{
if (group.empty())
{
return;
}
unsigned int texture2DCount = 0, texture3DCount = 0, texture2DArrayCount = 0;
for (const sh::ShaderVariable &uniform : group)
{
if (!programD3D.hasNamedUniform(uniform.name))
{
continue;
}
for (unsigned int index = 0; index < uniform.getArraySizeProduct(); index++)
{
switch (image2DBindLayout.at(uniform.binding + index))
{
case gl::TextureType::_2D:
texture2DCount++;
break;
case gl::TextureType::_3D:
texture3DCount++;
break;
case gl::TextureType::_2DArray:
case gl::TextureType::CubeMap:
texture2DArrayCount++;
break;
default:
UNREACHABLE();
}
}
}
unsigned int totalCount = texture2DCount + texture3DCount + texture2DArrayCount;
unsigned int *image2DRegisterIndex = GetImage2DRegisterIndex(
textureGroup, groupTextureRegisterIndex, groupRWTextureRegisterIndex);
unsigned int texture2DRegisterIndex = *image2DRegisterIndex;
unsigned int texture3DRegisterIndex = texture2DRegisterIndex + texture2DCount;
unsigned int texture2DArrayRegisterIndex = texture3DRegisterIndex + texture3DCount;
*image2DRegisterIndex += totalCount;
std::string offsetStr =
Image2DHLSLGroupOffsetPrefix(textureGroup) + Image2DHLSLGroupSuffix(textureGroup);
std::string declarationStr =
Image2DHLSLGroupDeclarationPrefix(textureGroup) + Image2DHLSLGroupSuffix(textureGroup);
std::string registerStr = Image2DHLSLGroupRegisterSuffix(textureGroup);
if (texture2DCount > 0)
{
out << "static const uint " << offsetStr << "2D = " << texture2DRegisterIndex << ";\n";
out << "uniform " << Image2DHLSLTextureString(textureGroup, gl::TextureType::_2D) << " "
<< declarationStr << "2D[" << texture2DCount << "]"
<< " : register(" << registerStr << texture2DRegisterIndex << ");\n";
}
if (texture3DCount > 0)
{
out << "static const uint " << offsetStr << "3D = " << texture3DRegisterIndex << ";\n";
out << "uniform " << Image2DHLSLTextureString(textureGroup, gl::TextureType::_3D) << " "
<< declarationStr << "3D[" << texture3DCount << "]"
<< " : register(" << registerStr << texture3DRegisterIndex << ");\n";
}
if (texture2DArrayCount > 0)
{
out << "static const uint " << offsetStr << "2DArray = " << texture2DArrayRegisterIndex
<< ";\n";
out << "uniform " << Image2DHLSLTextureString(textureGroup, gl::TextureType::_2DArray)
<< " " << declarationStr << "2DArray[" << texture2DArrayCount << "]"
<< " : register(" << registerStr << texture2DArrayRegisterIndex << ");\n";
}
for (const sh::ShaderVariable &uniform : group)
{
if (!programD3D.hasNamedUniform(uniform.name))
{
continue;
}
out << "static const uint " << DecorateVariable(uniform.name)
<< ArrayIndexString(uniform.arraySizes) << " = {";
for (unsigned int index = 0; index < uniform.getArraySizeProduct(); index++)
{
if (index > 0)
{
out << ", ";
}
switch (image2DBindLayout.at(uniform.binding + index))
{
case gl::TextureType::_2D:
{
out << texture2DRegisterIndex;
programD3D.assignImage2DRegisters(texture2DRegisterIndex,
uniform.binding + index, uniform.readonly);
texture2DRegisterIndex++;
break;
}
case gl::TextureType::_3D:
{
out << texture3DRegisterIndex;
programD3D.assignImage2DRegisters(texture3DRegisterIndex,
uniform.binding + index, uniform.readonly);
texture3DRegisterIndex++;
break;
}
case gl::TextureType::_2DArray:
case gl::TextureType::CubeMap:
{
out << texture2DArrayRegisterIndex;
programD3D.assignImage2DRegisters(texture2DArrayRegisterIndex,
uniform.binding + index, uniform.readonly);
texture2DArrayRegisterIndex++;
break;
}
default:
UNREACHABLE();
}
}
out << "};\n";
}
gl::Shader *shaderGL = programData.getAttachedShader(shaderType);
const ShaderD3D *shaderD3D = GetImplAs<ShaderD3D>(shaderGL);
const bool getDimensionsIgnoresBaseLevel = programD3D.usesGetDimensionsIgnoresBaseLevel();
if (shaderD3D->useImage2DFunction(Image2DHLSLGroupFunctionName(textureGroup, IMAGE2DSIZE)))
{
OutputImage2DSizeFunction(out, textureGroup, totalCount, texture2DCount, texture3DCount,
texture2DArrayCount, offsetStr, declarationStr,
getDimensionsIgnoresBaseLevel);
}
if (shaderD3D->useImage2DFunction(Image2DHLSLGroupFunctionName(textureGroup, IMAGE2DLOAD)))
{
OutputImage2DLoadFunction(out, textureGroup, totalCount, texture2DCount, texture3DCount,
texture2DArrayCount, offsetStr, declarationStr);
}
if (shaderD3D->useImage2DFunction(Image2DHLSLGroupFunctionName(textureGroup, IMAGE2DSTORE)))
{
OutputImage2DStoreFunction(out, textureGroup, totalCount, texture2DCount, texture3DCount,
texture2DArrayCount, offsetStr, declarationStr);
}
}
// kImage2DFunctionString must be the same as outputHLSL.
constexpr const char kImage2DFunctionString[] = "// @@ IMAGE2D DECLARATION FUNCTION STRING @@";
} // anonymous namespace
std::string generateShaderForImage2DBindSignature(
const d3d::Context *context,
ProgramD3D &programD3D,
const gl::ProgramState &programData,
gl::ShaderType shaderType,
std::vector<sh::ShaderVariable> &image2DUniforms,
const gl::ImageUnitTextureTypeMap &image2DBindLayout)
{
std::vector<std::vector<sh::ShaderVariable>> groupedImage2DUniforms(IMAGE2D_MAX + 1);
unsigned int image2DTexture2DCount = 0, image2DTexture3DCount = 0,
image2DTexture2DArrayCount = 0;
for (sh::ShaderVariable &image2D : image2DUniforms)
{
for (unsigned int index = 0; index < image2D.getArraySizeProduct(); index++)
{
// Any image variable declared without a binding qualifier is initially bound to unit
// zero.
if (image2D.binding == -1)
{
image2D.binding = 0;
}
switch (image2DBindLayout.at(image2D.binding + index))
{
case gl::TextureType::_2D:
image2DTexture2DCount++;
break;
case gl::TextureType::_3D:
image2DTexture3DCount++;
break;
case gl::TextureType::_2DArray:
case gl::TextureType::CubeMap:
image2DTexture2DArrayCount++;
break;
default:
UNREACHABLE();
}
}
Image2DHLSLGroup group = image2DHLSLGroup(image2D);
groupedImage2DUniforms[group].push_back(image2D);
}
gl::Shader *shaderGL = programData.getAttachedShader(shaderType);
const ShaderD3D *shaderD3D = GetImplAs<ShaderD3D>(shaderGL);
unsigned int groupTextureRegisterIndex = shaderD3D->getReadonlyImage2DRegisterIndex();
unsigned int groupRWTextureRegisterIndex = shaderD3D->getImage2DRegisterIndex();
unsigned int image2DTexture3DIndex = 0;
unsigned int image2DTexture2DArrayIndex = image2DTexture3DCount;
unsigned int image2DTexture2DIndex = image2DTexture3DCount + image2DTexture2DArrayCount;
std::ostringstream out;
for (int groupId = IMAGE2D_MIN; groupId < IMAGE2D_MAX; ++groupId)
{
OutputHLSLImage2DUniformGroup(programD3D, programData, shaderType, out,
Image2DHLSLGroup(groupId), groupedImage2DUniforms[groupId],
image2DBindLayout, &groupTextureRegisterIndex,
&groupRWTextureRegisterIndex, &image2DTexture3DIndex,
&image2DTexture2DArrayIndex, &image2DTexture2DIndex);
}
std::string shaderHLSL(programData.getAttachedShader(shaderType)->getTranslatedSource());
bool success = angle::ReplaceSubstring(&shaderHLSL, kImage2DFunctionString, out.str());
ASSERT(success);
return shaderHLSL;
}
} // namespace rx