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