blob: 663c2a2a5193a7411cb744a6e5a0fed1fc7308b2 [file] [log] [blame]
//
// Copyright 2014 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.
//
// ProgramD3D.h: Defines the rx::ProgramD3D class which implements rx::ProgramImpl.
#ifndef LIBANGLE_RENDERER_D3D_PROGRAMD3D_H_
#define LIBANGLE_RENDERER_D3D_PROGRAMD3D_H_
#include <string>
#include <vector>
#include "compiler/translator/blocklayoutHLSL.h"
#include "libANGLE/Constants.h"
#include "libANGLE/formatutils.h"
#include "libANGLE/renderer/ProgramImpl.h"
#include "libANGLE/renderer/d3d/DynamicHLSL.h"
#include "libANGLE/renderer/d3d/RendererD3D.h"
#include "platform/FeaturesD3D.h"
namespace rx
{
class RendererD3D;
class UniformStorageD3D;
class ShaderExecutableD3D;
#if !defined(ANGLE_COMPILE_OPTIMIZATION_LEVEL)
// WARNING: D3DCOMPILE_OPTIMIZATION_LEVEL3 may lead to a DX9 shader compiler hang.
// It should only be used selectively to work around specific bugs.
# define ANGLE_COMPILE_OPTIMIZATION_LEVEL D3DCOMPILE_OPTIMIZATION_LEVEL1
#endif
enum class HLSLRegisterType : uint8_t
{
None = 0,
Texture = 1,
UnorderedAccessView = 2
};
// Helper struct representing a single shader uniform
// TODO(jmadill): Make uniform blocks shared between all programs, so we don't need separate
// register indices.
struct D3DUniform : private angle::NonCopyable
{
D3DUniform(GLenum type,
HLSLRegisterType reg,
const std::string &nameIn,
const std::vector<unsigned int> &arraySizesIn,
bool defaultBlock);
~D3DUniform();
bool isSampler() const;
bool isImage() const;
bool isImage2D() const;
bool isArray() const { return !arraySizes.empty(); }
unsigned int getArraySizeProduct() const;
bool isReferencedByShader(gl::ShaderType shaderType) const;
const uint8_t *firstNonNullData() const;
const uint8_t *getDataPtrToElement(size_t elementIndex) const;
// Duplicated from the GL layer
const gl::UniformTypeInfo &typeInfo;
std::string name; // Names of arrays don't include [0], unlike at the GL layer.
std::vector<unsigned int> arraySizes;
// Pointer to a system copies of the data. Separate pointers for each uniform storage type.
gl::ShaderMap<uint8_t *> mShaderData;
// Register information.
HLSLRegisterType regType;
gl::ShaderMap<unsigned int> mShaderRegisterIndexes;
unsigned int registerCount;
// Register "elements" are used for uniform structs in ES3, to appropriately identify single
// uniforms
// inside aggregate types, which are packed according C-like structure rules.
unsigned int registerElement;
// Special buffer for sampler values.
std::vector<GLint> mSamplerData;
};
struct D3DInterfaceBlock
{
D3DInterfaceBlock();
D3DInterfaceBlock(const D3DInterfaceBlock &other);
bool activeInShader(gl::ShaderType shaderType) const
{
return mShaderRegisterIndexes[shaderType] != GL_INVALID_INDEX;
}
gl::ShaderMap<unsigned int> mShaderRegisterIndexes;
};
struct D3DVarying final
{
D3DVarying();
D3DVarying(const std::string &semanticNameIn,
unsigned int semanticIndexIn,
unsigned int componentCountIn,
unsigned int outputSlotIn);
D3DVarying(const D3DVarying &) = default;
D3DVarying &operator=(const D3DVarying &) = default;
std::string semanticName;
unsigned int semanticIndex;
unsigned int componentCount;
unsigned int outputSlot;
};
class ProgramD3DMetadata final : angle::NonCopyable
{
public:
ProgramD3DMetadata(RendererD3D *renderer,
const gl::ShaderMap<const ShaderD3D *> &attachedShaders,
EGLenum clientType);
~ProgramD3DMetadata();
int getRendererMajorShaderModel() const;
bool usesBroadcast(const gl::State &data) const;
bool usesSecondaryColor() const;
bool usesFragDepth() const;
bool usesPointCoord() const;
bool usesFragCoord() const;
bool usesPointSize() const;
bool usesInsertedPointCoordValue() const;
bool usesViewScale() const;
bool hasANGLEMultiviewEnabled() const;
bool usesVertexID() const;
bool usesViewID() const;
bool canSelectViewInVertexShader() const;
bool addsPointCoordToVertexShader() const;
bool usesTransformFeedbackGLPosition() const;
bool usesSystemValuePointSize() const;
bool usesMultipleFragmentOuts() const;
bool usesCustomOutVars() const;
const ShaderD3D *getFragmentShader() const;
private:
const int mRendererMajorShaderModel;
const std::string mShaderModelSuffix;
const bool mUsesInstancedPointSpriteEmulation;
const bool mUsesViewScale;
const bool mCanSelectViewInVertexShader;
const gl::ShaderMap<const ShaderD3D *> mAttachedShaders;
const EGLenum mClientType;
};
using D3DUniformMap = std::map<std::string, D3DUniform *>;
class ProgramD3D : public ProgramImpl
{
public:
ProgramD3D(const gl::ProgramState &data, RendererD3D *renderer);
~ProgramD3D() override;
const std::vector<PixelShaderOutputVariable> &getPixelShaderKey() { return mPixelShaderKey; }
GLint getSamplerMapping(gl::ShaderType type,
unsigned int samplerIndex,
const gl::Caps &caps) const;
gl::TextureType getSamplerTextureType(gl::ShaderType type, unsigned int samplerIndex) const;
gl::RangeUI getUsedSamplerRange(gl::ShaderType type) const;
enum SamplerMapping
{
WasDirty,
WasClean,
};
SamplerMapping updateSamplerMapping();
GLint getImageMapping(gl::ShaderType type,
unsigned int imageIndex,
bool readonly,
const gl::Caps &caps) const;
gl::RangeUI getUsedImageRange(gl::ShaderType type, bool readonly) const;
bool usesPointSize() const { return mUsesPointSize; }
bool usesPointSpriteEmulation() const;
bool usesGeometryShader(const gl::State &state, gl::PrimitiveMode drawMode) const;
bool usesGeometryShaderForPointSpriteEmulation() const;
bool usesGetDimensionsIgnoresBaseLevel() const;
bool usesInstancedPointSpriteEmulation() const;
std::unique_ptr<LinkEvent> load(const gl::Context *context,
gl::BinaryInputStream *stream,
gl::InfoLog &infoLog) override;
void save(const gl::Context *context, gl::BinaryOutputStream *stream) override;
void setBinaryRetrievableHint(bool retrievable) override;
void setSeparable(bool separable) override;
angle::Result getVertexExecutableForCachedInputLayout(d3d::Context *context,
ShaderExecutableD3D **outExectuable,
gl::InfoLog *infoLog);
angle::Result getGeometryExecutableForPrimitiveType(d3d::Context *errContext,
const gl::State &state,
gl::PrimitiveMode drawMode,
ShaderExecutableD3D **outExecutable,
gl::InfoLog *infoLog);
angle::Result getPixelExecutableForCachedOutputLayout(d3d::Context *context,
ShaderExecutableD3D **outExectuable,
gl::InfoLog *infoLog);
#if defined(STARBOARD)
angle::Result getPixelExecutableForCachedHdrOutputLayout(d3d::Context *context,
ShaderExecutableD3D **outExectuable,
gl::InfoLog *infoLog);
#endif // STARBOARD
angle::Result getComputeExecutableForImage2DBindLayout(d3d::Context *context,
ShaderExecutableD3D **outExecutable,
gl::InfoLog *infoLog);
std::unique_ptr<LinkEvent> link(const gl::Context *context,
const gl::ProgramLinkedResources &resources,
gl::InfoLog &infoLog) override;
GLboolean validate(const gl::Caps &caps, gl::InfoLog *infoLog) override;
void setPathFragmentInputGen(const std::string &inputName,
GLenum genMode,
GLint components,
const GLfloat *coeffs) override;
void updateUniformBufferCache(const gl::Caps &caps,
const gl::ShaderMap<unsigned int> &reservedShaderRegisterIndexes);
unsigned int getAtomicCounterBufferRegisterIndex(GLuint binding,
gl::ShaderType shaderType) const;
unsigned int getShaderStorageBufferRegisterIndex(GLuint blockIndex,
gl::ShaderType shaderType) const;
const std::vector<GLint> &getShaderUniformBufferCache(gl::ShaderType shaderType) const;
void dirtyAllUniforms();
void setUniform1fv(GLint location, GLsizei count, const GLfloat *v) override;
void setUniform2fv(GLint location, GLsizei count, const GLfloat *v) override;
void setUniform3fv(GLint location, GLsizei count, const GLfloat *v) override;
void setUniform4fv(GLint location, GLsizei count, const GLfloat *v) override;
void setUniform1iv(GLint location, GLsizei count, const GLint *v) override;
void setUniform2iv(GLint location, GLsizei count, const GLint *v) override;
void setUniform3iv(GLint location, GLsizei count, const GLint *v) override;
void setUniform4iv(GLint location, GLsizei count, const GLint *v) override;
void setUniform1uiv(GLint location, GLsizei count, const GLuint *v) override;
void setUniform2uiv(GLint location, GLsizei count, const GLuint *v) override;
void setUniform3uiv(GLint location, GLsizei count, const GLuint *v) override;
void setUniform4uiv(GLint location, GLsizei count, const GLuint *v) override;
void setUniformMatrix2fv(GLint location,
GLsizei count,
GLboolean transpose,
const GLfloat *value) override;
void setUniformMatrix3fv(GLint location,
GLsizei count,
GLboolean transpose,
const GLfloat *value) override;
void setUniformMatrix4fv(GLint location,
GLsizei count,
GLboolean transpose,
const GLfloat *value) override;
void setUniformMatrix2x3fv(GLint location,
GLsizei count,
GLboolean transpose,
const GLfloat *value) override;
void setUniformMatrix3x2fv(GLint location,
GLsizei count,
GLboolean transpose,
const GLfloat *value) override;
void setUniformMatrix2x4fv(GLint location,
GLsizei count,
GLboolean transpose,
const GLfloat *value) override;
void setUniformMatrix4x2fv(GLint location,
GLsizei count,
GLboolean transpose,
const GLfloat *value) override;
void setUniformMatrix3x4fv(GLint location,
GLsizei count,
GLboolean transpose,
const GLfloat *value) override;
void setUniformMatrix4x3fv(GLint location,
GLsizei count,
GLboolean transpose,
const GLfloat *value) override;
void getUniformfv(const gl::Context *context, GLint location, GLfloat *params) const override;
void getUniformiv(const gl::Context *context, GLint location, GLint *params) const override;
void getUniformuiv(const gl::Context *context, GLint location, GLuint *params) const override;
UniformStorageD3D *getShaderUniformStorage(gl::ShaderType shaderType) const
{
return mShaderUniformStorages[shaderType].get();
}
unsigned int getSerial() const;
const AttribIndexArray &getAttribLocationToD3DSemantics() const
{
return mAttribLocationToD3DSemantic;
}
void updateCachedInputLayout(Serial associatedSerial, const gl::State &state);
void updateCachedOutputLayout(const gl::Context *context, const gl::Framebuffer *framebuffer);
void updateCachedComputeImage2DBindLayout(const gl::Context *context);
bool isSamplerMappingDirty() { return mDirtySamplerMapping; }
// Checks if we need to recompile certain shaders.
bool hasVertexExecutableForCachedInputLayout();
bool hasGeometryExecutableForPrimitiveType(const gl::State &state, gl::PrimitiveMode drawMode);
bool hasPixelExecutableForCachedOutputLayout();
bool hasComputeExecutableForCachedImage2DBindLayout();
bool anyShaderUniformsDirty() const { return mShaderUniformsDirty.any(); }
bool areShaderUniformsDirty(gl::ShaderType shaderType) const
{
return mShaderUniformsDirty[shaderType];
}
const std::vector<D3DUniform *> &getD3DUniforms() const { return mD3DUniforms; }
void markUniformsClean();
const gl::ProgramState &getState() const { return mState; }
bool hasShaderStage(gl::ShaderType shaderType) const
{
return mState.getLinkedShaderStages()[shaderType];
}
void assignImage2DRegisters(unsigned int startImageIndex,
int startLogicalImageUnit,
bool readonly);
bool hasNamedUniform(const std::string &name);
bool usesVertexID() const { return mUsesVertexID; }
private:
// These forward-declared tasks are used for multi-thread shader compiles.
class GetExecutableTask;
class GetVertexExecutableTask;
class GetPixelExecutableTask;
class GetGeometryExecutableTask;
class GetComputeExecutableTask;
class GraphicsProgramLinkEvent;
class ComputeProgramLinkEvent;
class LoadBinaryTask;
class LoadBinaryLinkEvent;
class VertexExecutable
{
public:
enum HLSLAttribType
{
FLOAT,
UNSIGNED_INT,
SIGNED_INT,
};
typedef std::vector<HLSLAttribType> Signature;
VertexExecutable(const gl::InputLayout &inputLayout,
const Signature &signature,
ShaderExecutableD3D *shaderExecutable);
~VertexExecutable();
bool matchesSignature(const Signature &signature) const;
static void getSignature(RendererD3D *renderer,
const gl::InputLayout &inputLayout,
Signature *signatureOut);
const gl::InputLayout &inputs() const { return mInputs; }
const Signature &signature() const { return mSignature; }
ShaderExecutableD3D *shaderExecutable() const { return mShaderExecutable; }
private:
static HLSLAttribType GetAttribType(GLenum type);
gl::InputLayout mInputs;
Signature mSignature;
ShaderExecutableD3D *mShaderExecutable;
};
class PixelExecutable
{
public:
PixelExecutable(const std::vector<GLenum> &outputSignature,
ShaderExecutableD3D *shaderExecutable);
~PixelExecutable();
bool matchesSignature(const std::vector<GLenum> &signature) const
{
return mOutputSignature == signature;
}
const std::vector<GLenum> &outputSignature() const { return mOutputSignature; }
ShaderExecutableD3D *shaderExecutable() const { return mShaderExecutable; }
private:
std::vector<GLenum> mOutputSignature;
ShaderExecutableD3D *mShaderExecutable;
};
class ComputeExecutable
{
public:
ComputeExecutable(const gl::ImageUnitTextureTypeMap &signature,
std::unique_ptr<ShaderExecutableD3D> shaderExecutable);
~ComputeExecutable();
bool matchesSignature(const gl::ImageUnitTextureTypeMap &signature) const
{
return mSignature == signature;
}
const gl::ImageUnitTextureTypeMap &signature() const { return mSignature; }
ShaderExecutableD3D *shaderExecutable() const { return mShaderExecutable.get(); }
private:
gl::ImageUnitTextureTypeMap mSignature;
std::unique_ptr<ShaderExecutableD3D> mShaderExecutable;
};
struct Sampler
{
Sampler();
bool active;
GLint logicalTextureUnit;
gl::TextureType textureType;
};
struct Image
{
Image();
bool active;
GLint logicalImageUnit;
};
void initializeUniformStorage(const gl::ShaderBitSet &availableShaderStages);
void defineUniformsAndAssignRegisters();
void defineUniformBase(const gl::Shader *shader,
const sh::ShaderVariable &uniform,
D3DUniformMap *uniformMap);
void assignAllSamplerRegisters();
void assignSamplerRegisters(size_t uniformIndex);
static void AssignSamplers(unsigned int startSamplerIndex,
const gl::UniformTypeInfo &typeInfo,
unsigned int samplerCount,
std::vector<Sampler> &outSamplers,
gl::RangeUI *outUsedRange);
void assignAllImageRegisters();
void assignAllAtomicCounterRegisters();
void assignImageRegisters(size_t uniformIndex);
static void AssignImages(unsigned int startImageIndex,
int startLogicalImageUnit,
unsigned int imageCount,
std::vector<Image> &outImages,
gl::RangeUI *outUsedRange);
template <typename DestT>
void getUniformInternal(GLint location, DestT *dataOut) const;
template <typename T>
void setUniformImpl(const gl::VariableLocation &locationInfo,
GLsizei count,
const T *v,
uint8_t *targetData,
GLenum uniformType);
template <typename T>
void setUniformInternal(GLint location, GLsizei count, const T *v, GLenum uniformType);
template <int cols, int rows>
void setUniformMatrixfvInternal(GLint location,
GLsizei count,
GLboolean transpose,
const GLfloat *value);
std::unique_ptr<LinkEvent> compileProgramExecutables(const gl::Context *context,
gl::InfoLog &infoLog);
std::unique_ptr<LinkEvent> compileComputeExecutable(const gl::Context *context,
gl::InfoLog &infoLog);
angle::Result loadBinaryShaderExecutables(d3d::Context *contextD3D,
gl::BinaryInputStream *stream,
gl::InfoLog &infoLog);
void gatherTransformFeedbackVaryings(const gl::VaryingPacking &varyings,
const BuiltinInfo &builtins);
D3DUniform *getD3DUniformFromLocation(GLint location);
const D3DUniform *getD3DUniformFromLocation(GLint location) const;
void initAttribLocationsToD3DSemantic();
void reset();
void initializeUniformBlocks();
void initializeShaderStorageBlocks();
void updateCachedInputLayoutFromShader();
void updateCachedOutputLayoutFromShader();
void updateCachedImage2DBindLayoutFromComputeShader();
void updateCachedVertexExecutableIndex();
void updateCachedPixelExecutableIndex();
void updateCachedComputeExecutableIndex();
void linkResources(const gl::ProgramLinkedResources &resources);
RendererD3D *mRenderer;
DynamicHLSL *mDynamicHLSL;
std::vector<std::unique_ptr<VertexExecutable>> mVertexExecutables;
std::vector<std::unique_ptr<PixelExecutable>> mPixelExecutables;
angle::PackedEnumMap<gl::PrimitiveMode, std::unique_ptr<ShaderExecutableD3D>>
mGeometryExecutables;
std::vector<std::unique_ptr<ComputeExecutable>> mComputeExecutables;
#if defined(STARBOARD)
std::unique_ptr<PixelExecutable> mPixelHdrExecutable;
#endif // STARBOARD
gl::ShaderMap<std::string> mShaderHLSL;
gl::ShaderMap<angle::CompilerWorkaroundsD3D> mShaderWorkarounds;
bool mUsesFragDepth;
bool mHasANGLEMultiviewEnabled;
bool mUsesVertexID;
bool mUsesViewID;
std::vector<PixelShaderOutputVariable> mPixelShaderKey;
// Common code for all dynamic geometry shaders. Consists mainly of the GS input and output
// structures, built from the linked varying info. We store the string itself instead of the
// packed varyings for simplicity.
std::string mGeometryShaderPreamble;
bool mUsesPointSize;
bool mUsesFlatInterpolation;
gl::ShaderMap<std::unique_ptr<UniformStorageD3D>> mShaderUniformStorages;
gl::ShaderMap<std::vector<Sampler>> mShaderSamplers;
gl::ShaderMap<gl::RangeUI> mUsedShaderSamplerRanges;
bool mDirtySamplerMapping;
std::vector<Image> mImagesCS;
std::vector<Image> mReadonlyImagesCS;
gl::RangeUI mUsedComputeImageRange;
gl::RangeUI mUsedComputeReadonlyImageRange;
gl::RangeUI mUsedComputeAtomicCounterRange;
// Cache for pixel shader output layout to save reallocations.
std::vector<GLenum> mPixelShaderOutputLayoutCache;
Optional<size_t> mCachedPixelExecutableIndex;
AttribIndexArray mAttribLocationToD3DSemantic;
unsigned int mSerial;
gl::ShaderMap<std::vector<int>> mShaderUBOCaches;
VertexExecutable::Signature mCachedVertexSignature;
gl::InputLayout mCachedInputLayout;
Optional<size_t> mCachedVertexExecutableIndex;
std::vector<D3DVarying> mStreamOutVaryings;
std::vector<D3DUniform *> mD3DUniforms;
std::map<std::string, int> mImageBindingMap;
std::map<std::string, int> mAtomicBindingMap;
std::vector<D3DInterfaceBlock> mD3DUniformBlocks;
std::vector<D3DInterfaceBlock> mD3DShaderStorageBlocks;
std::array<unsigned int, gl::IMPLEMENTATION_MAX_ATOMIC_COUNTER_BUFFERS>
mComputeAtomicCounterBufferRegisterIndices;
std::vector<sh::ShaderVariable> mImage2DUniforms;
gl::ImageUnitTextureTypeMap mComputeShaderImage2DBindLayoutCache;
Optional<size_t> mCachedComputeExecutableIndex;
gl::ShaderBitSet mShaderUniformsDirty;
static unsigned int issueSerial();
static unsigned int mCurrentSerial;
Serial mCurrentVertexArrayStateSerial;
};
} // namespace rx
#endif // LIBANGLE_RENDERER_D3D_PROGRAMD3D_H_