Edit

kc3-lang/angle/src/compiler/translator/ImageFunctionHLSL.cpp

Branch :

  • Show log

    Commit

  • Author : Xinghua Cao
    Date : 2017-10-09 13:38:12
    Hash : 711b7a12
    Message : ES31: Support images in the compiler on D3D backend. BUG=angleproject:1987 TEST=angle_end2end_tests Change-Id: I83f5f9ffda7e676a8f98b963d1f1c50e9463faf4 Reviewed-on: https://chromium-review.googlesource.com/706247 Commit-Queue: Geoff Lang <geofflang@chromium.org> Reviewed-by: Geoff Lang <geofflang@chromium.org>

  • src/compiler/translator/ImageFunctionHLSL.cpp
  • //
    // Copyright (c) 2017 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.
    //
    // ImageFunctionHLSL: Class for writing implementations of ESSL image functions into HLSL output.
    //
    
    #include "compiler/translator/ImageFunctionHLSL.h"
    #include "compiler/translator/UtilsHLSL.h"
    
    namespace sh
    {
    
    // static
    void ImageFunctionHLSL::OutputImageFunctionArgumentList(
        TInfoSinkBase &out,
        const ImageFunctionHLSL::ImageFunction &imageFunction)
    {
        if (imageFunction.readonly)
        {
            out << TextureString(imageFunction.image, imageFunction.imageInternalFormat) << " tex";
        }
        else
        {
            out << RWTextureString(imageFunction.image, imageFunction.imageInternalFormat) << " tex";
        }
    
        if (imageFunction.method == ImageFunctionHLSL::ImageFunction::Method::LOAD ||
            imageFunction.method == ImageFunctionHLSL::ImageFunction::Method::STORE)
        {
            switch (imageFunction.image)
            {
                case EbtImage2D:
                case EbtIImage2D:
                case EbtUImage2D:
                    out << ", int2 p";
                    break;
                case EbtImage3D:
                case EbtIImage3D:
                case EbtUImage3D:
                case EbtImageCube:
                case EbtIImageCube:
                case EbtUImageCube:
                case EbtImage2DArray:
                case EbtIImage2DArray:
                case EbtUImage2DArray:
                    out << ", int3 p";
                    break;
                default:
                    UNREACHABLE();
            }
    
            if (imageFunction.method == ImageFunctionHLSL::ImageFunction::Method::STORE)
            {
                switch (imageFunction.image)
                {
                    case EbtImage2D:
                    case EbtImage3D:
                    case EbtImageCube:
                    case EbtImage2DArray:
                        out << ", float4 data";
                        break;
                    case EbtIImage2D:
                    case EbtIImage3D:
                    case EbtIImageCube:
                    case EbtIImage2DArray:
                        out << ", int4 data";
                        break;
                    case EbtUImage2D:
                    case EbtUImage3D:
                    case EbtUImageCube:
                    case EbtUImage2DArray:
                        out << ", uint4 data";
                        break;
                    default:
                        UNREACHABLE();
                }
            }
        }
    }
    
    // static
    void ImageFunctionHLSL::OutputImageSizeFunctionBody(
        TInfoSinkBase &out,
        const ImageFunctionHLSL::ImageFunction &imageFunction,
        const TString &imageReference)
    {
        if (IsImage3D(imageFunction.image) || IsImage2DArray(imageFunction.image) ||
            IsImageCube(imageFunction.image))
        {
            // "depth" stores either the number of layers in an array texture or 3D depth
            out << "    uint width; uint height; uint depth;\n"
                << "    " << imageReference << ".GetDimensions(width, height, depth);\n";
        }
        else if (IsImage2D(imageFunction.image))
        {
            out << "    uint width; uint height;\n"
                << "    " << imageReference << ".GetDimensions(width, height);\n";
        }
        else
            UNREACHABLE();
    
        if (strcmp(imageFunction.getReturnType(), "int3") == 0)
        {
            out << "    return int3(width, height, depth);\n";
        }
        else
        {
            out << "    return int2(width, height);\n";
        }
    }
    
    // static
    void ImageFunctionHLSL::OutputImageLoadFunctionBody(
        TInfoSinkBase &out,
        const ImageFunctionHLSL::ImageFunction &imageFunction,
        const TString &imageReference)
    {
        if (IsImage3D(imageFunction.image) || IsImage2DArray(imageFunction.image) ||
            IsImageCube(imageFunction.image))
        {
            out << "    return " << imageReference << "[uint3(p.x, p.y, p.z)];\n";
        }
        else if (IsImage2D(imageFunction.image))
        {
            out << "    return " << imageReference << "[uint2(p.x, p.y)];\n";
        }
        else
            UNREACHABLE();
    }
    
    // static
    void ImageFunctionHLSL::OutputImageStoreFunctionBody(
        TInfoSinkBase &out,
        const ImageFunctionHLSL::ImageFunction &imageFunction,
        const TString &imageReference)
    {
        if (IsImage3D(imageFunction.image) || IsImage2DArray(imageFunction.image) ||
            IsImage2D(imageFunction.image) || IsImageCube(imageFunction.image))
        {
            out << "    " << imageReference << "[p] = data;\n";
        }
        else
            UNREACHABLE();
    }
    
    TString ImageFunctionHLSL::ImageFunction::name() const
    {
        TString name = "gl_image";
        if (readonly)
        {
            name += TextureTypeSuffix(image, imageInternalFormat);
        }
        else
        {
            name += RWTextureTypeSuffix(image, imageInternalFormat);
        }
    
        switch (method)
        {
            case Method::SIZE:
                name += "Size";
                break;
            case Method::LOAD:
                name += "Load";
                break;
            case Method::STORE:
                name += "Store";
                break;
            default:
                UNREACHABLE();
        }
    
        return name;
    }
    
    const char *ImageFunctionHLSL::ImageFunction::getReturnType() const
    {
        if (method == ImageFunction::Method::SIZE)
        {
            switch (image)
            {
                case EbtImage2D:
                case EbtIImage2D:
                case EbtUImage2D:
                case EbtImageCube:
                case EbtIImageCube:
                case EbtUImageCube:
                    return "int2";
                case EbtImage3D:
                case EbtIImage3D:
                case EbtUImage3D:
                case EbtImage2DArray:
                case EbtIImage2DArray:
                case EbtUImage2DArray:
                    return "int3";
                default:
                    UNREACHABLE();
            }
        }
        else if (method == ImageFunction::Method::LOAD)
        {
            switch (image)
            {
                case EbtImage2D:
                case EbtImage3D:
                case EbtImageCube:
                case EbtImage2DArray:
                    return "float4";
                case EbtIImage2D:
                case EbtIImage3D:
                case EbtIImageCube:
                case EbtIImage2DArray:
                    return "int4";
                case EbtUImage2D:
                case EbtUImage3D:
                case EbtUImageCube:
                case EbtUImage2DArray:
                    return "uint4";
                default:
                    UNREACHABLE();
            }
        }
        else if (method == ImageFunction::Method::STORE)
        {
            return "void";
        }
        else
        {
            UNREACHABLE();
        }
        return "";
    }
    
    bool ImageFunctionHLSL::ImageFunction::operator<(const ImageFunction &rhs) const
    {
        return std::tie(image, imageInternalFormat, readonly, method) <
               std::tie(rhs.image, rhs.imageInternalFormat, rhs.readonly, rhs.method);
    }
    
    TString ImageFunctionHLSL::useImageFunction(const TString &name,
                                                const TBasicType &type,
                                                TLayoutImageInternalFormat imageInternalFormat,
                                                bool readonly)
    {
        ASSERT(IsImage(type));
        ImageFunction imageFunction;
        imageFunction.image               = type;
        imageFunction.imageInternalFormat = imageInternalFormat;
        imageFunction.readonly            = readonly;
    
        if (name == "imageSize")
        {
            imageFunction.method = ImageFunction::Method::SIZE;
        }
        else if (name == "imageLoad")
        {
            imageFunction.method = ImageFunction::Method::LOAD;
        }
        else if (name == "imageStore")
        {
            imageFunction.method = ImageFunction::Method::STORE;
        }
        else
            UNREACHABLE();
    
        mUsesImage.insert(imageFunction);
        return imageFunction.name();
    }
    
    void ImageFunctionHLSL::imageFunctionHeader(TInfoSinkBase &out)
    {
        for (const ImageFunction &imageFunction : mUsesImage)
        {
            // Function header
            out << imageFunction.getReturnType() << " " << imageFunction.name() << "(";
    
            OutputImageFunctionArgumentList(out, imageFunction);
    
            out << ")\n"
                   "{\n";
    
            TString imageReference("tex");
    
            if (imageFunction.method == ImageFunction::Method::SIZE)
            {
                OutputImageSizeFunctionBody(out, imageFunction, imageReference);
            }
            else if (imageFunction.method == ImageFunction::Method::LOAD)
            {
                OutputImageLoadFunctionBody(out, imageFunction, imageReference);
            }
            else
            {
                OutputImageStoreFunctionBody(out, imageFunction, imageReference);
            }
    
            out << "}\n"
                   "\n";
        }
    }
    
    }  // namespace sh