Edit

kc3-lang/angle/src/libANGLE/renderer/d3d/d3d11/ResourceManager11.cpp

Branch :

  • Show log

    Commit

  • Author : Geoff Lang
    Date : 2020-01-29 12:10:17
    Hash : a36f8bd4
    Message : Mark MemoryBuffer allocation functions as NO_DISCARD Not all call sites were checking the return value of MemoryBuffer::resize, mark the return value as NO_DISCARD and fix all the warnings. BUG=chromium:1030835 Change-Id: I762796e3d11efc131a814069d78a195b0d4c9f8f Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2028151 Commit-Queue: Geoff Lang <geofflang@chromium.org> Reviewed-by: Jamie Madill <jmadill@chromium.org>

  • src/libANGLE/renderer/d3d/d3d11/ResourceManager11.cpp
  • //
    // Copyright 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.
    //
    // ResourceManager11:
    //   Centralized point of allocation for all D3D11 Resources.
    
    #include "libANGLE/renderer/d3d/d3d11/ResourceManager11.h"
    
    #include "common/debug.h"
    #include "libANGLE/renderer/d3d/d3d11/Renderer11.h"
    #include "libANGLE/renderer/d3d/d3d11/formatutils11.h"
    
    namespace rx
    {
    
    namespace
    {
    
    constexpr uint8_t kDebugInitTextureDataValue = 0x48;
    constexpr FLOAT kDebugColorInitClearValue[4] = {0.3f, 0.5f, 0.7f, 0.5f};
    constexpr FLOAT kDebugDepthInitValue         = 0.2f;
    constexpr UINT8 kDebugStencilInitValue       = 3;
    
    // A hard limit on buffer size. This works around a problem in the NVIDIA drivers where buffer sizes
    // close to MAX_UINT would give undefined results. The limit of MAX_UINT/2 should be generous enough
    // for almost any demanding application.
    constexpr UINT kMaximumBufferSizeHardLimit = std::numeric_limits<UINT>::max() >> 1;
    
    uint64_t ComputeMippedMemoryUsage(unsigned int width,
                                      unsigned int height,
                                      unsigned int depth,
                                      uint64_t pixelSize,
                                      unsigned int mipLevels)
    {
        uint64_t sizeSum = 0;
    
        for (unsigned int level = 0; level < mipLevels; ++level)
        {
            unsigned int mipWidth  = std::max(width >> level, 1u);
            unsigned int mipHeight = std::max(height >> level, 1u);
            unsigned int mipDepth  = std::max(depth >> level, 1u);
            sizeSum += static_cast<uint64_t>(mipWidth * mipHeight * mipDepth) * pixelSize;
        }
    
        return sizeSum;
    }
    
    uint64_t ComputeMemoryUsage(const D3D11_TEXTURE2D_DESC *desc)
    {
        ASSERT(desc);
        uint64_t pixelBytes =
            static_cast<uint64_t>(d3d11::GetDXGIFormatSizeInfo(desc->Format).pixelBytes);
        return ComputeMippedMemoryUsage(desc->Width, desc->Height, 1, pixelBytes, desc->MipLevels);
    }
    
    uint64_t ComputeMemoryUsage(const D3D11_TEXTURE3D_DESC *desc)
    {
        ASSERT(desc);
        uint64_t pixelBytes =
            static_cast<uint64_t>(d3d11::GetDXGIFormatSizeInfo(desc->Format).pixelBytes);
        return ComputeMippedMemoryUsage(desc->Width, desc->Height, desc->Depth, pixelBytes,
                                        desc->MipLevels);
    }
    
    uint64_t ComputeMemoryUsage(const D3D11_BUFFER_DESC *desc)
    {
        ASSERT(desc);
        return static_cast<uint64_t>(desc->ByteWidth);
    }
    
    template <typename T>
    uint64_t ComputeMemoryUsage(const T *desc)
    {
        return 0;
    }
    
    template <ResourceType ResourceT>
    uint64_t ComputeGenericMemoryUsage(ID3D11DeviceChild *genericResource)
    {
        auto *typedResource = static_cast<GetD3D11Type<ResourceT> *>(genericResource);
        GetDescType<ResourceT> desc;
        typedResource->GetDesc(&desc);
        return ComputeMemoryUsage(&desc);
    }
    
    uint64_t ComputeGenericMemoryUsage(ResourceType resourceType, ID3D11DeviceChild *resource)
    {
        switch (resourceType)
        {
            case ResourceType::Texture2D:
                return ComputeGenericMemoryUsage<ResourceType::Texture2D>(resource);
            case ResourceType::Texture3D:
                return ComputeGenericMemoryUsage<ResourceType::Texture3D>(resource);
            case ResourceType::Buffer:
                return ComputeGenericMemoryUsage<ResourceType::Buffer>(resource);
    
            default:
                return 0;
        }
    }
    
    HRESULT CreateResource(ID3D11Device *device,
                           const D3D11_BLEND_DESC *desc,
                           void * /*initData*/,
                           ID3D11BlendState **blendState)
    {
        return device->CreateBlendState(desc, blendState);
    }
    
    HRESULT CreateResource(ID3D11Device *device,
                           const D3D11_BUFFER_DESC *desc,
                           const D3D11_SUBRESOURCE_DATA *initData,
                           ID3D11Buffer **buffer)
    {
        // Force buffers to be limited to a fixed max size.
        if (desc->ByteWidth > kMaximumBufferSizeHardLimit)
        {
            return E_OUTOFMEMORY;
        }
    
        return device->CreateBuffer(desc, initData, buffer);
    }
    
    HRESULT CreateResource(ID3D11Device *device,
                           const ShaderData *desc,
                           void * /*initData*/,
                           ID3D11ComputeShader **resourceOut)
    {
        return device->CreateComputeShader(desc->get(), desc->size(), nullptr, resourceOut);
    }
    
    HRESULT CreateResource(ID3D11Device *device,
                           const D3D11_DEPTH_STENCIL_DESC *desc,
                           void * /*initData*/,
                           ID3D11DepthStencilState **resourceOut)
    {
        return device->CreateDepthStencilState(desc, resourceOut);
    }
    
    HRESULT CreateResource(ID3D11Device *device,
                           const D3D11_DEPTH_STENCIL_VIEW_DESC *desc,
                           ID3D11Resource *resource,
                           ID3D11DepthStencilView **resourceOut)
    {
        return device->CreateDepthStencilView(resource, desc, resourceOut);
    }
    
    HRESULT CreateResource(ID3D11Device *device,
                           const ShaderData *desc,
                           const std::vector<D3D11_SO_DECLARATION_ENTRY> *initData,
                           ID3D11GeometryShader **resourceOut)
    {
        if (initData)
        {
            return device->CreateGeometryShaderWithStreamOutput(
                desc->get(), desc->size(), initData->data(), static_cast<UINT>(initData->size()),
                nullptr, 0, 0, nullptr, resourceOut);
        }
        else
        {
            return device->CreateGeometryShader(desc->get(), desc->size(), nullptr, resourceOut);
        }
    }
    
    HRESULT CreateResource(ID3D11Device *device,
                           const InputElementArray *desc,
                           const ShaderData *initData,
                           ID3D11InputLayout **resourceOut)
    {
        return device->CreateInputLayout(desc->get(), static_cast<UINT>(desc->size()), initData->get(),
                                         initData->size(), resourceOut);
    }
    
    HRESULT CreateResource(ID3D11Device *device,
                           const ShaderData *desc,
                           void * /*initData*/,
                           ID3D11PixelShader **resourceOut)
    {
        return device->CreatePixelShader(desc->get(), desc->size(), nullptr, resourceOut);
    }
    
    HRESULT CreateResource(ID3D11Device *device,
                           const D3D11_QUERY_DESC *desc,
                           void * /*initData*/,
                           ID3D11Query **resourceOut)
    {
        return device->CreateQuery(desc, resourceOut);
    }
    
    HRESULT CreateResource(ID3D11Device *device,
                           const D3D11_RASTERIZER_DESC *desc,
                           void * /*initData*/,
                           ID3D11RasterizerState **rasterizerState)
    {
        return device->CreateRasterizerState(desc, rasterizerState);
    }
    
    HRESULT CreateResource(ID3D11Device *device,
                           const D3D11_RENDER_TARGET_VIEW_DESC *desc,
                           ID3D11Resource *resource,
                           ID3D11RenderTargetView **renderTargetView)
    {
        return device->CreateRenderTargetView(resource, desc, renderTargetView);
    }
    
    HRESULT CreateResource(ID3D11Device *device,
                           const D3D11_SAMPLER_DESC *desc,
                           void * /*initData*/,
                           ID3D11SamplerState **resourceOut)
    {
        return device->CreateSamplerState(desc, resourceOut);
    }
    
    HRESULT CreateResource(ID3D11Device *device,
                           const D3D11_SHADER_RESOURCE_VIEW_DESC *desc,
                           ID3D11Resource *resource,
                           ID3D11ShaderResourceView **resourceOut)
    {
        return device->CreateShaderResourceView(resource, desc, resourceOut);
    }
    
    HRESULT CreateResource(ID3D11Device *device,
                           const D3D11_UNORDERED_ACCESS_VIEW_DESC *desc,
                           ID3D11Resource *resource,
                           ID3D11UnorderedAccessView **resourceOut)
    {
        return device->CreateUnorderedAccessView(resource, desc, resourceOut);
    }
    
    HRESULT CreateResource(ID3D11Device *device,
                           const D3D11_TEXTURE2D_DESC *desc,
                           const D3D11_SUBRESOURCE_DATA *initData,
                           ID3D11Texture2D **texture)
    {
        return device->CreateTexture2D(desc, initData, texture);
    }
    
    HRESULT CreateResource(ID3D11Device *device,
                           const D3D11_TEXTURE3D_DESC *desc,
                           const D3D11_SUBRESOURCE_DATA *initData,
                           ID3D11Texture3D **texture)
    {
        return device->CreateTexture3D(desc, initData, texture);
    }
    
    HRESULT CreateResource(ID3D11Device *device,
                           const ShaderData *desc,
                           void * /*initData*/,
                           ID3D11VertexShader **resourceOut)
    {
        return device->CreateVertexShader(desc->get(), desc->size(), nullptr, resourceOut);
    }
    
    DXGI_FORMAT GetTypedDepthStencilFormat(DXGI_FORMAT dxgiFormat)
    {
        switch (dxgiFormat)
        {
            case DXGI_FORMAT_R16_TYPELESS:
                return DXGI_FORMAT_D16_UNORM;
            case DXGI_FORMAT_R24G8_TYPELESS:
                return DXGI_FORMAT_D24_UNORM_S8_UINT;
            case DXGI_FORMAT_R32_TYPELESS:
                return DXGI_FORMAT_D32_FLOAT;
            case DXGI_FORMAT_R32G8X24_TYPELESS:
                return DXGI_FORMAT_D32_FLOAT_S8X24_UINT;
            default:
                return dxgiFormat;
        }
    }
    
    template <typename DescT, typename ResourceT>
    angle::Result ClearResource(d3d::Context *context,
                                Renderer11 *renderer,
                                const DescT *desc,
                                ResourceT *texture)
    {
        // No-op.
        return angle::Result::Continue;
    }
    
    template <>
    angle::Result ClearResource(d3d::Context *context,
                                Renderer11 *renderer,
                                const D3D11_TEXTURE2D_DESC *desc,
                                ID3D11Texture2D *texture)
    {
        ID3D11DeviceContext *deviceContext = renderer->getDeviceContext();
    
        if ((desc->BindFlags & D3D11_BIND_DEPTH_STENCIL) != 0)
        {
            D3D11_DEPTH_STENCIL_VIEW_DESC dsvDesc;
            dsvDesc.Flags  = 0;
            dsvDesc.Format = GetTypedDepthStencilFormat(desc->Format);
    
            const auto &format = d3d11_angle::GetFormat(dsvDesc.Format);
            UINT clearFlags    = (format.depthBits > 0 ? D3D11_CLEAR_DEPTH : 0) |
                              (format.stencilBits > 0 ? D3D11_CLEAR_STENCIL : 0);
    
            // Must process each mip level individually.
            for (UINT mipLevel = 0; mipLevel < desc->MipLevels; ++mipLevel)
            {
                if (desc->SampleDesc.Count == 0)
                {
                    dsvDesc.Texture2D.MipSlice = mipLevel;
                    dsvDesc.ViewDimension      = D3D11_DSV_DIMENSION_TEXTURE2D;
                }
                else
                {
                    dsvDesc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2DMS;
                }
    
                d3d11::DepthStencilView dsv;
                ANGLE_TRY(renderer->allocateResource(context, dsvDesc, texture, &dsv));
    
                deviceContext->ClearDepthStencilView(dsv.get(), clearFlags, kDebugDepthInitValue,
                                                     kDebugStencilInitValue);
            }
        }
        else
        {
            ASSERT((desc->BindFlags & D3D11_BIND_RENDER_TARGET) != 0);
            d3d11::RenderTargetView rtv;
            ANGLE_TRY(renderer->allocateResourceNoDesc(context, texture, &rtv));
    
            deviceContext->ClearRenderTargetView(rtv.get(), kDebugColorInitClearValue);
        }
    
        return angle::Result::Continue;
    }
    
    template <>
    angle::Result ClearResource(d3d::Context *context,
                                Renderer11 *renderer,
                                const D3D11_TEXTURE3D_DESC *desc,
                                ID3D11Texture3D *texture)
    {
        ID3D11DeviceContext *deviceContext = renderer->getDeviceContext();
    
        ASSERT((desc->BindFlags & D3D11_BIND_DEPTH_STENCIL) == 0);
        ASSERT((desc->BindFlags & D3D11_BIND_RENDER_TARGET) != 0);
    
        d3d11::RenderTargetView rtv;
        ANGLE_TRY(renderer->allocateResourceNoDesc(context, texture, &rtv));
    
        deviceContext->ClearRenderTargetView(rtv.get(), kDebugColorInitClearValue);
        return angle::Result::Continue;
    }
    
    #define ANGLE_RESOURCE_STRINGIFY_OP(NAME, RESTYPE, D3D11TYPE, DESCTYPE, INITDATATYPE) \
        "Error allocating " #RESTYPE,
    
    constexpr std::array<const char *, NumResourceTypes> kResourceTypeErrors = {
        {ANGLE_RESOURCE_TYPE_OP(Stringify, ANGLE_RESOURCE_STRINGIFY_OP)}};
    static_assert(kResourceTypeErrors[NumResourceTypes - 1] != nullptr,
                  "All members must be initialized.");
    
    }  // anonymous namespace
    
    // ResourceManager11 Implementation.
    ResourceManager11::ResourceManager11() : mInitializeAllocations(false)
    {
        for (auto &count : mAllocatedResourceCounts)
        {
            count = 0;
        }
        for (auto &memorySize : mAllocatedResourceDeviceMemory)
        {
            memorySize = 0;
        }
    }
    
    ResourceManager11::~ResourceManager11()
    {
        for (size_t count : mAllocatedResourceCounts)
        {
            ASSERT(count == 0);
        }
    
        for (uint64_t memorySize : mAllocatedResourceDeviceMemory)
        {
            ASSERT(memorySize == 0);
        }
    }
    
    template <typename T>
    angle::Result ResourceManager11::allocate(d3d::Context *context,
                                              Renderer11 *renderer,
                                              const GetDescFromD3D11<T> *desc,
                                              GetInitDataFromD3D11<T> *initData,
                                              Resource11<T> *resourceOut)
    {
        ID3D11Device *device = renderer->getDevice();
        T *resource          = nullptr;
    
        GetInitDataFromD3D11<T> *shadowInitData = initData;
        if (!shadowInitData && mInitializeAllocations)
        {
            shadowInitData = createInitDataIfNeeded<T>(desc);
        }
    
        HRESULT hr = CreateResource(device, desc, shadowInitData, &resource);
        ANGLE_TRY_HR(context, hr, kResourceTypeErrors[ResourceTypeIndex<T>()]);
    
        if (!shadowInitData && mInitializeAllocations)
        {
            ANGLE_TRY(ClearResource(context, renderer, desc, resource));
        }
    
        ASSERT(resource);
        incrResource(GetResourceTypeFromD3D11<T>(), ComputeMemoryUsage(desc));
        *resourceOut = std::move(Resource11<T>(resource, this));
        return angle::Result::Continue;
    }
    
    void ResourceManager11::incrResource(ResourceType resourceType, uint64_t memorySize)
    {
        size_t typeIndex = ResourceTypeIndex(resourceType);
    
        mAllocatedResourceCounts[typeIndex]++;
        mAllocatedResourceDeviceMemory[typeIndex] += memorySize;
    
        // This checks for integer overflow.
        ASSERT(mAllocatedResourceCounts[typeIndex] > 0);
        ASSERT(mAllocatedResourceDeviceMemory[typeIndex] >= memorySize);
    }
    
    void ResourceManager11::decrResource(ResourceType resourceType, uint64_t memorySize)
    {
        size_t typeIndex = ResourceTypeIndex(resourceType);
    
        ASSERT(mAllocatedResourceCounts[typeIndex] > 0);
        mAllocatedResourceCounts[typeIndex]--;
        ASSERT(mAllocatedResourceDeviceMemory[typeIndex] >= memorySize);
        mAllocatedResourceDeviceMemory[typeIndex] -= memorySize;
    }
    
    void ResourceManager11::onReleaseGeneric(ResourceType resourceType, ID3D11DeviceChild *resource)
    {
        ASSERT(resource);
        decrResource(resourceType, ComputeGenericMemoryUsage(resourceType, resource));
    }
    
    template <>
    const D3D11_SUBRESOURCE_DATA *ResourceManager11::createInitDataIfNeeded<ID3D11Texture2D>(
        const D3D11_TEXTURE2D_DESC *desc)
    {
        ASSERT(desc);
    
        if ((desc->BindFlags & (D3D11_BIND_DEPTH_STENCIL | D3D11_BIND_RENDER_TARGET)) != 0)
        {
            // This will be done using ClearView methods.
            return nullptr;
        }
    
        size_t requiredSize = static_cast<size_t>(ComputeMemoryUsage(desc));
        if (mZeroMemory.size() < requiredSize)
        {
            if (!mZeroMemory.resize(requiredSize))
            {
                ERR() << "Failed to allocate D3D texture initialization data.";
                return nullptr;
            }
            mZeroMemory.fill(kDebugInitTextureDataValue);
        }
    
        const auto &formatSizeInfo = d3d11::GetDXGIFormatSizeInfo(desc->Format);
    
        UINT subresourceCount = desc->MipLevels * desc->ArraySize;
        if (mShadowInitData.size() < subresourceCount)
        {
            mShadowInitData.resize(subresourceCount);
        }
    
        for (UINT mipLevel = 0; mipLevel < desc->MipLevels; ++mipLevel)
        {
            for (UINT arrayIndex = 0; arrayIndex < desc->ArraySize; ++arrayIndex)
            {
                UINT subresourceIndex = D3D11CalcSubresource(mipLevel, arrayIndex, desc->MipLevels);
                D3D11_SUBRESOURCE_DATA *data = &mShadowInitData[subresourceIndex];
    
                UINT levelWidth  = std::max(desc->Width >> mipLevel, 1u);
                UINT levelHeight = std::max(desc->Height >> mipLevel, 1u);
    
                data->SysMemPitch      = levelWidth * formatSizeInfo.pixelBytes;
                data->SysMemSlicePitch = data->SysMemPitch * levelHeight;
                data->pSysMem          = mZeroMemory.data();
            }
        }
    
        return mShadowInitData.data();
    }
    
    template <>
    const D3D11_SUBRESOURCE_DATA *ResourceManager11::createInitDataIfNeeded<ID3D11Texture3D>(
        const D3D11_TEXTURE3D_DESC *desc)
    {
        ASSERT(desc);
    
        if ((desc->BindFlags & D3D11_BIND_RENDER_TARGET) != 0)
        {
            // This will be done using ClearView methods.
            return nullptr;
        }
    
        size_t requiredSize = static_cast<size_t>(ComputeMemoryUsage(desc));
        if (mZeroMemory.size() < requiredSize)
        {
            if (!mZeroMemory.resize(requiredSize))
            {
                ERR() << "Failed to allocate D3D texture initialization data.";
                return nullptr;
            }
            mZeroMemory.fill(kDebugInitTextureDataValue);
        }
    
        const auto &formatSizeInfo = d3d11::GetDXGIFormatSizeInfo(desc->Format);
    
        UINT subresourceCount = desc->MipLevels;
        if (mShadowInitData.size() < subresourceCount)
        {
            mShadowInitData.resize(subresourceCount);
        }
    
        for (UINT mipLevel = 0; mipLevel < desc->MipLevels; ++mipLevel)
        {
            UINT subresourceIndex        = D3D11CalcSubresource(mipLevel, 0, desc->MipLevels);
            D3D11_SUBRESOURCE_DATA *data = &mShadowInitData[subresourceIndex];
    
            UINT levelWidth  = std::max(desc->Width >> mipLevel, 1u);
            UINT levelHeight = std::max(desc->Height >> mipLevel, 1u);
    
            data->SysMemPitch      = levelWidth * formatSizeInfo.pixelBytes;
            data->SysMemSlicePitch = data->SysMemPitch * levelHeight;
            data->pSysMem          = mZeroMemory.data();
        }
    
        return mShadowInitData.data();
    }
    
    template <typename T>
    GetInitDataFromD3D11<T> *ResourceManager11::createInitDataIfNeeded(const GetDescFromD3D11<T> *desc)
    {
        // No-op.
        return nullptr;
    }
    
    void ResourceManager11::setAllocationsInitialized(bool initialize)
    {
        mInitializeAllocations = initialize;
    }
    
    #define ANGLE_INSTANTIATE_OP(NAME, RESTYPE, D3D11TYPE, DESCTYPE, INITDATATYPE) \
                                                                                   \
        template angle::Result ResourceManager11::allocate(                        \
            d3d::Context *, Renderer11 *, const DESCTYPE *, INITDATATYPE *, Resource11<D3D11TYPE> *);
    
    ANGLE_RESOURCE_TYPE_OP(Instantitate, ANGLE_INSTANTIATE_OP)
    }  // namespace rx