• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1//
2// Copyright 2019 The ANGLE Project Authors. All rights reserved.
3// Use of this source code is governed by a BSD-style license that can be
4// found in the LICENSE file.
5//
6// RenderBufferMtl.mm:
7//    Implements the class methods for RenderBufferMtl.
8//
9
10#include "libANGLE/renderer/metal/RenderBufferMtl.h"
11
12#include "libANGLE/renderer/metal/ContextMtl.h"
13#include "libANGLE/renderer/metal/ImageMtl.h"
14#include "libANGLE/renderer/metal/mtl_format_utils.h"
15#include "libANGLE/renderer/metal/mtl_utils.h"
16
17namespace rx
18{
19
20RenderbufferMtl::RenderbufferMtl(const gl::RenderbufferState &state) : RenderbufferImpl(state) {}
21
22RenderbufferMtl::~RenderbufferMtl() {}
23
24void RenderbufferMtl::onDestroy(const gl::Context *context)
25{
26    releaseTexture();
27}
28
29void RenderbufferMtl::releaseTexture()
30{
31    mTexture           = nullptr;
32    mImplicitMSTexture = nullptr;
33}
34
35angle::Result RenderbufferMtl::setStorageImpl(const gl::Context *context,
36                                              GLsizei samples,
37                                              GLenum internalformat,
38                                              GLsizei width,
39                                              GLsizei height)
40{
41    ContextMtl *contextMtl = mtl::GetImpl(context);
42
43    if (mTexture != nullptr && mTexture->valid())
44    {
45        // Check against the state if we need to recreate the storage.
46        if (internalformat != mState.getFormat().info->internalFormat ||
47            width != mState.getWidth() || height != mState.getHeight() ||
48            samples != mState.getSamples())
49        {
50            releaseTexture();
51        }
52    }
53
54    const gl::InternalFormat &internalFormat = gl::GetSizedInternalFormatInfo(internalformat);
55    angle::FormatID angleFormatId =
56        angle::Format::InternalFormatToID(internalFormat.sizedInternalFormat);
57    mFormat = contextMtl->getPixelFormat(angleFormatId);
58
59    bool useImplicitResolve =
60        contextMtl->getDisplay()->getFeatures().alwaysResolveMultisampleRenderBuffers.enabled;
61
62    uint32_t actualSamples;
63    if (samples == 0)
64    {
65        actualSamples = 1;
66    }
67    else
68    {
69        // We always start at at least 2 samples
70        actualSamples = static_cast<uint32_t>(std::max<size_t>(2, samples));
71
72        const gl::TextureCaps &textureCaps =
73            contextMtl->getTextureCaps().get(mFormat.intendedFormatId);
74        actualSamples = textureCaps.getNearestSamples(actualSamples);
75        ANGLE_MTL_CHECK(contextMtl, actualSamples != 0, GL_INVALID_VALUE);
76    }
77
78    if ((mTexture == nullptr || !mTexture->valid()) && (width != 0 && height != 0))
79    {
80        if (actualSamples == 1 || (useImplicitResolve && mFormat.getCaps().resolve))
81        {
82            ANGLE_TRY(mtl::Texture::Make2DTexture(
83                contextMtl, mFormat, static_cast<uint32_t>(width), static_cast<uint32_t>(height), 1,
84                /* renderTargetOnly */ false,
85                /* allowFormatView */ mFormat.hasDepthAndStencilBits(), &mTexture));
86
87            // Use implicit resolve if alwaysResolveMultisampleRenderBuffers feature is enabled. At
88            // the end of every render pass, the MSAA render buffer will be automatically resolved
89            // to a single sampled texture.
90            if (actualSamples > 1)
91            {
92                // This format must supports implicit resolve
93                ASSERT(mFormat.getCaps().resolve);
94
95                ANGLE_TRY(mtl::Texture::Make2DMSTexture(
96                    contextMtl, mFormat, static_cast<uint32_t>(width),
97                    static_cast<uint32_t>(height), actualSamples,
98                    /* renderTargetOnly */ true,
99                    /* allowFormatView */ mFormat.hasDepthAndStencilBits(), &mImplicitMSTexture));
100            }
101        }
102        else
103        {
104            ANGLE_TRY(mtl::Texture::Make2DMSTexture(
105                contextMtl, mFormat, static_cast<uint32_t>(width), static_cast<uint32_t>(height),
106                actualSamples,
107                /* renderTargetOnly */ false,
108                /* allowFormatView */ mFormat.hasDepthAndStencilBits(), &mTexture));
109        }
110
111        mRenderTarget.setWithImplicitMSTexture(mTexture, mImplicitMSTexture,
112                                               mtl::kZeroNativeMipLevel, 0, mFormat);
113
114        // For emulated channels that GL texture intends to not have,
115        // we need to initialize their content.
116        bool emulatedChannels = mtl::IsFormatEmulated(mFormat);
117        if (emulatedChannels)
118        {
119            gl::ImageIndex index;
120
121            if (actualSamples > 1)
122            {
123                index = gl::ImageIndex::Make2DMultisample();
124            }
125            else
126            {
127                index = gl::ImageIndex::Make2D(0);
128            }
129
130            ANGLE_TRY(mtl::InitializeTextureContents(context, mTexture, mFormat,
131                                                     mtl::ImageNativeIndex(index, 0)));
132            if (mImplicitMSTexture)
133            {
134                ANGLE_TRY(mtl::InitializeTextureContents(
135                    context, mImplicitMSTexture, mFormat,
136                    mtl::ImageNativeIndex(gl::ImageIndex::Make2DMultisample(), 0)));
137            }
138        }  // if (emulatedChannels)
139        bool isDepthStencil = mFormat.hasDepthOrStencilBits();
140        if (isDepthStencil)
141        {
142            gl::ImageIndex index;
143            if (actualSamples > 1)
144            {
145                index = gl::ImageIndex::Make2DMultisample();
146            }
147            else
148            {
149                index = gl::ImageIndex::Make2D(0);
150            }
151            ANGLE_TRY(mtl::InitializeDepthStencilTextureContentsGPU(
152                context, mTexture, mFormat, mtl::ImageNativeIndex(index, 0)));
153            if (mImplicitMSTexture)
154            {
155                ANGLE_TRY(mtl::InitializeDepthStencilTextureContentsGPU(
156                    context, mImplicitMSTexture, mFormat,
157                    mtl::ImageNativeIndex(gl::ImageIndex::Make2DMultisample(), 0)));
158            }
159        }
160    }
161
162    return angle::Result::Continue;
163}
164
165angle::Result RenderbufferMtl::setStorage(const gl::Context *context,
166                                          GLenum internalformat,
167                                          GLsizei width,
168                                          GLsizei height)
169{
170    return setStorageImpl(context, 0, internalformat, width, height);
171}
172
173angle::Result RenderbufferMtl::setStorageMultisample(const gl::Context *context,
174                                                     GLsizei samples,
175                                                     GLenum internalformat,
176                                                     GLsizei width,
177                                                     GLsizei height,
178                                                     gl::MultisamplingMode mode)
179{
180    return setStorageImpl(context, samples, internalformat, width, height);
181}
182
183angle::Result RenderbufferMtl::setStorageEGLImageTarget(const gl::Context *context,
184                                                        egl::Image *image)
185{
186    releaseTexture();
187
188    ContextMtl *contextMtl = mtl::GetImpl(context);
189
190    ImageMtl *imageMtl = mtl::GetImpl(image);
191    mTexture           = imageMtl->getTexture();
192
193    const angle::FormatID angleFormatId =
194        angle::Format::InternalFormatToID(image->getFormat().info->sizedInternalFormat);
195    mFormat = contextMtl->getPixelFormat(angleFormatId);
196
197    mRenderTarget.set(mTexture, mtl::kZeroNativeMipLevel, 0, mFormat);
198
199    return angle::Result::Continue;
200}
201
202angle::Result RenderbufferMtl::getAttachmentRenderTarget(const gl::Context *context,
203                                                         GLenum binding,
204                                                         const gl::ImageIndex &imageIndex,
205                                                         GLsizei samples,
206                                                         FramebufferAttachmentRenderTarget **rtOut)
207{
208    ASSERT(mTexture && mTexture->valid());
209    *rtOut = &mRenderTarget;
210    return angle::Result::Continue;
211}
212
213angle::Result RenderbufferMtl::initializeContents(const gl::Context *context,
214                                                  GLenum binding,
215                                                  const gl::ImageIndex &imageIndex)
216{
217    if (imageIndex.valid())
218        return mtl::InitializeTextureContents(
219            context, mTexture, mFormat, mtl::ImageNativeIndex::FromBaseZeroGLIndex(imageIndex));
220    else
221        return mtl::InitializeTextureContents(
222            context, mTexture, mFormat,
223            mtl::ImageNativeIndex::FromBaseZeroGLIndex(gl::ImageIndex::Make2D(0)));
224}
225}  // namespace rx
226