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