Commit e6664f06 by Cooper Partin Committed by Geoff Lang

Added PointSprites Support for renderers that do not support Geometry Shaders

Change-Id: Iae9ac5f8fbba68dba5e49ccda7bb7eebb05c8e9a Reviewed-on: https://chromium-review.googlesource.com/240450Reviewed-by: 's avatarGeoff Lang <geofflang@chromium.org> Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org> Tested-by: 's avatarGeoff Lang <geofflang@chromium.org>
parent 31b5fc62
......@@ -140,8 +140,8 @@ OutputHLSL::OutputHLSL(TParseContext &context, TranslatorHLSL *parentTranslator)
}
else
{
// Reserve registers for dx_DepthRange and dx_ViewAdjust
mUniformHLSL->reserveUniformRegisters(2);
// Reserve registers for dx_DepthRange, dx_ViewAdjust and dx_ViewCoords
mUniformHLSL->reserveUniformRegisters(3);
}
}
......@@ -510,10 +510,11 @@ void OutputHLSL::header(const BuiltInFunctionEmulatorHLSL *builtInFunctionEmulat
out << " float3 dx_DepthRange : packoffset(c0);\n";
}
// dx_ViewAdjust will only be used in Feature Level 9 shaders.
// dx_ViewAdjust and dx_ViewCoords will only be used in Feature Level 9 shaders.
// However, we declare it for all shaders (including Feature Level 10+).
// The bytecode is the same whether we declare it or not, since D3DCompiler removes it if it's unused.
out << " float4 dx_ViewAdjust : packoffset(c1);\n";
out << " float2 dx_ViewCoords : packoffset(c2);\n";
out << "};\n"
"\n";
......@@ -525,7 +526,8 @@ void OutputHLSL::header(const BuiltInFunctionEmulatorHLSL *builtInFunctionEmulat
out << "uniform float3 dx_DepthRange : register(c0);\n";
}
out << "uniform float4 dx_ViewAdjust : register(c1);\n"
out << "uniform float4 dx_ViewAdjust : register(c1);\n";
out << "uniform float2 dx_ViewCoords : register(c2);\n"
"\n";
}
......
......@@ -28,7 +28,8 @@ struct Workarounds
Workarounds()
: mrtPerfWorkaround(false),
setDataFasterThanImageUpload(false),
zeroMaxLodWorkaround(false)
zeroMaxLodWorkaround(false),
useInstancedPointSpriteEmulation(false)
{}
bool mrtPerfWorkaround;
......@@ -40,6 +41,12 @@ struct Workarounds
// This causes problems when (for example) an application creates a mipmapped texture2D, but sets GL_TEXTURE_MIN_FILTER to GL_NEAREST (i.e disables mipmaps).
// To work around this, D3D11 FL9_3 has to create two copies of the texture. The textures' level zeros are identical, but only one texture has mips.
bool zeroMaxLodWorkaround;
// Some renderers do not support Geometry Shaders so the Geometry Shader-based
// PointSprite emulation will not work.
// To work around this, D3D11 FL9_3 has to use a different pointsprite
// emulation that is implemented using instanced quads.
bool useInstancedPointSpriteEmulation;
};
}
......
......@@ -420,6 +420,22 @@ std::string DynamicHLSL::generateVertexShaderForInputLayout(const std::string &s
}
}
// If gl_PointSize is used in the shader then pointsprites rendering is expected.
// If the renderer does not support Geometry shaders then Instanced PointSprite emulation
// may must be used.
bool usesPointSize = sourceShader.find("GL_USES_POINT_SIZE") != std::string::npos;
bool useInstancedPointSpriteEmulation = usesPointSize && mRenderer->getWorkarounds().useInstancedPointSpriteEmulation;
// Instanced PointSprite emulation requires additional entries in the
// VS_INPUT structure to support the vertices that make up the quad vertices.
// These values must be in sync with the cooresponding values added during inputlayout creation
// in InputLayoutCache::applyVertexBuffers().
if (useInstancedPointSpriteEmulation)
{
structHLSL += " float3 spriteVertexPos : SPRITEPOSITION0;\n";
structHLSL += " float2 spriteTexCoord : SPRITETEXCOORD0;\n";
}
std::string replacementHLSL = "struct VS_INPUT\n"
"{\n" +
structHLSL +
......@@ -694,6 +710,7 @@ bool DynamicHLSL::generateShaderLinkHLSL(const gl::Data &data, InfoLog &infoLog,
bool usesFragCoord = fragmentShader->mUsesFragCoord;
bool usesPointCoord = fragmentShader->mUsesPointCoord;
bool usesPointSize = vertexShader->mUsesPointSize;
bool useInstancedPointSpriteEmulation = usesPointSize && mRenderer->getWorkarounds().useInstancedPointSpriteEmulation;
if (usesFragColor && usesFragData)
{
......@@ -720,12 +737,27 @@ bool DynamicHLSL::generateShaderLinkHLSL(const gl::Data &data, InfoLog &infoLog,
}
const std::string &varyingHLSL = generateVaryingHLSL(vertexShader);
// Instanced PointSprite emulation requires that gl_PointCoord is present in the vertex shader VS_OUTPUT
// structure to ensure compatibility with the generated PS_INPUT of the pixel shader.
// GeometryShader PointSprite emulation does not require this additional entry because the
// GS_OUTPUT of the Geometry shader contains the pointCoord value and already matches the PS_INPUT of the
// generated pixel shader.
const SemanticInfo &vertexSemantics = getSemanticInfo(registers, usesFragCoord,
false, usesPointSize, false);
(useInstancedPointSpriteEmulation && usesPointCoord),
usesPointSize, false);
storeUserLinkedVaryings(vertexShader, linkedVaryings);
storeBuiltinLinkedVaryings(vertexSemantics, linkedVaryings);
// Instanced PointSprite emulation requires additional entries originally generated in the
// GeometryShader HLSL. These include pointsize clamp values.
if (useInstancedPointSpriteEmulation)
{
vertexHLSL += "static float minPointSize = " + Str((int)mRenderer->getRendererCaps().minAliasedPointSize) + ".0f;\n"
"static float maxPointSize = " + Str((int)mRenderer->getRendererCaps().maxAliasedPointSize) + ".0f;\n";
}
// Add stub string to be replaced when shader is dynamically defined by its layout
vertexHLSL += "\n" + VERTEX_ATTRIBUTE_STUB_STRING + "\n"
"struct VS_OUTPUT\n" + generateVaryingLinkHLSL(vertexSemantics, varyingHLSL) + "\n"
......@@ -802,6 +834,22 @@ bool DynamicHLSL::generateShaderLinkHLSL(const gl::Data &data, InfoLog &infoLog,
}
}
// Instanced PointSprite emulation requires additional entries to calculate
// the final output vertex positions of the quad that represents each sprite.
if (useInstancedPointSpriteEmulation)
{
vertexHLSL += "\n"
" gl_PointSize = clamp(gl_PointSize, minPointSize, maxPointSize);\n"
" output.dx_Position.xyz += float3(input.spriteVertexPos.x * gl_PointSize / (dx_ViewCoords.x*2), input.spriteVertexPos.y * gl_PointSize / (dx_ViewCoords.y*2), input.spriteVertexPos.z) * output.dx_Position.w;\n"
" output.gl_PointSize = gl_PointSize;\n";
if (usesPointCoord)
{
vertexHLSL += "\n"
" output.gl_PointCoord = input.spriteTexCoord;\n";
}
}
vertexHLSL += "\n"
" return output;\n"
"}\n";
......
......@@ -213,7 +213,12 @@ bool ProgramD3D::usesPointSpriteEmulation() const
bool ProgramD3D::usesGeometryShader() const
{
return usesPointSpriteEmulation();
return usesPointSpriteEmulation() && !usesInstancedPointSpriteEmulation();
}
bool ProgramD3D::usesInstancedPointSpriteEmulation() const
{
return mRenderer->getWorkarounds().useInstancedPointSpriteEmulation;
}
GLint ProgramD3D::getSamplerMapping(gl::SamplerType type, unsigned int samplerIndex, const gl::Caps &caps) const
......
......@@ -58,6 +58,7 @@ class ProgramD3D : public ProgramImpl
bool usesPointSize() const { return mUsesPointSize; }
bool usesPointSpriteEmulation() const;
bool usesGeometryShader() const;
bool usesInstancedPointSpriteEmulation() const;
GLenum getBinaryFormat() { return GL_PROGRAM_BINARY_ANGLE; }
LinkResult load(gl::InfoLog &infoLog, gl::BinaryInputStream *stream);
......
......@@ -76,7 +76,7 @@ gl::Error RendererD3D::drawElements(const gl::Data &data,
return error;
}
if (!applyPrimitiveType(mode, count))
if (!applyPrimitiveType(mode, count, program->usesPointSize()))
{
return gl::Error(GL_NO_ERROR);
}
......@@ -159,7 +159,7 @@ gl::Error RendererD3D::drawArrays(const gl::Data &data,
return error;
}
if (!applyPrimitiveType(mode, count))
if (!applyPrimitiveType(mode, count, program->usesPointSize()))
{
return gl::Error(GL_NO_ERROR);
}
......@@ -204,7 +204,7 @@ gl::Error RendererD3D::drawArrays(const gl::Data &data,
if (!skipDraw(data, mode))
{
error = drawArrays(mode, count, instances, transformFeedbackActive);
error = drawArrays(mode, count, instances, transformFeedbackActive, program->usesPointSize());
if (error.isError())
{
return error;
......
......@@ -92,7 +92,7 @@ class RendererD3D : public Renderer
virtual gl::Error applyShaders(gl::Program *program, const gl::VertexFormat inputLayout[], const gl::Framebuffer *framebuffer,
bool rasterizerDiscard, bool transformFeedbackActive) = 0;
virtual gl::Error applyUniforms(const ProgramImpl &program, const std::vector<gl::LinkedUniform*> &uniformArray) = 0;
virtual bool applyPrimitiveType(GLenum primitiveType, GLsizei elementCount) = 0;
virtual bool applyPrimitiveType(GLenum primitiveType, GLsizei elementCount, bool usesPointSize) = 0;
virtual gl::Error applyVertexBuffer(const gl::State &state, GLint first, GLsizei count, GLsizei instances) = 0;
virtual gl::Error applyIndexBuffer(const GLvoid *indices, gl::Buffer *elementArrayBuffer, GLsizei count, GLenum mode, GLenum type, TranslatedIndexData *indexInfo) = 0;
virtual void applyTransformFeedbackBuffers(const gl::State& state) = 0;
......@@ -156,7 +156,7 @@ class RendererD3D : public Renderer
gl::Error getScratchMemoryBuffer(size_t requestedSize, MemoryBuffer **bufferOut);
protected:
virtual gl::Error drawArrays(GLenum mode, GLsizei count, GLsizei instances, bool transformFeedbackActive) = 0;
virtual gl::Error drawArrays(GLenum mode, GLsizei count, GLsizei instances, bool transformFeedbackActive, bool usesPointSize) = 0;
virtual gl::Error drawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid *indices,
gl::Buffer *elementArrayBuffer, const TranslatedIndexData &indexInfo, GLsizei instances) = 0;
......@@ -201,6 +201,7 @@ struct dx_VertexConstants
{
float depthRange[4];
float viewAdjust[4];
float viewCoords[4];
};
struct dx_PixelConstants
......
......@@ -77,6 +77,9 @@ class InputLayoutCache
UINT mCurrentVertexStrides[gl::MAX_VERTEX_ATTRIBS];
UINT mCurrentVertexOffsets[gl::MAX_VERTEX_ATTRIBS];
ID3D11Buffer *mPointSpriteVertexBuffer;
ID3D11Buffer *mPointSpriteIndexBuffer;
static std::size_t hashInputLayout(const InputLayoutKey &inputLayout);
static bool compareInputLayouts(const InputLayoutKey &a, const InputLayoutKey &b);
......
......@@ -928,6 +928,13 @@ void Renderer11::setViewport(const gl::Rectangle &viewport, float zNear, float z
mPixelConstants.viewCoords[2] = actualViewport.x + (actualViewport.width * 0.5f);
mPixelConstants.viewCoords[3] = actualViewport.y + (actualViewport.height * 0.5f);
// Instanced pointsprite emulation requires ViewCoords to be defined in the
// the vertex shader.
mVertexConstants.viewCoords[0] = mPixelConstants.viewCoords[0];
mVertexConstants.viewCoords[1] = mPixelConstants.viewCoords[1];
mVertexConstants.viewCoords[2] = mPixelConstants.viewCoords[2];
mVertexConstants.viewCoords[3] = mPixelConstants.viewCoords[3];
mPixelConstants.depthFront[0] = (actualZFar - actualZNear) * 0.5f;
mPixelConstants.depthFront[1] = (actualZNear + actualZFar) * 0.5f;
......@@ -943,7 +950,7 @@ void Renderer11::setViewport(const gl::Rectangle &viewport, float zNear, float z
mForceSetViewport = false;
}
bool Renderer11::applyPrimitiveType(GLenum mode, GLsizei count)
bool Renderer11::applyPrimitiveType(GLenum mode, GLsizei count, bool usesPointSize)
{
D3D11_PRIMITIVE_TOPOLOGY primitiveTopology = D3D_PRIMITIVE_TOPOLOGY_UNDEFINED;
......@@ -964,6 +971,14 @@ bool Renderer11::applyPrimitiveType(GLenum mode, GLsizei count)
return false;
}
// If instanced pointsprite emulation is being used and If gl_PointSize is used in the shader,
// GL_POINTS mode is expected to render pointsprites.
// Instanced PointSprite emulation requires that the topology to be D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST.
if (mode == GL_POINTS && usesPointSize && getWorkarounds().useInstancedPointSpriteEmulation)
{
primitiveTopology = D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST;
}
if (primitiveTopology != mCurrentPrimitiveTopology)
{
mDeviceContext->IASetPrimitiveTopology(primitiveTopology);
......@@ -1226,8 +1241,9 @@ void Renderer11::applyTransformFeedbackBuffers(const gl::State& state)
}
}
gl::Error Renderer11::drawArrays(GLenum mode, GLsizei count, GLsizei instances, bool transformFeedbackActive)
gl::Error Renderer11::drawArrays(GLenum mode, GLsizei count, GLsizei instances, bool transformFeedbackActive, bool usesPointSize)
{
bool useInstancedPointSpriteEmulation = usesPointSize && getWorkarounds().useInstancedPointSpriteEmulation;
if (mode == GL_POINTS && transformFeedbackActive)
{
// Since point sprites are generated with a geometry shader, too many vertices will
......@@ -1277,7 +1293,17 @@ gl::Error Renderer11::drawArrays(GLenum mode, GLsizei count, GLsizei instances,
}
else
{
// If gl_PointSize is used and GL_POINTS is specified, then it is expected to render pointsprites.
// If instanced pointsprite emulation is being used the topology is expexted to be
// D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST and DrawIndexedInstanced must be used.
if (mode == GL_POINTS && useInstancedPointSpriteEmulation)
{
mDeviceContext->DrawIndexedInstanced(6, count, 0, 0, 0);
}
else
{
mDeviceContext->Draw(count, 0);
}
return gl::Error(GL_NO_ERROR);
}
}
......
......@@ -81,7 +81,7 @@ class Renderer11 : public RendererD3D
virtual void setViewport(const gl::Rectangle &viewport, float zNear, float zFar, GLenum drawMode, GLenum frontFace,
bool ignoreViewport);
virtual bool applyPrimitiveType(GLenum mode, GLsizei count);
virtual bool applyPrimitiveType(GLenum mode, GLsizei count, bool usesPointSize);
gl::Error applyRenderTarget(const gl::Framebuffer *frameBuffer) override;
virtual gl::Error applyShaders(gl::Program *program, const gl::VertexFormat inputLayout[], const gl::Framebuffer *framebuffer,
bool rasterizerDiscard, bool transformFeedbackActive);
......@@ -91,7 +91,7 @@ class Renderer11 : public RendererD3D
virtual gl::Error applyIndexBuffer(const GLvoid *indices, gl::Buffer *elementArrayBuffer, GLsizei count, GLenum mode, GLenum type, TranslatedIndexData *indexInfo);
virtual void applyTransformFeedbackBuffers(const gl::State &state);
virtual gl::Error drawArrays(GLenum mode, GLsizei count, GLsizei instances, bool transformFeedbackActive);
virtual gl::Error drawArrays(GLenum mode, GLsizei count, GLsizei instances, bool transformFeedbackActive, bool usesPointSize);
virtual gl::Error drawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid *indices,
gl::Buffer *elementArrayBuffer, const TranslatedIndexData &indexInfo, GLsizei instances);
......
......@@ -1142,6 +1142,7 @@ Workarounds GenerateWorkarounds(D3D_FEATURE_LEVEL featureLevel)
workarounds.mrtPerfWorkaround = true;
workarounds.setDataFasterThanImageUpload = true;
workarounds.zeroMaxLodWorkaround = (featureLevel <= D3D_FEATURE_LEVEL_9_3);
workarounds.useInstancedPointSpriteEmulation = (featureLevel <= D3D_FEATURE_LEVEL_9_3);
return workarounds;
}
......
......@@ -1146,7 +1146,7 @@ void Renderer9::setViewport(const gl::Rectangle &viewport, float zNear, float zF
mForceSetViewport = false;
}
bool Renderer9::applyPrimitiveType(GLenum mode, GLsizei count)
bool Renderer9::applyPrimitiveType(GLenum mode, GLsizei count, bool usesPointSize)
{
switch (mode)
{
......@@ -1389,7 +1389,7 @@ void Renderer9::applyTransformFeedbackBuffers(const gl::State& state)
UNREACHABLE();
}
gl::Error Renderer9::drawArrays(GLenum mode, GLsizei count, GLsizei instances, bool transformFeedbackActive)
gl::Error Renderer9::drawArrays(GLenum mode, GLsizei count, GLsizei instances, bool transformFeedbackActive, bool usesPointSize)
{
ASSERT(!transformFeedbackActive);
......
......@@ -87,13 +87,13 @@ class Renderer9 : public RendererD3D
virtual gl::Error applyShaders(gl::Program *program, const gl::VertexFormat inputLayout[], const gl::Framebuffer *framebuffer,
bool rasterizerDiscard, bool transformFeedbackActive);
virtual gl::Error applyUniforms(const ProgramImpl &program, const std::vector<gl::LinkedUniform*> &uniformArray);
virtual bool applyPrimitiveType(GLenum primitiveType, GLsizei elementCount);
virtual bool applyPrimitiveType(GLenum primitiveType, GLsizei elementCount, bool usesPointSize);
virtual gl::Error applyVertexBuffer(const gl::State &state, GLint first, GLsizei count, GLsizei instances);
virtual gl::Error applyIndexBuffer(const GLvoid *indices, gl::Buffer *elementArrayBuffer, GLsizei count, GLenum mode, GLenum type, TranslatedIndexData *indexInfo);
virtual void applyTransformFeedbackBuffers(const gl::State& state);
virtual gl::Error drawArrays(GLenum mode, GLsizei count, GLsizei instances, bool transformFeedbackActive);
virtual gl::Error drawArrays(GLenum mode, GLsizei count, GLsizei instances, bool transformFeedbackActive, bool usesPointSize);
virtual gl::Error drawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid *indices,
gl::Buffer *elementArrayBuffer, const TranslatedIndexData &indexInfo, GLsizei instances);
......
......@@ -565,6 +565,7 @@ Workarounds GenerateWorkarounds()
Workarounds workarounds;
workarounds.mrtPerfWorkaround = true;
workarounds.setDataFasterThanImageUpload = false;
workarounds.useInstancedPointSpriteEmulation = false;
return workarounds;
}
......
......@@ -35,6 +35,7 @@
'<(angle_path)/tests/angle_tests/media/pixel.inl',
'<(angle_path)/tests/angle_tests/OcclusionQueriesTest.cpp',
'<(angle_path)/tests/angle_tests/PBOExtensionTest.cpp',
'<(angle_path)/tests/angle_tests/PointSpritesTest.cpp',
'<(angle_path)/tests/angle_tests/ProgramBinaryTest.cpp',
'<(angle_path)/tests/angle_tests/ReadPixelsTest.cpp',
'<(angle_path)/tests/angle_tests/RendererTest.cpp',
......
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