// // Copyright 2016 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. // // renderer_utils: // Helper methods pertaining to most or all back-ends. // #ifndef LIBANGLE_RENDERER_RENDERER_UTILS_H_ #define LIBANGLE_RENDERER_RENDERER_UTILS_H_ #include #include #include #include #include "common/angleutils.h" #include "common/utilities.h" #include "libANGLE/angletypes.h" namespace angle { struct FeatureSetBase; struct Format; enum class FormatID; } // namespace angle namespace gl { struct FormatType; struct InternalFormat; class State; } // namespace gl namespace egl { class AttributeMap; struct DisplayState; } // namespace egl namespace rx { class ContextImpl; class ResourceSerial { public: constexpr ResourceSerial() : mValue(kDirty) {} explicit constexpr ResourceSerial(uintptr_t value) : mValue(value) {} constexpr bool operator==(ResourceSerial other) const { return mValue == other.mValue; } constexpr bool operator!=(ResourceSerial other) const { return mValue != other.mValue; } void dirty() { mValue = kDirty; } void clear() { mValue = kEmpty; } constexpr bool valid() const { return mValue != kEmpty && mValue != kDirty; } constexpr bool empty() const { return mValue == kEmpty; } private: constexpr static uintptr_t kDirty = std::numeric_limits::max(); constexpr static uintptr_t kEmpty = 0; uintptr_t mValue; }; class Serial final { public: constexpr Serial() : mValue(kInvalid) {} constexpr Serial(const Serial &other) = default; Serial &operator=(const Serial &other) = default; constexpr bool operator==(const Serial &other) const { return mValue != kInvalid && mValue == other.mValue; } constexpr bool operator==(uint32_t value) const { return mValue != kInvalid && mValue == static_cast(value); } constexpr bool operator!=(const Serial &other) const { return mValue == kInvalid || mValue != other.mValue; } constexpr bool operator>(const Serial &other) const { return mValue > other.mValue; } constexpr bool operator>=(const Serial &other) const { return mValue >= other.mValue; } constexpr bool operator<(const Serial &other) const { return mValue < other.mValue; } constexpr bool operator<=(const Serial &other) const { return mValue <= other.mValue; } constexpr bool operator<(uint32_t value) const { return mValue < static_cast(value); } // Useful for serialization. constexpr uint64_t getValue() const { return mValue; } private: template friend class SerialFactoryBase; constexpr explicit Serial(uint64_t value) : mValue(value) {} uint64_t mValue; static constexpr uint64_t kInvalid = 0; }; template class SerialFactoryBase final : angle::NonCopyable { public: SerialFactoryBase() : mSerial(1) {} Serial generate() { ASSERT(mSerial + 1 > mSerial); return Serial(mSerial++); } private: SerialBaseType mSerial; }; using SerialFactory = SerialFactoryBase; using AtomicSerialFactory = SerialFactoryBase>; using MipGenerationFunction = void (*)(size_t sourceWidth, size_t sourceHeight, size_t sourceDepth, const uint8_t *sourceData, size_t sourceRowPitch, size_t sourceDepthPitch, uint8_t *destData, size_t destRowPitch, size_t destDepthPitch); typedef void (*PixelReadFunction)(const uint8_t *source, uint8_t *dest); typedef void (*PixelWriteFunction)(const uint8_t *source, uint8_t *dest); typedef void (*PixelCopyFunction)(const uint8_t *source, uint8_t *dest); class FastCopyFunctionMap { public: struct Entry { angle::FormatID formatID; PixelCopyFunction func; }; constexpr FastCopyFunctionMap() : FastCopyFunctionMap(nullptr, 0) {} constexpr FastCopyFunctionMap(const Entry *data, size_t size) : mSize(size), mData(data) {} bool has(angle::FormatID formatID) const; PixelCopyFunction get(angle::FormatID formatID) const; private: size_t mSize; const Entry *mData; }; struct PackPixelsParams { PackPixelsParams(); PackPixelsParams(const gl::Rectangle &area, const angle::Format &destFormat, GLuint outputPitch, bool reverseRowOrderIn, gl::Buffer *packBufferIn, ptrdiff_t offset); gl::Rectangle area; const angle::Format *destFormat; GLuint outputPitch; gl::Buffer *packBuffer; bool reverseRowOrder; ptrdiff_t offset; }; void PackPixels(const PackPixelsParams ¶ms, const angle::Format &sourceFormat, int inputPitch, const uint8_t *source, uint8_t *destination); using InitializeTextureDataFunction = void (*)(size_t width, size_t height, size_t depth, uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch); using LoadImageFunction = void (*)(size_t width, size_t height, size_t depth, const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch); struct LoadImageFunctionInfo { LoadImageFunctionInfo() : loadFunction(nullptr), requiresConversion(false) {} LoadImageFunctionInfo(LoadImageFunction loadFunction, bool requiresConversion) : loadFunction(loadFunction), requiresConversion(requiresConversion) {} LoadImageFunction loadFunction; bool requiresConversion; }; using LoadFunctionMap = LoadImageFunctionInfo (*)(GLenum); bool ShouldUseDebugLayers(const egl::AttributeMap &attribs); bool ShouldUseVirtualizedContexts(const egl::AttributeMap &attribs, bool defaultValue); void CopyImageCHROMIUM(const uint8_t *sourceData, size_t sourceRowPitch, size_t sourcePixelBytes, size_t sourceDepthPitch, PixelReadFunction pixelReadFunction, uint8_t *destData, size_t destRowPitch, size_t destPixelBytes, size_t destDepthPitch, PixelWriteFunction pixelWriteFunction, GLenum destUnsizedFormat, GLenum destComponentType, size_t width, size_t height, size_t depth, bool unpackFlipY, bool unpackPremultiplyAlpha, bool unpackUnmultiplyAlpha); // Incomplete textures are 1x1 textures filled with black, used when samplers are incomplete. // This helper class encapsulates handling incomplete textures. Because the GL back-end // can take advantage of the driver's incomplete textures, and because clearing multisample // textures is so difficult, we can keep an instance of this class in the back-end instead // of moving the logic to the Context front-end. // This interface allows us to call-back to init a multisample texture. class MultisampleTextureInitializer { public: virtual ~MultisampleTextureInitializer() {} virtual angle::Result initializeMultisampleTextureToBlack(const gl::Context *context, gl::Texture *glTexture) = 0; }; class IncompleteTextureSet final : angle::NonCopyable { public: IncompleteTextureSet(); ~IncompleteTextureSet(); void onDestroy(const gl::Context *context); angle::Result getIncompleteTexture(const gl::Context *context, gl::TextureType type, MultisampleTextureInitializer *multisampleInitializer, gl::Texture **textureOut); private: gl::TextureMap mIncompleteTextures; }; // Helpers to set a matrix uniform value based on GLSL or HLSL semantics. // The return value indicate if the data was updated or not. template struct SetFloatUniformMatrixGLSL { static bool Run(unsigned int arrayElementOffset, unsigned int elementCount, GLsizei countIn, GLboolean transpose, const GLfloat *value, uint8_t *targetData); }; template struct SetFloatUniformMatrixHLSL { static bool Run(unsigned int arrayElementOffset, unsigned int elementCount, GLsizei countIn, GLboolean transpose, const GLfloat *value, uint8_t *targetData); }; // Helper method to de-tranpose a matrix uniform for an API query. void GetMatrixUniform(GLenum type, GLfloat *dataOut, const GLfloat *source, bool transpose); template void GetMatrixUniform(GLenum type, NonFloatT *dataOut, const NonFloatT *source, bool transpose); const angle::Format &GetFormatFromFormatType(GLenum format, GLenum type); angle::Result ComputeStartVertex(ContextImpl *contextImpl, const gl::IndexRange &indexRange, GLint baseVertex, GLint *firstVertexOut); angle::Result GetVertexRangeInfo(const gl::Context *context, GLint firstVertex, GLsizei vertexOrIndexCount, gl::DrawElementsType indexTypeOrInvalid, const void *indices, GLint baseVertex, GLint *startVertexOut, size_t *vertexCountOut); gl::Rectangle ClipRectToScissor(const gl::State &glState, const gl::Rectangle &rect, bool invertY); // Helper method to intialize a FeatureSet with overrides from the DisplayState void OverrideFeaturesWithDisplayState(angle::FeatureSetBase *features, const egl::DisplayState &state); template size_t LineLoopRestartIndexCountHelper(GLsizei indexCount, const uint8_t *srcPtr) { constexpr In restartIndex = gl::GetPrimitiveRestartIndexFromType(); const In *inIndices = reinterpret_cast(srcPtr); size_t numIndices = 0; // See CopyLineLoopIndicesWithRestart() below for more info on how // numIndices is calculated. GLsizei loopStartIndex = 0; for (GLsizei curIndex = 0; curIndex < indexCount; curIndex++) { In vertex = inIndices[curIndex]; if (vertex != restartIndex) { numIndices++; } else { if (curIndex > loopStartIndex) { numIndices += 2; } loopStartIndex = curIndex + 1; } } if (indexCount > loopStartIndex) { numIndices++; } return numIndices; } inline size_t GetLineLoopWithRestartIndexCount(gl::DrawElementsType glIndexType, GLsizei indexCount, const uint8_t *srcPtr) { switch (glIndexType) { case gl::DrawElementsType::UnsignedByte: return LineLoopRestartIndexCountHelper(indexCount, srcPtr); case gl::DrawElementsType::UnsignedShort: return LineLoopRestartIndexCountHelper(indexCount, srcPtr); case gl::DrawElementsType::UnsignedInt: return LineLoopRestartIndexCountHelper(indexCount, srcPtr); default: UNREACHABLE(); return 0; } } // Writes the line-strip vertices for a line loop to outPtr, // where outLimit is calculated as in GetPrimitiveRestartIndexCount. template void CopyLineLoopIndicesWithRestart(GLsizei indexCount, const uint8_t *srcPtr, uint8_t *outPtr) { constexpr In restartIndex = gl::GetPrimitiveRestartIndexFromType(); constexpr Out outRestartIndex = gl::GetPrimitiveRestartIndexFromType(); const In *inIndices = reinterpret_cast(srcPtr); Out *outIndices = reinterpret_cast(outPtr); GLsizei loopStartIndex = 0; for (GLsizei curIndex = 0; curIndex < indexCount; curIndex++) { In vertex = inIndices[curIndex]; if (vertex != restartIndex) { *(outIndices++) = static_cast(vertex); } else { if (curIndex > loopStartIndex) { // Emit an extra vertex only if the loop is not empty. *(outIndices++) = inIndices[loopStartIndex]; // Then restart the strip. *(outIndices++) = outRestartIndex; } loopStartIndex = curIndex + 1; } } if (indexCount > loopStartIndex) { // Close the last loop if not empty. *(outIndices++) = inIndices[loopStartIndex]; } } } // namespace rx #endif // LIBANGLE_RENDERER_RENDERER_UTILS_H_