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, ...@@ -115,6 +115,11 @@ OutputHLSL::OutputHLSL(sh::GLenum shaderType,
mUsesInstanceID = false; mUsesInstanceID = false;
mUsesVertexID = false; mUsesVertexID = false;
mUsesFragDepth = false; mUsesFragDepth = false;
mUsesNumWorkGroups = false;
mUsesWorkGroupID = false;
mUsesLocalInvocationID = false;
mUsesGlobalInvocationID = false;
mUsesLocalInvocationIndex = false;
mUsesXor = false; mUsesXor = false;
mUsesDiscardRewriting = false; mUsesDiscardRewriting = false;
mUsesNestedBreak = false; mUsesNestedBreak = false;
...@@ -540,7 +545,7 @@ void OutputHLSL::header(TInfoSinkBase &out, const BuiltInFunctionEmulator *built ...@@ -540,7 +545,7 @@ void OutputHLSL::header(TInfoSinkBase &out, const BuiltInFunctionEmulator *built
out << "#define GL_USES_FRAG_DATA\n"; out << "#define GL_USES_FRAG_DATA\n";
} }
} }
else // Vertex shader else if (mShaderType == GL_VERTEX_SHADER)
{ {
out << "// Attributes\n"; out << "// Attributes\n";
out << attributes; out << attributes;
...@@ -631,6 +636,40 @@ void OutputHLSL::header(TInfoSinkBase &out, const BuiltInFunctionEmulator *built ...@@ -631,6 +636,40 @@ void OutputHLSL::header(TInfoSinkBase &out, const BuiltInFunctionEmulator *built
out << "\n"; 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 = bool getDimensionsIgnoresBaseLevel =
(mCompileOptions & SH_HLSL_GET_DIMENSIONS_IGNORES_BASE_LEVEL) != 0; (mCompileOptions & SH_HLSL_GET_DIMENSIONS_IGNORES_BASE_LEVEL) != 0;
...@@ -666,6 +705,31 @@ void OutputHLSL::header(TInfoSinkBase &out, const BuiltInFunctionEmulator *built ...@@ -666,6 +705,31 @@ void OutputHLSL::header(TInfoSinkBase &out, const BuiltInFunctionEmulator *built
out << "#define GL_USES_DEPTH_RANGE\n"; 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) if (mUsesXor)
{ {
out << "bool xor(bool p, bool q)\n" out << "bool xor(bool p, bool q)\n"
...@@ -779,6 +843,31 @@ void OutputHLSL::visitSymbol(TIntermSymbol *node) ...@@ -779,6 +843,31 @@ void OutputHLSL::visitSymbol(TIntermSymbol *node)
mUsesFragDepth = true; mUsesFragDepth = true;
out << "gl_Depth"; 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 else
{ {
out << DecorateIfNeeded(node->getName()); out << DecorateIfNeeded(node->getName());
......
...@@ -173,6 +173,11 @@ class OutputHLSL : public TIntermTraverser ...@@ -173,6 +173,11 @@ class OutputHLSL : public TIntermTraverser
bool mUsesInstanceID; bool mUsesInstanceID;
bool mUsesVertexID; bool mUsesVertexID;
bool mUsesFragDepth; bool mUsesFragDepth;
bool mUsesNumWorkGroups;
bool mUsesWorkGroupID;
bool mUsesLocalInvocationID;
bool mUsesGlobalInvocationID;
bool mUsesLocalInvocationIndex;
bool mUsesXor; bool mUsesXor;
bool mUsesDiscardRewriting; bool mUsesDiscardRewriting;
bool mUsesNestedBreak; bool mUsesNestedBreak;
......
...@@ -42,7 +42,8 @@ PrimitiveType GetPrimitiveType(GLenum drawMode); ...@@ -42,7 +42,8 @@ PrimitiveType GetPrimitiveType(GLenum drawMode);
enum SamplerType enum SamplerType
{ {
SAMPLER_PIXEL, SAMPLER_PIXEL,
SAMPLER_VERTEX SAMPLER_VERTEX,
SAMPLER_COMPUTE
}; };
struct Rectangle struct Rectangle
...@@ -288,6 +289,11 @@ inline DestT *GetImplAs(SrcT *src) ...@@ -288,6 +289,11 @@ inline DestT *GetImplAs(SrcT *src)
return GetAs<DestT>(src->getImplementation()); 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" #include "angletypes.inl"
......
...@@ -764,6 +764,79 @@ void DynamicHLSL::generateShaderLinkHLSL(const gl::ContextState &data, ...@@ -764,6 +764,79 @@ void DynamicHLSL::generateShaderLinkHLSL(const gl::ContextState &data,
*pixelHLSL = pixelStream.str(); *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, std::string DynamicHLSL::generateGeometryShaderPreamble(const VaryingPacking &varyingPacking,
const BuiltinVaryingsD3D &builtinsD3D) const const BuiltinVaryingsD3D &builtinsD3D) const
{ {
......
...@@ -115,6 +115,7 @@ class DynamicHLSL : angle::NonCopyable ...@@ -115,6 +115,7 @@ class DynamicHLSL : angle::NonCopyable
const BuiltinVaryingsD3D &builtinsD3D, const BuiltinVaryingsD3D &builtinsD3D,
std::string *pixelHLSL, std::string *pixelHLSL,
std::string *vertexHLSL) const; std::string *vertexHLSL) const;
std::string generateComputeShaderLinkHLSL(const gl::ProgramState &programData) const;
std::string generateGeometryShaderPreamble(const gl::VaryingPacking &varyingPacking, std::string generateGeometryShaderPreamble(const gl::VaryingPacking &varyingPacking,
const BuiltinVaryingsD3D &builtinsD3D) const; const BuiltinVaryingsD3D &builtinsD3D) const;
......
...@@ -44,6 +44,7 @@ struct D3DUniform : angle::NonCopyable ...@@ -44,6 +44,7 @@ struct D3DUniform : angle::NonCopyable
unsigned int elementCount() const { return std::max(1u, arraySize); } unsigned int elementCount() const { return std::max(1u, arraySize); }
bool isReferencedByVertexShader() const; bool isReferencedByVertexShader() const;
bool isReferencedByFragmentShader() const; bool isReferencedByFragmentShader() const;
bool isReferencedByComputeShader() const;
// Duplicated from the GL layer // Duplicated from the GL layer
GLenum type; GLenum type;
...@@ -60,6 +61,7 @@ struct D3DUniform : angle::NonCopyable ...@@ -60,6 +61,7 @@ struct D3DUniform : angle::NonCopyable
// Register information. // Register information.
unsigned int vsRegisterIndex; unsigned int vsRegisterIndex;
unsigned int psRegisterIndex; unsigned int psRegisterIndex;
unsigned int csRegisterIndex;
unsigned int registerCount; unsigned int registerCount;
// Register "elements" are used for uniform structs in ES3, to appropriately identify single // Register "elements" are used for uniform structs in ES3, to appropriately identify single
...@@ -70,14 +72,22 @@ struct D3DUniform : angle::NonCopyable ...@@ -70,14 +72,22 @@ struct D3DUniform : angle::NonCopyable
struct D3DUniformBlock 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 vertexStaticUse() const { return vsRegisterIndex != GL_INVALID_INDEX; }
bool fragmentStaticUse() const { return psRegisterIndex != GL_INVALID_INDEX; } bool fragmentStaticUse() const { return psRegisterIndex != GL_INVALID_INDEX; }
bool computeStaticUse() const { return csRegisterIndex != GL_INVALID_INDEX; }
unsigned int vsRegisterIndex; unsigned int vsRegisterIndex;
unsigned int psRegisterIndex; unsigned int psRegisterIndex;
unsigned int csRegisterIndex;
}; };
struct D3DVarying final struct D3DVarying final
...@@ -166,6 +176,9 @@ class ProgramD3D : public ProgramImpl ...@@ -166,6 +176,9 @@ class ProgramD3D : public ProgramImpl
GLenum drawMode, GLenum drawMode,
ShaderExecutableD3D **outExecutable, ShaderExecutableD3D **outExecutable,
gl::InfoLog *infoLog); gl::InfoLog *infoLog);
gl::Error getComputeExecutable(const gl::ContextState &data,
ShaderExecutableD3D **outExecutable,
gl::InfoLog *infoLog);
LinkResult link(const gl::ContextState &data, LinkResult link(const gl::ContextState &data,
const gl::VaryingPacking &packing, const gl::VaryingPacking &packing,
...@@ -236,8 +249,18 @@ class ProgramD3D : public ProgramImpl ...@@ -236,8 +249,18 @@ class ProgramD3D : public ProgramImpl
void setUniformBlockBinding(GLuint uniformBlockIndex, GLuint uniformBlockBinding) override; void setUniformBlockBinding(GLuint uniformBlockIndex, GLuint uniformBlockBinding) override;
const UniformStorageD3D &getVertexUniformStorage() const { return *mVertexUniformStorage; } const UniformStorageD3D &getVertexUniformStorage() const
const UniformStorageD3D &getFragmentUniformStorage() const { return *mFragmentUniformStorage; } {
return *mVertexUniformStorage.get();
}
const UniformStorageD3D &getFragmentUniformStorage() const
{
return *mFragmentUniformStorage.get();
}
const UniformStorageD3D &getComputeUniformStorage() const
{
return *mComputeUniformStorage.get();
}
unsigned int getSerial() const; unsigned int getSerial() const;
...@@ -352,6 +375,7 @@ class ProgramD3D : public ProgramImpl ...@@ -352,6 +375,7 @@ class ProgramD3D : public ProgramImpl
GLenum targetUniformType); GLenum targetUniformType);
LinkResult compileProgramExecutables(const gl::ContextState &data, gl::InfoLog &infoLog); LinkResult compileProgramExecutables(const gl::ContextState &data, gl::InfoLog &infoLog);
LinkResult compileComputeExecutable(gl::InfoLog &infoLog);
void gatherTransformFeedbackVaryings(const gl::VaryingPacking &varyings, void gatherTransformFeedbackVaryings(const gl::VaryingPacking &varyings,
const BuiltinInfo &builtins); const BuiltinInfo &builtins);
...@@ -363,15 +387,16 @@ class ProgramD3D : public ProgramImpl ...@@ -363,15 +387,16 @@ class ProgramD3D : public ProgramImpl
void reset(); void reset();
void ensureUniformBlocksInitialized(); void ensureUniformBlocksInitialized();
void initUniformBlockInfo(); void initUniformBlockInfo(const gl::Shader *shader);
size_t getUniformBlockInfo(const sh::InterfaceBlock &interfaceBlock); size_t getUniformBlockInfo(const sh::InterfaceBlock &interfaceBlock);
RendererD3D *mRenderer; RendererD3D *mRenderer;
DynamicHLSL *mDynamicHLSL; DynamicHLSL *mDynamicHLSL;
std::vector<VertexExecutable *> mVertexExecutables; std::vector<std::unique_ptr<VertexExecutable>> mVertexExecutables;
std::vector<PixelExecutable *> mPixelExecutables; std::vector<std::unique_ptr<PixelExecutable>> mPixelExecutables;
std::vector<ShaderExecutableD3D *> mGeometryExecutables; std::vector<std::unique_ptr<ShaderExecutableD3D>> mGeometryExecutables;
std::unique_ptr<ShaderExecutableD3D> mComputeExecutable;
std::string mVertexHLSL; std::string mVertexHLSL;
angle::CompilerWorkaroundsD3D mVertexWorkarounds; angle::CompilerWorkaroundsD3D mVertexWorkarounds;
...@@ -389,13 +414,16 @@ class ProgramD3D : public ProgramImpl ...@@ -389,13 +414,16 @@ class ProgramD3D : public ProgramImpl
bool mUsesPointSize; bool mUsesPointSize;
bool mUsesFlatInterpolation; bool mUsesFlatInterpolation;
UniformStorageD3D *mVertexUniformStorage; std::unique_ptr<UniformStorageD3D> mVertexUniformStorage;
UniformStorageD3D *mFragmentUniformStorage; std::unique_ptr<UniformStorageD3D> mFragmentUniformStorage;
std::unique_ptr<UniformStorageD3D> mComputeUniformStorage;
std::vector<Sampler> mSamplersPS; std::vector<Sampler> mSamplersPS;
std::vector<Sampler> mSamplersVS; std::vector<Sampler> mSamplersVS;
std::vector<Sampler> mSamplersCS;
GLuint mUsedVertexSamplerRange; GLuint mUsedVertexSamplerRange;
GLuint mUsedPixelSamplerRange; GLuint mUsedPixelSamplerRange;
GLuint mUsedComputeSamplerRange;
bool mDirtySamplerMapping; bool mDirtySamplerMapping;
// Cache for getPixelExecutableForFramebuffer // Cache for getPixelExecutableForFramebuffer
......
...@@ -75,6 +75,7 @@ enum ShaderType ...@@ -75,6 +75,7 @@ enum ShaderType
SHADER_VERTEX, SHADER_VERTEX,
SHADER_PIXEL, SHADER_PIXEL,
SHADER_GEOMETRY, SHADER_GEOMETRY,
SHADER_COMPUTE,
SHADER_TYPE_MAX SHADER_TYPE_MAX
}; };
......
...@@ -29,6 +29,9 @@ const char *GetShaderTypeString(GLenum type) ...@@ -29,6 +29,9 @@ const char *GetShaderTypeString(GLenum type)
case GL_FRAGMENT_SHADER: case GL_FRAGMENT_SHADER:
return "FRAGMENT"; return "FRAGMENT";
case GL_COMPUTE_SHADER:
return "COMPUTE";
default: default:
UNREACHABLE(); UNREACHABLE();
return ""; return "";
...@@ -192,7 +195,7 @@ bool ShaderD3D::postTranslateCompile(gl::Compiler *compiler, std::string *infoLo ...@@ -192,7 +195,7 @@ bool ShaderD3D::postTranslateCompile(gl::Compiler *compiler, std::string *infoLo
mUsesPointSize = translatedSource.find("GL_USES_POINT_SIZE") != std::string::npos; mUsesPointSize = translatedSource.find("GL_USES_POINT_SIZE") != std::string::npos;
mUsesPointCoord = translatedSource.find("GL_USES_POINT_COORD") != std::string::npos; mUsesPointCoord = translatedSource.find("GL_USES_POINT_COORD") != std::string::npos;
mUsesDepthRange = translatedSource.find("GL_USES_DEPTH_RANGE") != 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 = mUsesDiscardRewriting =
translatedSource.find("ANGLE_USES_DISCARD_REWRITING") != std::string::npos; translatedSource.find("ANGLE_USES_DISCARD_REWRITING") != std::string::npos;
mUsesNestedBreak = translatedSource.find("ANGLE_USES_NESTED_BREAK") != std::string::npos; mUsesNestedBreak = translatedSource.find("ANGLE_USES_NESTED_BREAK") != std::string::npos;
......
...@@ -3460,15 +3460,14 @@ gl::Error Renderer11::loadExecutable(const void *function, ...@@ -3460,15 +3460,14 @@ gl::Error Renderer11::loadExecutable(const void *function,
{ {
case SHADER_VERTEX: case SHADER_VERTEX:
{ {
ID3D11VertexShader *vertexShader = NULL; ID3D11VertexShader *vertexShader = nullptr;
ID3D11GeometryShader *streamOutShader = NULL; ID3D11GeometryShader *streamOutShader = nullptr;
HRESULT result = mDevice->CreateVertexShader(function, length, NULL, &vertexShader); HRESULT result = mDevice->CreateVertexShader(function, length, NULL, &vertexShader);
ASSERT(SUCCEEDED(result)); ASSERT(SUCCEEDED(result));
if (FAILED(result)) if (FAILED(result))
{ {
return gl::Error(GL_OUT_OF_MEMORY, "Failed to create vertex shader, result: 0x%X.", return gl::OutOfMemory() << "Failed to create vertex shader, " << result;
result);
} }
if (!streamOutVaryings.empty()) if (!streamOutVaryings.empty())
...@@ -3496,8 +3495,7 @@ gl::Error Renderer11::loadExecutable(const void *function, ...@@ -3496,8 +3495,7 @@ gl::Error Renderer11::loadExecutable(const void *function,
ASSERT(SUCCEEDED(result)); ASSERT(SUCCEEDED(result));
if (FAILED(result)) if (FAILED(result))
{ {
return gl::Error(GL_OUT_OF_MEMORY, return gl::OutOfMemory() << "Failed to create steam output shader, " << result;
"Failed to create steam output shader, result: 0x%X.", result);
} }
} }
...@@ -3507,14 +3505,13 @@ gl::Error Renderer11::loadExecutable(const void *function, ...@@ -3507,14 +3505,13 @@ gl::Error Renderer11::loadExecutable(const void *function,
break; break;
case SHADER_PIXEL: case SHADER_PIXEL:
{ {
ID3D11PixelShader *pixelShader = NULL; ID3D11PixelShader *pixelShader = nullptr;
HRESULT result = mDevice->CreatePixelShader(function, length, NULL, &pixelShader); HRESULT result = mDevice->CreatePixelShader(function, length, NULL, &pixelShader);
ASSERT(SUCCEEDED(result)); ASSERT(SUCCEEDED(result));
if (FAILED(result)) if (FAILED(result))
{ {
return gl::Error(GL_OUT_OF_MEMORY, "Failed to create pixel shader, result: 0x%X.", return gl::OutOfMemory() << "Failed to create pixel shader, " << result;
result);
} }
*outExecutable = new ShaderExecutable11(function, length, pixelShader); *outExecutable = new ShaderExecutable11(function, length, pixelShader);
...@@ -3522,19 +3519,32 @@ gl::Error Renderer11::loadExecutable(const void *function, ...@@ -3522,19 +3519,32 @@ gl::Error Renderer11::loadExecutable(const void *function,
break; break;
case SHADER_GEOMETRY: case SHADER_GEOMETRY:
{ {
ID3D11GeometryShader *geometryShader = NULL; ID3D11GeometryShader *geometryShader = nullptr;
HRESULT result = mDevice->CreateGeometryShader(function, length, NULL, &geometryShader); HRESULT result = mDevice->CreateGeometryShader(function, length, NULL, &geometryShader);
ASSERT(SUCCEEDED(result)); ASSERT(SUCCEEDED(result));
if (FAILED(result)) if (FAILED(result))
{ {
return gl::Error(GL_OUT_OF_MEMORY, return gl::OutOfMemory() << "Failed to create geometry shader, " << result;
"Failed to create geometry shader, result: 0x%X.", result);
} }
*outExecutable = new ShaderExecutable11(function, length, geometryShader); *outExecutable = new ShaderExecutable11(function, length, geometryShader);
} }
break; 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: default:
UNREACHABLE(); UNREACHABLE();
return gl::Error(GL_INVALID_OPERATION); return gl::Error(GL_INVALID_OPERATION);
...@@ -3564,6 +3574,9 @@ gl::Error Renderer11::compileToExecutable(gl::InfoLog &infoLog, ...@@ -3564,6 +3574,9 @@ gl::Error Renderer11::compileToExecutable(gl::InfoLog &infoLog,
case SHADER_GEOMETRY: case SHADER_GEOMETRY:
profileStream << "gs"; profileStream << "gs";
break; break;
case SHADER_COMPUTE:
profileStream << "cs";
break;
default: default:
UNREACHABLE(); UNREACHABLE();
return gl::Error(GL_INVALID_OPERATION); return gl::Error(GL_INVALID_OPERATION);
......
...@@ -17,27 +17,42 @@ ShaderExecutable11::ShaderExecutable11(const void *function, size_t length, ID3D ...@@ -17,27 +17,42 @@ ShaderExecutable11::ShaderExecutable11(const void *function, size_t length, ID3D
: ShaderExecutableD3D(function, length) : ShaderExecutableD3D(function, length)
{ {
mPixelExecutable = executable; mPixelExecutable = executable;
mVertexExecutable = NULL; mVertexExecutable = nullptr;
mGeometryExecutable = NULL; mGeometryExecutable = nullptr;
mStreamOutExecutable = NULL; mStreamOutExecutable = nullptr;
mComputeExecutable = nullptr;
} }
ShaderExecutable11::ShaderExecutable11(const void *function, size_t length, ID3D11VertexShader *executable, ID3D11GeometryShader *streamOut) ShaderExecutable11::ShaderExecutable11(const void *function, size_t length, ID3D11VertexShader *executable, ID3D11GeometryShader *streamOut)
: ShaderExecutableD3D(function, length) : ShaderExecutableD3D(function, length)
{ {
mVertexExecutable = executable; mVertexExecutable = executable;
mPixelExecutable = NULL; mPixelExecutable = nullptr;
mGeometryExecutable = NULL; mGeometryExecutable = nullptr;
mStreamOutExecutable = streamOut; mStreamOutExecutable = streamOut;
mComputeExecutable = nullptr;
} }
ShaderExecutable11::ShaderExecutable11(const void *function, size_t length, ID3D11GeometryShader *executable) ShaderExecutable11::ShaderExecutable11(const void *function, size_t length, ID3D11GeometryShader *executable)
: ShaderExecutableD3D(function, length) : ShaderExecutableD3D(function, length)
{ {
mGeometryExecutable = executable; mGeometryExecutable = executable;
mVertexExecutable = NULL; mVertexExecutable = nullptr;
mPixelExecutable = NULL; mPixelExecutable = nullptr;
mStreamOutExecutable = NULL; 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() ShaderExecutable11::~ShaderExecutable11()
...@@ -46,6 +61,7 @@ ShaderExecutable11::~ShaderExecutable11() ...@@ -46,6 +61,7 @@ ShaderExecutable11::~ShaderExecutable11()
SafeRelease(mPixelExecutable); SafeRelease(mPixelExecutable);
SafeRelease(mGeometryExecutable); SafeRelease(mGeometryExecutable);
SafeRelease(mStreamOutExecutable); SafeRelease(mStreamOutExecutable);
SafeRelease(mComputeExecutable);
} }
ID3D11VertexShader *ShaderExecutable11::getVertexShader() const ID3D11VertexShader *ShaderExecutable11::getVertexShader() const
...@@ -68,6 +84,11 @@ ID3D11GeometryShader *ShaderExecutable11::getStreamOutShader() const ...@@ -68,6 +84,11 @@ ID3D11GeometryShader *ShaderExecutable11::getStreamOutShader() const
return mStreamOutExecutable; return mStreamOutExecutable;
} }
ID3D11ComputeShader *ShaderExecutable11::getComputeShader() const
{
return mComputeExecutable;
}
UniformStorage11::UniformStorage11(Renderer11 *renderer, size_t initialSize) UniformStorage11::UniformStorage11(Renderer11 *renderer, size_t initialSize)
: UniformStorageD3D(initialSize), : UniformStorageD3D(initialSize),
mConstantBuffer(NULL) mConstantBuffer(NULL)
......
...@@ -23,6 +23,7 @@ class ShaderExecutable11 : public ShaderExecutableD3D ...@@ -23,6 +23,7 @@ class ShaderExecutable11 : public ShaderExecutableD3D
ShaderExecutable11(const void *function, size_t length, ID3D11PixelShader *executable); 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, ID3D11VertexShader *executable, ID3D11GeometryShader *streamOut);
ShaderExecutable11(const void *function, size_t length, ID3D11GeometryShader *executable); ShaderExecutable11(const void *function, size_t length, ID3D11GeometryShader *executable);
ShaderExecutable11(const void *function, size_t length, ID3D11ComputeShader *executable);
virtual ~ShaderExecutable11(); virtual ~ShaderExecutable11();
...@@ -30,12 +31,14 @@ class ShaderExecutable11 : public ShaderExecutableD3D ...@@ -30,12 +31,14 @@ class ShaderExecutable11 : public ShaderExecutableD3D
ID3D11VertexShader *getVertexShader() const; ID3D11VertexShader *getVertexShader() const;
ID3D11GeometryShader *getGeometryShader() const; ID3D11GeometryShader *getGeometryShader() const;
ID3D11GeometryShader *getStreamOutShader() const; ID3D11GeometryShader *getStreamOutShader() const;
ID3D11ComputeShader *getComputeShader() const;
private: private:
ID3D11PixelShader *mPixelExecutable; ID3D11PixelShader *mPixelExecutable;
ID3D11VertexShader *mVertexExecutable; ID3D11VertexShader *mVertexExecutable;
ID3D11GeometryShader *mGeometryExecutable; ID3D11GeometryShader *mGeometryExecutable;
ID3D11GeometryShader *mStreamOutExecutable; ID3D11GeometryShader *mStreamOutExecutable;
ID3D11ComputeShader *mComputeExecutable;
}; };
class UniformStorage11 : public UniformStorageD3D class UniformStorage11 : public UniformStorageD3D
......
...@@ -830,6 +830,84 @@ size_t GetMaximumPixelTextureUnits(D3D_FEATURE_LEVEL featureLevel) ...@@ -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) int GetMinimumTexelOffset(D3D_FEATURE_LEVEL featureLevel)
{ {
switch (featureLevel) switch (featureLevel)
...@@ -1160,6 +1238,18 @@ void GenerateCaps(ID3D11Device *device, ID3D11DeviceContext *deviceContext, cons ...@@ -1160,6 +1238,18 @@ void GenerateCaps(ID3D11Device *device, ID3D11DeviceContext *deviceContext, cons
caps->minProgramTexelOffset = GetMinimumTexelOffset(featureLevel); caps->minProgramTexelOffset = GetMinimumTexelOffset(featureLevel);
caps->maxProgramTexelOffset = GetMaximumTexelOffset(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 // Aggregate shader limits
caps->maxUniformBufferBindings = caps->maxVertexUniformBlocks + caps->maxFragmentUniformBlocks; caps->maxUniformBufferBindings = caps->maxVertexUniformBlocks + caps->maxFragmentUniformBlocks;
caps->maxUniformBlockSize = GetMaximumConstantBufferSize(featureLevel); caps->maxUniformBlockSize = GetMaximumConstantBufferSize(featureLevel);
...@@ -1175,6 +1265,9 @@ void GenerateCaps(ID3D11Device *device, ID3D11DeviceContext *deviceContext, cons ...@@ -1175,6 +1265,9 @@ void GenerateCaps(ID3D11Device *device, ID3D11DeviceContext *deviceContext, cons
static_cast<GLint64>(caps->maxVertexUniformComponents); static_cast<GLint64>(caps->maxVertexUniformComponents);
caps->maxCombinedFragmentUniformComponents = (static_cast<GLint64>(caps->maxFragmentUniformBlocks) * static_cast<GLint64>(caps->maxUniformBlockSize / 4)) + caps->maxCombinedFragmentUniformComponents = (static_cast<GLint64>(caps->maxFragmentUniformBlocks) * static_cast<GLint64>(caps->maxUniformBlockSize / 4)) +
static_cast<GLint64>(caps->maxFragmentUniformComponents); static_cast<GLint64>(caps->maxFragmentUniformComponents);
caps->maxCombinedComputeUniformComponents =
static_cast<GLuint>(caps->maxComputeUniformBlocks * (caps->maxUniformBlockSize / 4) +
caps->maxComputeUniformComponents);
caps->maxVaryingComponents = caps->maxVaryingComponents =
static_cast<GLuint>(GetMaximumVertexOutputVectors(featureLevel)) * 4; static_cast<GLuint>(GetMaximumVertexOutputVectors(featureLevel)) * 4;
caps->maxVaryingVectors = static_cast<GLuint>(GetMaximumVertexOutputVectors(featureLevel)); caps->maxVaryingVectors = static_cast<GLuint>(GetMaximumVertexOutputVectors(featureLevel));
......
...@@ -211,6 +211,41 @@ TEST_P(ComputeShaderTest, AttachmentCount) ...@@ -211,6 +211,41 @@ TEST_P(ComputeShaderTest, AttachmentCount)
EXPECT_GL_NO_ERROR(); 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 // Check that it is not possible to create a compute shader when the context does not support ES
// 3.10 // 3.10
TEST_P(ComputeShaderTestES3, NotSupported) TEST_P(ComputeShaderTestES3, NotSupported)
...@@ -220,7 +255,7 @@ TEST_P(ComputeShaderTestES3, NotSupported) ...@@ -220,7 +255,7 @@ TEST_P(ComputeShaderTestES3, NotSupported)
EXPECT_GL_ERROR(GL_INVALID_ENUM); 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()); ANGLE_INSTANTIATE_TEST(ComputeShaderTestES3, ES3_OPENGL(), ES3_OPENGLES());
} // namespace } // namespace
...@@ -335,6 +335,69 @@ TEST_P(ProgramBinaryES3Test, UniformBlockBindingNoDraw) ...@@ -335,6 +335,69 @@ TEST_P(ProgramBinaryES3Test, UniformBlockBindingNoDraw)
ANGLE_INSTANTIATE_TEST(ProgramBinaryES3Test, ES3_D3D11(), ES3_OPENGL(), ES3_OPENGLES()); 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 class ProgramBinaryTransformFeedbackTest : public ANGLETest
{ {
protected: protected:
......
...@@ -491,6 +491,21 @@ PlatformParameters ES3_D3D11_FL10_1() ...@@ -491,6 +491,21 @@ PlatformParameters ES3_D3D11_FL10_1()
return PlatformParameters(3, 0, egl_platform::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() PlatformParameters ES3_D3D11_WARP()
{ {
return PlatformParameters(3, 0, egl_platform::D3D11_WARP()); return PlatformParameters(3, 0, egl_platform::D3D11_WARP());
......
...@@ -113,6 +113,9 @@ PlatformParameters ES3_D3D11(); ...@@ -113,6 +113,9 @@ PlatformParameters ES3_D3D11();
PlatformParameters ES3_D3D11_FL11_1(); PlatformParameters ES3_D3D11_FL11_1();
PlatformParameters ES3_D3D11_FL11_0(); PlatformParameters ES3_D3D11_FL11_0();
PlatformParameters ES3_D3D11_FL10_1(); 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_WARP();
PlatformParameters ES3_D3D11_FL11_1_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