Commit 2cd9d7e0 by Xinghua Cao Committed by Commit Bot

D3D11: Add support to compile and link compute shaders.

BUG=angleproject:1442 Change-Id: I13240e931e6f121d175d2cd6b41324d38bb39a5c Reviewed-on: https://chromium-review.googlesource.com/405831 Commit-Queue: Jamie Madill <jmadill@chromium.org> Reviewed-by: 's avatarGeoff Lang <geofflang@chromium.org> Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org>
parent e7d8432d
......@@ -115,6 +115,11 @@ OutputHLSL::OutputHLSL(sh::GLenum shaderType,
mUsesInstanceID = false;
mUsesVertexID = false;
mUsesFragDepth = false;
mUsesNumWorkGroups = false;
mUsesWorkGroupID = false;
mUsesLocalInvocationID = false;
mUsesGlobalInvocationID = false;
mUsesLocalInvocationIndex = false;
mUsesXor = false;
mUsesDiscardRewriting = false;
mUsesNestedBreak = false;
......@@ -540,7 +545,7 @@ void OutputHLSL::header(TInfoSinkBase &out, const BuiltInFunctionEmulator *built
out << "#define GL_USES_FRAG_DATA\n";
}
}
else // Vertex shader
else if (mShaderType == GL_VERTEX_SHADER)
{
out << "// Attributes\n";
out << attributes;
......@@ -631,6 +636,40 @@ void OutputHLSL::header(TInfoSinkBase &out, const BuiltInFunctionEmulator *built
out << "\n";
}
}
else // Compute shader
{
ASSERT(mShaderType == GL_COMPUTE_SHADER);
if (mUsesNumWorkGroups)
{
out << "cbuffer DriverConstants : register(b1)\n"
"{\n";
out << " uint3 gl_NumWorkGroups : packoffset(c0);\n";
out << "};\n";
}
// Follow built-in variables would be initialized in
// DynamicHLSL::generateComputeShaderLinkHLSL, if they
// are used in compute shader.
if (mUsesWorkGroupID)
{
out << "static uint3 gl_WorkGroupID = uint3(0, 0, 0);\n";
}
if (mUsesLocalInvocationID)
{
out << "static uint3 gl_LocalInvocationID = uint3(0, 0, 0);\n";
}
if (mUsesGlobalInvocationID)
{
out << "static uint3 gl_GlobalInvocationID = uint3(0, 0, 0);\n";
}
if (mUsesLocalInvocationIndex)
{
out << "static uint gl_LocalInvocationIndex = uint(0);\n";
}
}
bool getDimensionsIgnoresBaseLevel =
(mCompileOptions & SH_HLSL_GET_DIMENSIONS_IGNORES_BASE_LEVEL) != 0;
......@@ -666,6 +705,31 @@ void OutputHLSL::header(TInfoSinkBase &out, const BuiltInFunctionEmulator *built
out << "#define GL_USES_DEPTH_RANGE\n";
}
if (mUsesNumWorkGroups)
{
out << "#define GL_USES_NUM_WORK_GROUPS\n";
}
if (mUsesWorkGroupID)
{
out << "#define GL_USES_WORK_GROUP_ID\n";
}
if (mUsesLocalInvocationID)
{
out << "#define GL_USES_LOCAL_INVOCATION_ID\n";
}
if (mUsesGlobalInvocationID)
{
out << "#define GL_USES_GLOBAL_INVOCATION_ID\n";
}
if (mUsesLocalInvocationIndex)
{
out << "#define GL_USES_LOCAL_INVOCATION_INDEX\n";
}
if (mUsesXor)
{
out << "bool xor(bool p, bool q)\n"
......@@ -779,6 +843,31 @@ void OutputHLSL::visitSymbol(TIntermSymbol *node)
mUsesFragDepth = true;
out << "gl_Depth";
}
else if (qualifier == EvqNumWorkGroups)
{
mUsesNumWorkGroups = true;
out << name;
}
else if (qualifier == EvqWorkGroupID)
{
mUsesWorkGroupID = true;
out << name;
}
else if (qualifier == EvqLocalInvocationID)
{
mUsesLocalInvocationID = true;
out << name;
}
else if (qualifier == EvqGlobalInvocationID)
{
mUsesGlobalInvocationID = true;
out << name;
}
else if (qualifier == EvqLocalInvocationIndex)
{
mUsesLocalInvocationIndex = true;
out << name;
}
else
{
out << DecorateIfNeeded(node->getName());
......
......@@ -173,6 +173,11 @@ class OutputHLSL : public TIntermTraverser
bool mUsesInstanceID;
bool mUsesVertexID;
bool mUsesFragDepth;
bool mUsesNumWorkGroups;
bool mUsesWorkGroupID;
bool mUsesLocalInvocationID;
bool mUsesGlobalInvocationID;
bool mUsesLocalInvocationIndex;
bool mUsesXor;
bool mUsesDiscardRewriting;
bool mUsesNestedBreak;
......
......@@ -42,7 +42,8 @@ PrimitiveType GetPrimitiveType(GLenum drawMode);
enum SamplerType
{
SAMPLER_PIXEL,
SAMPLER_VERTEX
SAMPLER_VERTEX,
SAMPLER_COMPUTE
};
struct Rectangle
......@@ -288,6 +289,11 @@ inline DestT *GetImplAs(SrcT *src)
return GetAs<DestT>(src->getImplementation());
}
template <typename DestT, typename SrcT>
inline DestT *SafeGetImplAs(SrcT *src)
{
return src != nullptr ? GetAs<DestT>(src->getImplementation()) : nullptr;
}
}
#include "angletypes.inl"
......
......@@ -764,6 +764,79 @@ void DynamicHLSL::generateShaderLinkHLSL(const gl::ContextState &data,
*pixelHLSL = pixelStream.str();
}
std::string DynamicHLSL::generateComputeShaderLinkHLSL(const gl::ProgramState &programData) const
{
const gl::Shader *computeShaderGL = programData.getAttachedComputeShader();
std::stringstream computeStream;
std::string translatedSource = computeShaderGL->getTranslatedSource();
computeStream << translatedSource;
bool usesWorkGroupID = translatedSource.find("GL_USES_WORK_GROUP_ID") != std::string::npos;
bool usesLocalInvocationID =
translatedSource.find("GL_USES_LOCAL_INVOCATION_ID") != std::string::npos;
bool usesGlobalInvocationID =
translatedSource.find("GL_USES_GLOBAL_INVOCATION_ID") != std::string::npos;
bool usesLocalInvocationIndex =
translatedSource.find("GL_USES_LOCAL_INVOCATION_INDEX") != std::string::npos;
computeStream << "\nstruct CS_INPUT\n{\n";
if (usesWorkGroupID)
{
computeStream << " uint3 dx_WorkGroupID : "
<< "SV_GroupID;\n";
}
if (usesLocalInvocationID)
{
computeStream << " uint3 dx_LocalInvocationID : "
<< "SV_GroupThreadID;\n";
}
if (usesGlobalInvocationID)
{
computeStream << " uint3 dx_GlobalInvocationID : "
<< "SV_DispatchThreadID;\n";
}
if (usesLocalInvocationIndex)
{
computeStream << " uint dx_LocalInvocationIndex : "
<< "SV_GroupIndex;\n";
}
computeStream << "};\n\n";
const sh::WorkGroupSize &localSize = computeShaderGL->getWorkGroupSize();
computeStream << "[numthreads(" << localSize[0] << ", " << localSize[1] << ", " << localSize[2]
<< ")]\n";
computeStream << "void main(CS_INPUT input)\n"
<< "{\n";
if (usesWorkGroupID)
{
computeStream << " gl_WorkGroupID = input.dx_WorkGroupID;\n";
}
if (usesLocalInvocationID)
{
computeStream << " gl_LocalInvocationID = input.dx_LocalInvocationID;\n";
}
if (usesGlobalInvocationID)
{
computeStream << " gl_GlobalInvocationID = input.dx_GlobalInvocationID;\n";
}
if (usesLocalInvocationIndex)
{
computeStream << " gl_LocalInvocationIndex = input.dx_LocalInvocationIndex;\n";
}
computeStream << "\n"
<< " gl_main();\n"
<< "}\n";
return computeStream.str();
}
std::string DynamicHLSL::generateGeometryShaderPreamble(const VaryingPacking &varyingPacking,
const BuiltinVaryingsD3D &builtinsD3D) const
{
......
......@@ -115,6 +115,7 @@ class DynamicHLSL : angle::NonCopyable
const BuiltinVaryingsD3D &builtinsD3D,
std::string *pixelHLSL,
std::string *vertexHLSL) const;
std::string generateComputeShaderLinkHLSL(const gl::ProgramState &programData) const;
std::string generateGeometryShaderPreamble(const gl::VaryingPacking &varyingPacking,
const BuiltinVaryingsD3D &builtinsD3D) const;
......
......@@ -44,6 +44,7 @@ struct D3DUniform : angle::NonCopyable
unsigned int elementCount() const { return std::max(1u, arraySize); }
bool isReferencedByVertexShader() const;
bool isReferencedByFragmentShader() const;
bool isReferencedByComputeShader() const;
// Duplicated from the GL layer
GLenum type;
......@@ -60,6 +61,7 @@ struct D3DUniform : angle::NonCopyable
// Register information.
unsigned int vsRegisterIndex;
unsigned int psRegisterIndex;
unsigned int csRegisterIndex;
unsigned int registerCount;
// Register "elements" are used for uniform structs in ES3, to appropriately identify single
......@@ -70,14 +72,22 @@ struct D3DUniform : angle::NonCopyable
struct D3DUniformBlock
{
D3DUniformBlock() : vsRegisterIndex(GL_INVALID_INDEX), psRegisterIndex(GL_INVALID_INDEX) {}
D3DUniformBlock()
: vsRegisterIndex(GL_INVALID_INDEX),
psRegisterIndex(GL_INVALID_INDEX),
csRegisterIndex(GL_INVALID_INDEX)
{
}
bool vertexStaticUse() const { return vsRegisterIndex != GL_INVALID_INDEX; }
bool fragmentStaticUse() const { return psRegisterIndex != GL_INVALID_INDEX; }
bool computeStaticUse() const { return csRegisterIndex != GL_INVALID_INDEX; }
unsigned int vsRegisterIndex;
unsigned int psRegisterIndex;
unsigned int csRegisterIndex;
};
struct D3DVarying final
......@@ -166,6 +176,9 @@ class ProgramD3D : public ProgramImpl
GLenum drawMode,
ShaderExecutableD3D **outExecutable,
gl::InfoLog *infoLog);
gl::Error getComputeExecutable(const gl::ContextState &data,
ShaderExecutableD3D **outExecutable,
gl::InfoLog *infoLog);
LinkResult link(const gl::ContextState &data,
const gl::VaryingPacking &packing,
......@@ -236,8 +249,18 @@ class ProgramD3D : public ProgramImpl
void setUniformBlockBinding(GLuint uniformBlockIndex, GLuint uniformBlockBinding) override;
const UniformStorageD3D &getVertexUniformStorage() const { return *mVertexUniformStorage; }
const UniformStorageD3D &getFragmentUniformStorage() const { return *mFragmentUniformStorage; }
const UniformStorageD3D &getVertexUniformStorage() const
{
return *mVertexUniformStorage.get();
}
const UniformStorageD3D &getFragmentUniformStorage() const
{
return *mFragmentUniformStorage.get();
}
const UniformStorageD3D &getComputeUniformStorage() const
{
return *mComputeUniformStorage.get();
}
unsigned int getSerial() const;
......@@ -352,6 +375,7 @@ class ProgramD3D : public ProgramImpl
GLenum targetUniformType);
LinkResult compileProgramExecutables(const gl::ContextState &data, gl::InfoLog &infoLog);
LinkResult compileComputeExecutable(gl::InfoLog &infoLog);
void gatherTransformFeedbackVaryings(const gl::VaryingPacking &varyings,
const BuiltinInfo &builtins);
......@@ -363,15 +387,16 @@ class ProgramD3D : public ProgramImpl
void reset();
void ensureUniformBlocksInitialized();
void initUniformBlockInfo();
void initUniformBlockInfo(const gl::Shader *shader);
size_t getUniformBlockInfo(const sh::InterfaceBlock &interfaceBlock);
RendererD3D *mRenderer;
DynamicHLSL *mDynamicHLSL;
std::vector<VertexExecutable *> mVertexExecutables;
std::vector<PixelExecutable *> mPixelExecutables;
std::vector<ShaderExecutableD3D *> mGeometryExecutables;
std::vector<std::unique_ptr<VertexExecutable>> mVertexExecutables;
std::vector<std::unique_ptr<PixelExecutable>> mPixelExecutables;
std::vector<std::unique_ptr<ShaderExecutableD3D>> mGeometryExecutables;
std::unique_ptr<ShaderExecutableD3D> mComputeExecutable;
std::string mVertexHLSL;
angle::CompilerWorkaroundsD3D mVertexWorkarounds;
......@@ -389,13 +414,16 @@ class ProgramD3D : public ProgramImpl
bool mUsesPointSize;
bool mUsesFlatInterpolation;
UniformStorageD3D *mVertexUniformStorage;
UniformStorageD3D *mFragmentUniformStorage;
std::unique_ptr<UniformStorageD3D> mVertexUniformStorage;
std::unique_ptr<UniformStorageD3D> mFragmentUniformStorage;
std::unique_ptr<UniformStorageD3D> mComputeUniformStorage;
std::vector<Sampler> mSamplersPS;
std::vector<Sampler> mSamplersVS;
std::vector<Sampler> mSamplersCS;
GLuint mUsedVertexSamplerRange;
GLuint mUsedPixelSamplerRange;
GLuint mUsedComputeSamplerRange;
bool mDirtySamplerMapping;
// Cache for getPixelExecutableForFramebuffer
......
......@@ -75,6 +75,7 @@ enum ShaderType
SHADER_VERTEX,
SHADER_PIXEL,
SHADER_GEOMETRY,
SHADER_COMPUTE,
SHADER_TYPE_MAX
};
......
......@@ -29,6 +29,9 @@ const char *GetShaderTypeString(GLenum type)
case GL_FRAGMENT_SHADER:
return "FRAGMENT";
case GL_COMPUTE_SHADER:
return "COMPUTE";
default:
UNREACHABLE();
return "";
......@@ -192,7 +195,7 @@ bool ShaderD3D::postTranslateCompile(gl::Compiler *compiler, std::string *infoLo
mUsesPointSize = translatedSource.find("GL_USES_POINT_SIZE") != std::string::npos;
mUsesPointCoord = translatedSource.find("GL_USES_POINT_COORD") != std::string::npos;
mUsesDepthRange = translatedSource.find("GL_USES_DEPTH_RANGE") != std::string::npos;
mUsesFragDepth = translatedSource.find("GL_USES_FRAG_DEPTH") != std::string::npos;
mUsesFragDepth = translatedSource.find("GL_USES_FRAG_DEPTH") != std::string::npos;
mUsesDiscardRewriting =
translatedSource.find("ANGLE_USES_DISCARD_REWRITING") != std::string::npos;
mUsesNestedBreak = translatedSource.find("ANGLE_USES_NESTED_BREAK") != std::string::npos;
......
......@@ -3460,15 +3460,14 @@ gl::Error Renderer11::loadExecutable(const void *function,
{
case SHADER_VERTEX:
{
ID3D11VertexShader *vertexShader = NULL;
ID3D11GeometryShader *streamOutShader = NULL;
ID3D11VertexShader *vertexShader = nullptr;
ID3D11GeometryShader *streamOutShader = nullptr;
HRESULT result = mDevice->CreateVertexShader(function, length, NULL, &vertexShader);
ASSERT(SUCCEEDED(result));
if (FAILED(result))
{
return gl::Error(GL_OUT_OF_MEMORY, "Failed to create vertex shader, result: 0x%X.",
result);
return gl::OutOfMemory() << "Failed to create vertex shader, " << result;
}
if (!streamOutVaryings.empty())
......@@ -3496,8 +3495,7 @@ gl::Error Renderer11::loadExecutable(const void *function,
ASSERT(SUCCEEDED(result));
if (FAILED(result))
{
return gl::Error(GL_OUT_OF_MEMORY,
"Failed to create steam output shader, result: 0x%X.", result);
return gl::OutOfMemory() << "Failed to create steam output shader, " << result;
}
}
......@@ -3507,14 +3505,13 @@ gl::Error Renderer11::loadExecutable(const void *function,
break;
case SHADER_PIXEL:
{
ID3D11PixelShader *pixelShader = NULL;
ID3D11PixelShader *pixelShader = nullptr;
HRESULT result = mDevice->CreatePixelShader(function, length, NULL, &pixelShader);
ASSERT(SUCCEEDED(result));
if (FAILED(result))
{
return gl::Error(GL_OUT_OF_MEMORY, "Failed to create pixel shader, result: 0x%X.",
result);
return gl::OutOfMemory() << "Failed to create pixel shader, " << result;
}
*outExecutable = new ShaderExecutable11(function, length, pixelShader);
......@@ -3522,19 +3519,32 @@ gl::Error Renderer11::loadExecutable(const void *function,
break;
case SHADER_GEOMETRY:
{
ID3D11GeometryShader *geometryShader = NULL;
ID3D11GeometryShader *geometryShader = nullptr;
HRESULT result = mDevice->CreateGeometryShader(function, length, NULL, &geometryShader);
ASSERT(SUCCEEDED(result));
if (FAILED(result))
{
return gl::Error(GL_OUT_OF_MEMORY,
"Failed to create geometry shader, result: 0x%X.", result);
return gl::OutOfMemory() << "Failed to create geometry shader, " << result;
}
*outExecutable = new ShaderExecutable11(function, length, geometryShader);
}
break;
case SHADER_COMPUTE:
{
ID3D11ComputeShader *computeShader = nullptr;
HRESULT result = mDevice->CreateComputeShader(function, length, NULL, &computeShader);
ASSERT(SUCCEEDED(result));
if (FAILED(result))
{
return gl::OutOfMemory() << "Failed to create compute shader, " << result;
}
*outExecutable = new ShaderExecutable11(function, length, computeShader);
}
break;
default:
UNREACHABLE();
return gl::Error(GL_INVALID_OPERATION);
......@@ -3564,6 +3574,9 @@ gl::Error Renderer11::compileToExecutable(gl::InfoLog &infoLog,
case SHADER_GEOMETRY:
profileStream << "gs";
break;
case SHADER_COMPUTE:
profileStream << "cs";
break;
default:
UNREACHABLE();
return gl::Error(GL_INVALID_OPERATION);
......
......@@ -17,27 +17,42 @@ ShaderExecutable11::ShaderExecutable11(const void *function, size_t length, ID3D
: ShaderExecutableD3D(function, length)
{
mPixelExecutable = executable;
mVertexExecutable = NULL;
mGeometryExecutable = NULL;
mStreamOutExecutable = NULL;
mVertexExecutable = nullptr;
mGeometryExecutable = nullptr;
mStreamOutExecutable = nullptr;
mComputeExecutable = nullptr;
}
ShaderExecutable11::ShaderExecutable11(const void *function, size_t length, ID3D11VertexShader *executable, ID3D11GeometryShader *streamOut)
: ShaderExecutableD3D(function, length)
{
mVertexExecutable = executable;
mPixelExecutable = NULL;
mGeometryExecutable = NULL;
mPixelExecutable = nullptr;
mGeometryExecutable = nullptr;
mStreamOutExecutable = streamOut;
mComputeExecutable = nullptr;
}
ShaderExecutable11::ShaderExecutable11(const void *function, size_t length, ID3D11GeometryShader *executable)
: ShaderExecutableD3D(function, length)
{
mGeometryExecutable = executable;
mVertexExecutable = NULL;
mPixelExecutable = NULL;
mStreamOutExecutable = NULL;
mVertexExecutable = nullptr;
mPixelExecutable = nullptr;
mStreamOutExecutable = nullptr;
mComputeExecutable = nullptr;
}
ShaderExecutable11::ShaderExecutable11(const void *function,
size_t length,
ID3D11ComputeShader *executable)
: ShaderExecutableD3D(function, length)
{
mComputeExecutable = executable;
mPixelExecutable = nullptr;
mVertexExecutable = nullptr;
mGeometryExecutable = nullptr;
mStreamOutExecutable = nullptr;
}
ShaderExecutable11::~ShaderExecutable11()
......@@ -46,6 +61,7 @@ ShaderExecutable11::~ShaderExecutable11()
SafeRelease(mPixelExecutable);
SafeRelease(mGeometryExecutable);
SafeRelease(mStreamOutExecutable);
SafeRelease(mComputeExecutable);
}
ID3D11VertexShader *ShaderExecutable11::getVertexShader() const
......@@ -68,6 +84,11 @@ ID3D11GeometryShader *ShaderExecutable11::getStreamOutShader() const
return mStreamOutExecutable;
}
ID3D11ComputeShader *ShaderExecutable11::getComputeShader() const
{
return mComputeExecutable;
}
UniformStorage11::UniformStorage11(Renderer11 *renderer, size_t initialSize)
: UniformStorageD3D(initialSize),
mConstantBuffer(NULL)
......
......@@ -23,6 +23,7 @@ class ShaderExecutable11 : public ShaderExecutableD3D
ShaderExecutable11(const void *function, size_t length, ID3D11PixelShader *executable);
ShaderExecutable11(const void *function, size_t length, ID3D11VertexShader *executable, ID3D11GeometryShader *streamOut);
ShaderExecutable11(const void *function, size_t length, ID3D11GeometryShader *executable);
ShaderExecutable11(const void *function, size_t length, ID3D11ComputeShader *executable);
virtual ~ShaderExecutable11();
......@@ -30,12 +31,14 @@ class ShaderExecutable11 : public ShaderExecutableD3D
ID3D11VertexShader *getVertexShader() const;
ID3D11GeometryShader *getGeometryShader() const;
ID3D11GeometryShader *getStreamOutShader() const;
ID3D11ComputeShader *getComputeShader() const;
private:
ID3D11PixelShader *mPixelExecutable;
ID3D11VertexShader *mVertexExecutable;
ID3D11GeometryShader *mGeometryExecutable;
ID3D11GeometryShader *mStreamOutExecutable;
ID3D11ComputeShader *mComputeExecutable;
};
class UniformStorage11 : public UniformStorageD3D
......
......@@ -830,6 +830,84 @@ size_t GetMaximumPixelTextureUnits(D3D_FEATURE_LEVEL featureLevel)
}
}
std::array<GLuint, 3> GetMaxComputeWorkGroupCount(D3D_FEATURE_LEVEL featureLevel)
{
switch (featureLevel)
{
case D3D_FEATURE_LEVEL_11_1:
case D3D_FEATURE_LEVEL_11_0:
return {{D3D11_CS_DISPATCH_MAX_THREAD_GROUPS_PER_DIMENSION,
D3D11_CS_DISPATCH_MAX_THREAD_GROUPS_PER_DIMENSION,
D3D11_CS_DISPATCH_MAX_THREAD_GROUPS_PER_DIMENSION}};
break;
default:
return {{0, 0, 0}};
}
}
std::array<GLuint, 3> GetMaxComputeWorkGroupSize(D3D_FEATURE_LEVEL featureLevel)
{
switch (featureLevel)
{
case D3D_FEATURE_LEVEL_11_1:
case D3D_FEATURE_LEVEL_11_0:
return {{D3D11_CS_THREAD_GROUP_MAX_X, D3D11_CS_THREAD_GROUP_MAX_Y,
D3D11_CS_THREAD_GROUP_MAX_Z}};
break;
default:
return {{0, 0, 0}};
}
}
size_t GetMaxComputeWorkGroupInvocations(D3D_FEATURE_LEVEL featureLevel)
{
switch (featureLevel)
{
case D3D_FEATURE_LEVEL_11_1:
case D3D_FEATURE_LEVEL_11_0:
return D3D11_CS_THREAD_GROUP_MAX_THREADS_PER_GROUP;
default:
return 0;
}
}
size_t GetMaximumComputeUniformVectors(D3D_FEATURE_LEVEL featureLevel)
{
switch (featureLevel)
{
case D3D_FEATURE_LEVEL_11_1:
case D3D_FEATURE_LEVEL_11_0:
return D3D11_REQ_CONSTANT_BUFFER_ELEMENT_COUNT;
default:
return 0;
}
}
size_t GetMaximumComputeUniformBlocks(D3D_FEATURE_LEVEL featureLevel)
{
switch (featureLevel)
{
case D3D_FEATURE_LEVEL_11_1:
case D3D_FEATURE_LEVEL_11_0:
return D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT -
d3d11::RESERVED_CONSTANT_BUFFER_SLOT_COUNT;
default:
return 0;
}
}
size_t GetMaximumComputeTextureUnits(D3D_FEATURE_LEVEL featureLevel)
{
switch (featureLevel)
{
case D3D_FEATURE_LEVEL_11_1:
case D3D_FEATURE_LEVEL_11_0:
return D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT;
default:
return 0;
}
}
int GetMinimumTexelOffset(D3D_FEATURE_LEVEL featureLevel)
{
switch (featureLevel)
......@@ -1160,6 +1238,18 @@ void GenerateCaps(ID3D11Device *device, ID3D11DeviceContext *deviceContext, cons
caps->minProgramTexelOffset = GetMinimumTexelOffset(featureLevel);
caps->maxProgramTexelOffset = GetMaximumTexelOffset(featureLevel);
// Compute shader limits
caps->maxComputeWorkGroupCount = GetMaxComputeWorkGroupCount(featureLevel);
caps->maxComputeWorkGroupSize = GetMaxComputeWorkGroupSize(featureLevel);
caps->maxComputeWorkGroupInvocations =
static_cast<GLuint>(GetMaxComputeWorkGroupInvocations(featureLevel));
caps->maxComputeUniformComponents =
static_cast<GLuint>(GetMaximumComputeUniformVectors(featureLevel)) * 4;
caps->maxComputeUniformBlocks =
static_cast<GLuint>(GetMaximumComputeUniformBlocks(featureLevel));
caps->maxComputeTextureImageUnits =
static_cast<GLuint>(GetMaximumComputeTextureUnits(featureLevel));
// Aggregate shader limits
caps->maxUniformBufferBindings = caps->maxVertexUniformBlocks + caps->maxFragmentUniformBlocks;
caps->maxUniformBlockSize = GetMaximumConstantBufferSize(featureLevel);
......@@ -1175,6 +1265,9 @@ void GenerateCaps(ID3D11Device *device, ID3D11DeviceContext *deviceContext, cons
static_cast<GLint64>(caps->maxVertexUniformComponents);
caps->maxCombinedFragmentUniformComponents = (static_cast<GLint64>(caps->maxFragmentUniformBlocks) * static_cast<GLint64>(caps->maxUniformBlockSize / 4)) +
static_cast<GLint64>(caps->maxFragmentUniformComponents);
caps->maxCombinedComputeUniformComponents =
static_cast<GLuint>(caps->maxComputeUniformBlocks * (caps->maxUniformBlockSize / 4) +
caps->maxComputeUniformComponents);
caps->maxVaryingComponents =
static_cast<GLuint>(GetMaximumVertexOutputVectors(featureLevel)) * 4;
caps->maxVaryingVectors = static_cast<GLuint>(GetMaximumVertexOutputVectors(featureLevel));
......
......@@ -211,6 +211,41 @@ TEST_P(ComputeShaderTest, AttachmentCount)
EXPECT_GL_NO_ERROR();
}
// Access all compute shader special variables.
TEST_P(ComputeShaderTest, AccessAllSpecialVariables)
{
const std::string csSource =
"#version 310 es\n"
"layout(local_size_x=4, local_size_y=3, local_size_z=2) in;\n"
"void main()\n"
"{\n"
" uvec3 temp1 = gl_NumWorkGroups;\n"
" uvec3 temp2 = gl_WorkGroupSize;\n"
" uvec3 temp3 = gl_WorkGroupID;\n"
" uvec3 temp4 = gl_LocalInvocationID;\n"
" uvec3 temp5 = gl_GlobalInvocationID;\n"
" uint temp6 = gl_LocalInvocationIndex;\n"
"}\n";
ANGLE_GL_COMPUTE_PROGRAM(program, csSource);
}
// Access part compute shader special variables.
TEST_P(ComputeShaderTest, AccessPartSpecialVariables)
{
const std::string csSource =
"#version 310 es\n"
"layout(local_size_x=4, local_size_y=3, local_size_z=2) in;\n"
"void main()\n"
"{\n"
" uvec3 temp1 = gl_WorkGroupSize;\n"
" uvec3 temp2 = gl_WorkGroupID;\n"
" uint temp3 = gl_LocalInvocationIndex;\n"
"}\n";
ANGLE_GL_COMPUTE_PROGRAM(program, csSource);
}
// Check that it is not possible to create a compute shader when the context does not support ES
// 3.10
TEST_P(ComputeShaderTestES3, NotSupported)
......@@ -220,7 +255,7 @@ TEST_P(ComputeShaderTestES3, NotSupported)
EXPECT_GL_ERROR(GL_INVALID_ENUM);
}
ANGLE_INSTANTIATE_TEST(ComputeShaderTest, ES31_OPENGL(), ES31_OPENGLES());
ANGLE_INSTANTIATE_TEST(ComputeShaderTest, ES31_OPENGL(), ES31_OPENGLES(), ES31_D3D11());
ANGLE_INSTANTIATE_TEST(ComputeShaderTestES3, ES3_OPENGL(), ES3_OPENGLES());
} // namespace
......@@ -335,6 +335,69 @@ TEST_P(ProgramBinaryES3Test, UniformBlockBindingNoDraw)
ANGLE_INSTANTIATE_TEST(ProgramBinaryES3Test, ES3_D3D11(), ES3_OPENGL(), ES3_OPENGLES());
class ProgramBinaryES31Test : public ANGLETest
{
protected:
ProgramBinaryES31Test()
{
setWindowWidth(128);
setWindowHeight(128);
setConfigRedBits(8);
setConfigGreenBits(8);
setConfigBlueBits(8);
setConfigAlphaBits(8);
}
};
// Tests that saving and loading a program attached with computer shader.
TEST_P(ProgramBinaryES31Test, ProgramBinaryWithComputeShader)
{
// We can't run the test if no program binary formats are supported.
GLint binaryFormatCount = 0;
glGetIntegerv(GL_NUM_PROGRAM_BINARY_FORMATS, &binaryFormatCount);
if (binaryFormatCount == 0)
{
std::cout << "Test skipped because no program binary formats available." << std::endl;
return;
}
const std::string &computeShader =
"#version 310 es\n"
"layout(local_size_x=4, local_size_y=3, local_size_z=1) in;\n"
"uniform block {\n"
" vec2 f;\n"
"};\n"
"uniform vec2 g;\n"
"uniform highp sampler2D tex;\n"
"void main() {\n"
" vec4 color = texture(tex, f + g);\n"
"}";
ANGLE_GL_COMPUTE_PROGRAM(program, computeShader);
// Read back the binary.
GLint programLength = 0;
glGetProgramiv(program.get(), GL_PROGRAM_BINARY_LENGTH, &programLength);
ASSERT_GL_NO_ERROR();
GLsizei readLength = 0;
GLenum binaryFormat = GL_NONE;
std::vector<uint8_t> binary(programLength);
glGetProgramBinary(program.get(), programLength, &readLength, &binaryFormat, binary.data());
ASSERT_GL_NO_ERROR();
EXPECT_EQ(static_cast<GLsizei>(programLength), readLength);
// Load a new program with the binary.
ANGLE_GL_BINARY_ES3_PROGRAM(binaryProgram, binary, binaryFormat);
// TODO(Xinghua): add dispatch support when available.
ASSERT_GL_NO_ERROR();
}
ANGLE_INSTANTIATE_TEST(ProgramBinaryES31Test, ES31_D3D11(), ES31_OPENGL(), ES31_OPENGLES());
class ProgramBinaryTransformFeedbackTest : public ANGLETest
{
protected:
......
......@@ -491,6 +491,21 @@ PlatformParameters ES3_D3D11_FL10_1()
return PlatformParameters(3, 0, egl_platform::D3D11_FL10_1());
}
PlatformParameters ES31_D3D11()
{
return PlatformParameters(3, 1, egl_platform::D3D11());
}
PlatformParameters ES31_D3D11_FL11_1()
{
return PlatformParameters(3, 1, egl_platform::D3D11_FL11_1());
}
PlatformParameters ES31_D3D11_FL11_0()
{
return PlatformParameters(3, 1, egl_platform::D3D11_FL11_0());
}
PlatformParameters ES3_D3D11_WARP()
{
return PlatformParameters(3, 0, egl_platform::D3D11_WARP());
......
......@@ -113,6 +113,9 @@ PlatformParameters ES3_D3D11();
PlatformParameters ES3_D3D11_FL11_1();
PlatformParameters ES3_D3D11_FL11_0();
PlatformParameters ES3_D3D11_FL10_1();
PlatformParameters ES31_D3D11();
PlatformParameters ES31_D3D11_FL11_1();
PlatformParameters ES31_D3D11_FL11_0();
PlatformParameters ES3_D3D11_WARP();
PlatformParameters ES3_D3D11_FL11_1_WARP();
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment