Edit

kc3-lang/angle/src/libANGLE/renderer/renderer_utils.cpp

Branch :

  • Show log

    Commit

  • Author : Jamie Madill
    Date : 2018-10-10 16:13:02
    Hash : 1c7f08c3
    Message : Inline RefCountObject::release. Also don't return errors from the object release methods. Not returning errors reduces the amount of code generated. Also we shouldn't be exiting early from destructor type functions. Increases object binding performance. Bug: angleproject:2877 Change-Id: Ieb8120d885b946915e355419825e1f52f31d7b49 Reviewed-on: https://chromium-review.googlesource.com/c/1270218 Reviewed-by: Geoff Lang <geofflang@chromium.org> Commit-Queue: Jamie Madill <jmadill@chromium.org>

  • src/libANGLE/renderer/renderer_utils.cpp
  • //
    // 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.
    //
    
    #include "libANGLE/renderer/renderer_utils.h"
    
    #include "image_util/copyimage.h"
    #include "image_util/imageformats.h"
    
    #include "libANGLE/AttributeMap.h"
    #include "libANGLE/Context.h"
    #include "libANGLE/formatutils.h"
    #include "libANGLE/renderer/ContextImpl.h"
    #include "libANGLE/renderer/Format.h"
    
    #include <string.h>
    #include "common/utilities.h"
    
    namespace rx
    {
    
    namespace
    {
    void CopyColor(gl::ColorF *color)
    {
        // No-op
    }
    
    void PremultiplyAlpha(gl::ColorF *color)
    {
        color->red *= color->alpha;
        color->green *= color->alpha;
        color->blue *= color->alpha;
    }
    
    void UnmultiplyAlpha(gl::ColorF *color)
    {
        if (color->alpha != 0.0f)
        {
            float invAlpha = 1.0f / color->alpha;
            color->red *= invAlpha;
            color->green *= invAlpha;
            color->blue *= invAlpha;
        }
    }
    
    void ClipChannelsR(gl::ColorF *color)
    {
        color->green = 0.0f;
        color->blue  = 0.0f;
        color->alpha = 1.0f;
    }
    
    void ClipChannelsRG(gl::ColorF *color)
    {
        color->blue  = 0.0f;
        color->alpha = 1.0f;
    }
    
    void ClipChannelsRGB(gl::ColorF *color)
    {
        color->alpha = 1.0f;
    }
    
    void ClipChannelsLuminance(gl::ColorF *color)
    {
        color->alpha = 1.0f;
    }
    
    void ClipChannelsAlpha(gl::ColorF *color)
    {
        color->red   = 0.0f;
        color->green = 0.0f;
        color->blue  = 0.0f;
    }
    
    void ClipChannelsNoOp(gl::ColorF *color)
    {
    }
    
    void WriteUintColor(const gl::ColorF &color,
                        PixelWriteFunction colorWriteFunction,
                        uint8_t *destPixelData)
    {
        gl::ColorUI destColor(
            static_cast<unsigned int>(color.red * 255), static_cast<unsigned int>(color.green * 255),
            static_cast<unsigned int>(color.blue * 255), static_cast<unsigned int>(color.alpha * 255));
        colorWriteFunction(reinterpret_cast<const uint8_t *>(&destColor), destPixelData);
    }
    
    void WriteFloatColor(const gl::ColorF &color,
                         PixelWriteFunction colorWriteFunction,
                         uint8_t *destPixelData)
    {
        colorWriteFunction(reinterpret_cast<const uint8_t *>(&color), destPixelData);
    }
    
    template <typename T, int cols, int rows>
    bool TransposeExpandMatrix(T *target, const GLfloat *value)
    {
        constexpr int targetWidth  = 4;
        constexpr int targetHeight = rows;
        constexpr int srcWidth     = rows;
        constexpr int srcHeight    = cols;
    
        constexpr int copyWidth  = std::min(targetHeight, srcWidth);
        constexpr int copyHeight = std::min(targetWidth, srcHeight);
    
        T staging[targetWidth * targetHeight] = {0};
    
        for (int x = 0; x < copyWidth; x++)
        {
            for (int y = 0; y < copyHeight; y++)
            {
                staging[x * targetWidth + y] = static_cast<T>(value[y * srcWidth + x]);
            }
        }
    
        if (memcmp(target, staging, targetWidth * targetHeight * sizeof(T)) == 0)
        {
            return false;
        }
    
        memcpy(target, staging, targetWidth * targetHeight * sizeof(T));
        return true;
    }
    
    template <typename T, int cols, int rows>
    bool ExpandMatrix(T *target, const GLfloat *value)
    {
        constexpr int kTargetWidth  = 4;
        constexpr int kTargetHeight = rows;
        constexpr int kSrcWidth     = cols;
        constexpr int kSrcHeight    = rows;
    
        constexpr int kCopyWidth  = std::min(kTargetWidth, kSrcWidth);
        constexpr int kCopyHeight = std::min(kTargetHeight, kSrcHeight);
    
        T staging[kTargetWidth * kTargetHeight] = {0};
    
        for (int y = 0; y < kCopyHeight; y++)
        {
            for (int x = 0; x < kCopyWidth; x++)
            {
                staging[y * kTargetWidth + x] = static_cast<T>(value[y * kSrcWidth + x]);
            }
        }
    
        if (memcmp(target, staging, kTargetWidth * kTargetHeight * sizeof(T)) == 0)
        {
            return false;
        }
    
        memcpy(target, staging, kTargetWidth * kTargetHeight * sizeof(T));
        return true;
    }
    }  // anonymous namespace
    
    PackPixelsParams::PackPixelsParams()
        : destFormat(nullptr), outputPitch(0), packBuffer(nullptr), offset(0)
    {
    }
    
    PackPixelsParams::PackPixelsParams(const gl::Rectangle &areaIn,
                                       const angle::Format &destFormat,
                                       GLuint outputPitchIn,
                                       bool reverseRowOrderIn,
                                       gl::Buffer *packBufferIn,
                                       ptrdiff_t offsetIn)
        : area(areaIn),
          destFormat(&destFormat),
          outputPitch(outputPitchIn),
          packBuffer(packBufferIn),
          reverseRowOrder(reverseRowOrderIn),
          offset(offsetIn)
    {
    }
    
    void PackPixels(const PackPixelsParams &params,
                    const angle::Format &sourceFormat,
                    int inputPitchIn,
                    const uint8_t *sourceIn,
                    uint8_t *destWithoutOffset)
    {
        uint8_t *destWithOffset = destWithoutOffset + params.offset;
    
        const uint8_t *source = sourceIn;
        int inputPitch        = inputPitchIn;
    
        if (params.reverseRowOrder)
        {
            source += inputPitch * (params.area.height - 1);
            inputPitch = -inputPitch;
        }
    
        if (sourceFormat == *params.destFormat)
        {
            // Direct copy possible
            for (int y = 0; y < params.area.height; ++y)
            {
                memcpy(destWithOffset + y * params.outputPitch, source + y * inputPitch,
                       params.area.width * sourceFormat.pixelBytes);
            }
            return;
        }
    
        PixelCopyFunction fastCopyFunc = sourceFormat.fastCopyFunctions.get(params.destFormat->id);
    
        if (fastCopyFunc)
        {
            // Fast copy is possible through some special function
            for (int y = 0; y < params.area.height; ++y)
            {
                for (int x = 0; x < params.area.width; ++x)
                {
                    uint8_t *dest =
                        destWithOffset + y * params.outputPitch + x * params.destFormat->pixelBytes;
                    const uint8_t *src = source + y * inputPitch + x * sourceFormat.pixelBytes;
    
                    fastCopyFunc(src, dest);
                }
            }
            return;
        }
    
        PixelWriteFunction pixelWriteFunction = params.destFormat->pixelWriteFunction;
        ASSERT(pixelWriteFunction != nullptr);
    
        // Maximum size of any Color<T> type used.
        uint8_t temp[16];
        static_assert(sizeof(temp) >= sizeof(gl::ColorF) && sizeof(temp) >= sizeof(gl::ColorUI) &&
                          sizeof(temp) >= sizeof(gl::ColorI) &&
                          sizeof(temp) >= sizeof(angle::DepthStencil),
                      "Unexpected size of pixel struct.");
    
        PixelReadFunction pixelReadFunction = sourceFormat.pixelReadFunction;
        ASSERT(pixelReadFunction != nullptr);
    
        for (int y = 0; y < params.area.height; ++y)
        {
            for (int x = 0; x < params.area.width; ++x)
            {
                uint8_t *dest =
                    destWithOffset + y * params.outputPitch + x * params.destFormat->pixelBytes;
                const uint8_t *src = source + y * inputPitch + x * sourceFormat.pixelBytes;
    
                // readFunc and writeFunc will be using the same type of color, CopyTexImage
                // will not allow the copy otherwise.
                pixelReadFunction(src, temp);
                pixelWriteFunction(temp, dest);
            }
        }
    }
    
    bool FastCopyFunctionMap::has(angle::FormatID formatID) const
    {
        return (get(formatID) != nullptr);
    }
    
    PixelCopyFunction FastCopyFunctionMap::get(angle::FormatID formatID) const
    {
        for (size_t index = 0; index < mSize; ++index)
        {
            if (mData[index].formatID == formatID)
            {
                return mData[index].func;
            }
        }
    
        return nullptr;
    }
    
    bool ShouldUseDebugLayers(const egl::AttributeMap &attribs)
    {
        EGLAttrib debugSetting =
            attribs.get(EGL_PLATFORM_ANGLE_DEBUG_LAYERS_ENABLED_ANGLE, EGL_DONT_CARE);
    
    // Prefer to enable debug layers if compiling in Debug, and disabled in Release.
    #if defined(ANGLE_ENABLE_ASSERTS)
        return (debugSetting != EGL_FALSE);
    #else
        return (debugSetting == EGL_TRUE);
    #endif  // defined(ANGLE_ENABLE_ASSERTS)
    }
    
    bool ShouldUseVirtualizedContexts(const egl::AttributeMap &attribs, bool defaultValue)
    {
        EGLAttrib virtualizedContextRequest =
            attribs.get(EGL_PLATFORM_ANGLE_CONTEXT_VIRTUALIZATION_ANGLE, EGL_DONT_CARE);
        if (defaultValue)
        {
            return (virtualizedContextRequest != EGL_FALSE);
        }
        else
        {
            return (virtualizedContextRequest == EGL_TRUE);
        }
    }
    
    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)
    {
        using ConversionFunction              = void (*)(gl::ColorF *);
        ConversionFunction conversionFunction = CopyColor;
        if (unpackPremultiplyAlpha != unpackUnmultiplyAlpha)
        {
            if (unpackPremultiplyAlpha)
            {
                conversionFunction = PremultiplyAlpha;
            }
            else
            {
                conversionFunction = UnmultiplyAlpha;
            }
        }
    
        auto clipChannelsFunction = ClipChannelsNoOp;
        switch (destUnsizedFormat)
        {
            case GL_RED:
                clipChannelsFunction = ClipChannelsR;
                break;
            case GL_RG:
                clipChannelsFunction = ClipChannelsRG;
                break;
            case GL_RGB:
                clipChannelsFunction = ClipChannelsRGB;
                break;
            case GL_LUMINANCE:
                clipChannelsFunction = ClipChannelsLuminance;
                break;
            case GL_ALPHA:
                clipChannelsFunction = ClipChannelsAlpha;
                break;
        }
    
        auto writeFunction = (destComponentType == GL_UNSIGNED_INT) ? WriteUintColor : WriteFloatColor;
    
        for (size_t z = 0; z < depth; z++)
        {
            for (size_t y = 0; y < height; y++)
            {
                for (size_t x = 0; x < width; x++)
                {
                    const uint8_t *sourcePixelData =
                        sourceData + y * sourceRowPitch + x * sourcePixelBytes + z * sourceDepthPitch;
    
                    gl::ColorF sourceColor;
                    pixelReadFunction(sourcePixelData, reinterpret_cast<uint8_t *>(&sourceColor));
    
                    conversionFunction(&sourceColor);
                    clipChannelsFunction(&sourceColor);
    
                    size_t destY = 0;
                    if (unpackFlipY)
                    {
                        destY += (height - 1);
                        destY -= y;
                    }
                    else
                    {
                        destY += y;
                    }
    
                    uint8_t *destPixelData =
                        destData + destY * destRowPitch + x * destPixelBytes + z * destDepthPitch;
                    writeFunction(sourceColor, pixelWriteFunction, destPixelData);
                }
            }
        }
    }
    
    // IncompleteTextureSet implementation.
    IncompleteTextureSet::IncompleteTextureSet()
    {
    }
    
    IncompleteTextureSet::~IncompleteTextureSet()
    {
    }
    
    void IncompleteTextureSet::onDestroy(const gl::Context *context)
    {
        // Clear incomplete textures.
        for (auto &incompleteTexture : mIncompleteTextures)
        {
            if (incompleteTexture.get() != nullptr)
            {
                incompleteTexture->onDestroy(context);
                incompleteTexture.set(context, nullptr);
            }
        }
    }
    
    gl::Error IncompleteTextureSet::getIncompleteTexture(
        const gl::Context *context,
        gl::TextureType type,
        MultisampleTextureInitializer *multisampleInitializer,
        gl::Texture **textureOut)
    {
        *textureOut = mIncompleteTextures[type].get();
        if (*textureOut != nullptr)
        {
            return gl::NoError();
        }
    
        ContextImpl *implFactory = context->getImplementation();
    
        const GLubyte color[] = {0, 0, 0, 255};
        const gl::Extents colorSize(1, 1, 1);
        gl::PixelUnpackState unpack;
        unpack.alignment = 1;
        const gl::Box area(0, 0, 0, 1, 1, 1);
    
        // If a texture is external use a 2D texture for the incomplete texture
        gl::TextureType createType = (type == gl::TextureType::External) ? gl::TextureType::_2D : type;
    
        gl::Texture *tex = new gl::Texture(implFactory, std::numeric_limits<GLuint>::max(), createType);
        angle::UniqueObjectPointer<gl::Texture, gl::Context> t(tex, context);
    
        if (createType == gl::TextureType::_2DMultisample)
        {
            ANGLE_TRY(t->setStorageMultisample(context, createType, 1, GL_RGBA8, colorSize, true));
        }
        else
        {
            ANGLE_TRY(t->setStorage(context, createType, 1, GL_RGBA8, colorSize));
        }
    
        if (type == gl::TextureType::CubeMap)
        {
            for (gl::TextureTarget face : gl::AllCubeFaceTextureTargets())
            {
                ANGLE_TRY(t->setSubImage(context, unpack, nullptr, face, 0, area, GL_RGBA,
                                         GL_UNSIGNED_BYTE, color));
            }
        }
        else if (type == gl::TextureType::_2DMultisample)
        {
            // Call a specialized clear function to init a multisample texture.
            ANGLE_TRY(multisampleInitializer->initializeMultisampleTextureToBlack(context, t.get()));
        }
        else
        {
            ANGLE_TRY(t->setSubImage(context, unpack, nullptr,
                                     gl::NonCubeTextureTypeToTarget(createType), 0, area, GL_RGBA,
                                     GL_UNSIGNED_BYTE, color));
        }
    
        ANGLE_TRY(t->syncState(context));
    
        mIncompleteTextures[type].set(context, t.release());
        *textureOut = mIncompleteTextures[type].get();
        return gl::NoError();
    }
    
    #define ANGLE_INSTANTIATE_SET_UNIFORM_MATRIX_FUNC(cols, rows)                            \
        template bool SetFloatUniformMatrix<cols, rows>(unsigned int, unsigned int, GLsizei, \
                                                        GLboolean, const GLfloat *, uint8_t *)
    
    ANGLE_INSTANTIATE_SET_UNIFORM_MATRIX_FUNC(2, 2);
    ANGLE_INSTANTIATE_SET_UNIFORM_MATRIX_FUNC(3, 3);
    ANGLE_INSTANTIATE_SET_UNIFORM_MATRIX_FUNC(4, 4);
    ANGLE_INSTANTIATE_SET_UNIFORM_MATRIX_FUNC(2, 3);
    ANGLE_INSTANTIATE_SET_UNIFORM_MATRIX_FUNC(3, 2);
    ANGLE_INSTANTIATE_SET_UNIFORM_MATRIX_FUNC(2, 4);
    ANGLE_INSTANTIATE_SET_UNIFORM_MATRIX_FUNC(4, 2);
    ANGLE_INSTANTIATE_SET_UNIFORM_MATRIX_FUNC(3, 4);
    ANGLE_INSTANTIATE_SET_UNIFORM_MATRIX_FUNC(4, 3);
    
    #undef ANGLE_INSTANTIATE_SET_UNIFORM_MATRIX_FUNC
    
    template <int cols, int rows>
    bool SetFloatUniformMatrix(unsigned int arrayElementOffset,
                               unsigned int elementCount,
                               GLsizei countIn,
                               GLboolean transpose,
                               const GLfloat *value,
                               uint8_t *targetData)
    {
        unsigned int count =
            std::min(elementCount - arrayElementOffset, static_cast<unsigned int>(countIn));
    
        const unsigned int targetMatrixStride = (4 * rows);
        GLfloat *target                       = reinterpret_cast<GLfloat *>(
            targetData + arrayElementOffset * sizeof(GLfloat) * targetMatrixStride);
    
        bool dirty = false;
    
        for (unsigned int i = 0; i < count; i++)
        {
            if (transpose == GL_FALSE)
            {
                dirty = ExpandMatrix<GLfloat, cols, rows>(target, value) || dirty;
            }
            else
            {
                dirty = TransposeExpandMatrix<GLfloat, cols, rows>(target, value) || dirty;
            }
            target += targetMatrixStride;
            value += cols * rows;
        }
    
        return dirty;
    }
    
    template void GetMatrixUniform<GLint>(GLenum, GLint *, const GLint *, bool);
    template void GetMatrixUniform<GLuint>(GLenum, GLuint *, const GLuint *, bool);
    
    void GetMatrixUniform(GLenum type, GLfloat *dataOut, const GLfloat *source, bool transpose)
    {
        int columns = gl::VariableColumnCount(type);
        int rows    = gl::VariableRowCount(type);
        for (GLint col = 0; col < columns; ++col)
        {
            for (GLint row = 0; row < rows; ++row)
            {
                GLfloat *outptr = dataOut + ((col * rows) + row);
                const GLfloat *inptr =
                    transpose ? source + ((row * 4) + col) : source + ((col * 4) + row);
                *outptr = *inptr;
            }
        }
    }
    
    template <typename NonFloatT>
    void GetMatrixUniform(GLenum type, NonFloatT *dataOut, const NonFloatT *source, bool transpose)
    {
        UNREACHABLE();
    }
    
    const angle::Format &GetFormatFromFormatType(GLenum format, GLenum type)
    {
        GLenum sizedInternalFormat    = gl::GetInternalFormatInfo(format, type).sizedInternalFormat;
        angle::FormatID angleFormatID = angle::Format::InternalFormatToID(sizedInternalFormat);
        return angle::Format::Get(angleFormatID);
    }
    }  // namespace rx