Edit

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

Branch :

  • Show log

    Commit

  • Author : Jamie Madill
    Date : 2018-07-23 14:59:41
    Hash : 522095f7
    Message : Rename "color" functions to "pixel" functions. This extends of the copy, read and write functions to cover depth and stencil formats. Refactoring change only. Bug: angleproject:2673 Change-Id: I4b0b2f4cf8621051cacd95cdbd6d70f94ca612e2 Reviewed-on: https://chromium-review.googlesource.com/1147152 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,
                                       const gl::PixelPackState &packIn,
                                       gl::Buffer *packBufferIn,
                                       ptrdiff_t offsetIn)
        : area(areaIn),
          destFormat(&destFormat),
          outputPitch(outputPitchIn),
          packBuffer(packBufferIn),
          pack(),
          offset(offsetIn)
    {
        pack.alignment       = packIn.alignment;
        pack.reverseRowOrder = packIn.reverseRowOrder;
    }
    
    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.pack.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,
                           PixelReadFunction pixelReadFunction,
                           uint8_t *destData,
                           size_t destRowPitch,
                           size_t destPixelBytes,
                           PixelWriteFunction pixelWriteFunction,
                           GLenum destUnsizedFormat,
                           GLenum destComponentType,
                           size_t width,
                           size_t height,
                           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 y = 0; y < height; y++)
        {
            for (size_t x = 0; x < width; x++)
            {
                const uint8_t *sourcePixelData = sourceData + y * sourceRowPitch + x * sourcePixelBytes;
    
                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;
                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)
            {
                ANGLE_SWALLOW_ERR(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, 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, 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