• 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    uint32_t actualSamples;
60    if (samples == 0)
61    {
62        actualSamples = 1;
63    }
64    else
65    {
66        // We always start at at least 2 samples
67        actualSamples = static_cast<uint32_t>(std::max<size_t>(2, samples));
68
69        const gl::TextureCaps &textureCaps =
70            contextMtl->getTextureCaps().get(mFormat.intendedFormatId);
71        actualSamples = textureCaps.getNearestSamples(actualSamples);
72        ANGLE_MTL_CHECK(contextMtl, actualSamples != 0, GL_INVALID_VALUE);
73    }
74
75    if ((mTexture == nullptr || !mTexture->valid()) && (width != 0 && height != 0))
76    {
77        if (actualSamples == 1 || (mFormat.getCaps().resolve))
78        {
79            ANGLE_TRY(mtl::Texture::Make2DTexture(
80                contextMtl, mFormat, static_cast<uint32_t>(width), static_cast<uint32_t>(height), 1,
81                /* renderTargetOnly */ false,
82                /* allowFormatView */ mFormat.hasDepthAndStencilBits(), &mTexture));
83
84            // Use implicit resolve for depth stencil texture whenever possible. This is because
85            // for depth stencil texture, if stencil needs to be blitted, a formatted clone has
86            // to be created. And it is expensive to clone a multisample texture.
87            if (actualSamples > 1)
88            {
89                // This format must supports implicit resolve
90                ASSERT(mFormat.getCaps().resolve);
91
92                ANGLE_TRY(mtl::Texture::Make2DMSTexture(
93                    contextMtl, mFormat, static_cast<uint32_t>(width),
94                    static_cast<uint32_t>(height), actualSamples,
95                    /* renderTargetOnly */ true,
96                    /* allowFormatView */ mFormat.hasDepthAndStencilBits(), &mImplicitMSTexture));
97            }
98        }
99        else
100        {
101            ANGLE_TRY(mtl::Texture::Make2DMSTexture(
102                contextMtl, mFormat, static_cast<uint32_t>(width), static_cast<uint32_t>(height),
103                actualSamples,
104                /* renderTargetOnly */ false,
105                /* allowFormatView */ mFormat.hasDepthAndStencilBits(), &mTexture));
106        }
107
108        mRenderTarget.setWithImplicitMSTexture(mTexture, mImplicitMSTexture,
109                                               mtl::kZeroNativeMipLevel, 0, mFormat);
110
111        // For emulated channels that GL texture intends to not have,
112        // we need to initialize their content.
113        bool emulatedChannels = mtl::IsFormatEmulated(mFormat);
114        if (emulatedChannels)
115        {
116            gl::ImageIndex index;
117
118            if (actualSamples > 1)
119            {
120                index = gl::ImageIndex::Make2DMultisample();
121            }
122            else
123            {
124                index = gl::ImageIndex::Make2D(0);
125            }
126
127            ANGLE_TRY(mtl::InitializeTextureContents(context, mTexture, mFormat,
128                                                     mtl::ImageNativeIndex(index, 0)));
129            if (mImplicitMSTexture)
130            {
131                ANGLE_TRY(mtl::InitializeTextureContents(
132                    context, mImplicitMSTexture, mFormat,
133                    mtl::ImageNativeIndex(gl::ImageIndex::Make2DMultisample(), 0)));
134            }
135        }  // if (emulatedChannels)
136        bool isDepthStencil = mFormat.hasDepthOrStencilBits();
137        if (isDepthStencil)
138        {
139            gl::ImageIndex index;
140            if (actualSamples > 1)
141            {
142                index = gl::ImageIndex::Make2DMultisample();
143            }
144            else
145            {
146                index = gl::ImageIndex::Make2D(0);
147            }
148            ANGLE_TRY(mtl::InitializeDepthStencilTextureContentsGPU(
149                context, mTexture, mFormat, mtl::ImageNativeIndex(index, 0)));
150            if (mImplicitMSTexture)
151            {
152                ANGLE_TRY(mtl::InitializeDepthStencilTextureContentsGPU(
153                    context, mImplicitMSTexture, mFormat,
154                    mtl::ImageNativeIndex(gl::ImageIndex::Make2DMultisample(), 0)));
155            }
156        }
157    }
158
159    return angle::Result::Continue;
160}
161
162angle::Result RenderbufferMtl::setStorage(const gl::Context *context,
163                                          GLenum internalformat,
164                                          GLsizei width,
165                                          GLsizei height)
166{
167    return setStorageImpl(context, 0, internalformat, width, height);
168}
169
170angle::Result RenderbufferMtl::setStorageMultisample(const gl::Context *context,
171                                                     GLsizei samples,
172                                                     GLenum internalformat,
173                                                     GLsizei width,
174                                                     GLsizei height,
175                                                     gl::MultisamplingMode mode)
176{
177    return setStorageImpl(context, samples, internalformat, width, height);
178}
179
180angle::Result RenderbufferMtl::setStorageEGLImageTarget(const gl::Context *context,
181                                                        egl::Image *image)
182{
183    releaseTexture();
184
185    ContextMtl *contextMtl = mtl::GetImpl(context);
186
187    ImageMtl *imageMtl = mtl::GetImpl(image);
188    mTexture           = imageMtl->getTexture();
189
190    const angle::FormatID angleFormatId =
191        angle::Format::InternalFormatToID(image->getFormat().info->sizedInternalFormat);
192    mFormat = contextMtl->getPixelFormat(angleFormatId);
193
194    mRenderTarget.set(mTexture, mtl::kZeroNativeMipLevel, 0, mFormat);
195
196    return angle::Result::Continue;
197}
198
199angle::Result RenderbufferMtl::getAttachmentRenderTarget(const gl::Context *context,
200                                                         GLenum binding,
201                                                         const gl::ImageIndex &imageIndex,
202                                                         GLsizei samples,
203                                                         FramebufferAttachmentRenderTarget **rtOut)
204{
205    ASSERT(mTexture && mTexture->valid());
206    *rtOut = &mRenderTarget;
207    return angle::Result::Continue;
208}
209
210angle::Result RenderbufferMtl::initializeContents(const gl::Context *context,
211                                                  const gl::ImageIndex &imageIndex)
212{
213    if (imageIndex.valid())
214        return mtl::InitializeTextureContents(
215            context, mTexture, mFormat, mtl::ImageNativeIndex::FromBaseZeroGLIndex(imageIndex));
216    else
217        return mtl::InitializeTextureContents(
218            context, mTexture, mFormat,
219            mtl::ImageNativeIndex::FromBaseZeroGLIndex(gl::ImageIndex::Make2D(0)));
220}
221}
222