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/ErrorStrings.h" 13#include "libANGLE/renderer/metal/ContextMtl.h" 14#include "libANGLE/renderer/metal/ImageMtl.h" 15#include "libANGLE/renderer/metal/mtl_format_utils.h" 16#include "libANGLE/renderer/metal/mtl_utils.h" 17 18namespace rx 19{ 20 21RenderbufferMtl::RenderbufferMtl(const gl::RenderbufferState &state) : RenderbufferImpl(state) {} 22 23RenderbufferMtl::~RenderbufferMtl() {} 24 25void RenderbufferMtl::onDestroy(const gl::Context *context) 26{ 27 releaseTexture(); 28} 29 30void RenderbufferMtl::releaseTexture() 31{ 32 mTexture = nullptr; 33 mImplicitMSTexture = nullptr; 34} 35 36angle::Result RenderbufferMtl::setStorageImpl(const gl::Context *context, 37 GLsizei samples, 38 GLenum internalformat, 39 GLsizei width, 40 GLsizei height, 41 gl::MultisamplingMode mode) 42{ 43 ContextMtl *contextMtl = mtl::GetImpl(context); 44 45 if (mTexture != nullptr && mTexture->valid()) 46 { 47 // Check against the state if we need to recreate the storage. 48 if (internalformat != mState.getFormat().info->internalFormat || 49 width != mState.getWidth() || height != mState.getHeight() || 50 samples != mState.getSamples()) 51 { 52 releaseTexture(); 53 } 54 } 55 56 const gl::InternalFormat &internalFormat = gl::GetSizedInternalFormatInfo(internalformat); 57 angle::FormatID angleFormatId = 58 angle::Format::InternalFormatToID(internalFormat.sizedInternalFormat); 59 mFormat = contextMtl->getPixelFormat(angleFormatId); 60 61 uint32_t actualSamples; 62 if (samples == 0) 63 { 64 actualSamples = 1; 65 } 66 else 67 { 68 // We always start at at least 2 samples 69 actualSamples = static_cast<uint32_t>(std::max<size_t>(2, samples)); 70 71 const gl::TextureCaps &textureCaps = 72 contextMtl->getTextureCaps().get(mFormat.intendedFormatId); 73 actualSamples = textureCaps.getNearestSamples(actualSamples); 74 ANGLE_CHECK(contextMtl, actualSamples != 0, gl::err::kInternalError, GL_INVALID_VALUE); 75 } 76 77 if ((mTexture == nullptr || !mTexture->valid()) && (width != 0 && height != 0)) 78 { 79 if (actualSamples == 1 || mode == gl::MultisamplingMode::MultisampledRenderToTexture) 80 { 81 ANGLE_TRY(mtl::Texture::Make2DTexture( 82 contextMtl, mFormat, static_cast<uint32_t>(width), static_cast<uint32_t>(height), 1, 83 /* renderTargetOnly */ false, 84 /* allowFormatView */ mFormat.hasDepthAndStencilBits(), &mTexture)); 85 86 if (mode == gl::MultisamplingMode::MultisampledRenderToTexture) 87 { 88 // This format must supports implicit resolve 89 ASSERT(mFormat.getCaps().resolve); 90 91 ANGLE_TRY(mtl::Texture::MakeMemoryLess2DMSTexture( 92 contextMtl, mFormat, static_cast<uint32_t>(width), 93 static_cast<uint32_t>(height), actualSamples, &mImplicitMSTexture)); 94 } 95 } 96 else 97 { 98 ANGLE_TRY(mtl::Texture::Make2DMSTexture( 99 contextMtl, mFormat, static_cast<uint32_t>(width), static_cast<uint32_t>(height), 100 actualSamples, 101 /* renderTargetOnly */ false, 102 /* allowFormatView */ mFormat.hasDepthAndStencilBits(), &mTexture)); 103 } 104 105 mRenderTarget.setWithImplicitMSTexture(mTexture, mImplicitMSTexture, 106 mtl::kZeroNativeMipLevel, 0, mFormat); 107 108 // For emulated channels that GL texture intends to not have, 109 // we need to initialize their content. 110 bool emulatedChannels = mtl::IsFormatEmulated(mFormat); 111 if (emulatedChannels) 112 { 113 gl::ImageIndex index; 114 115 if (mTexture->samples() > 1) 116 { 117 index = gl::ImageIndex::Make2DMultisample(); 118 } 119 else 120 { 121 index = gl::ImageIndex::Make2D(0); 122 } 123 124 ANGLE_TRY(mtl::InitializeTextureContents(context, mTexture, mFormat, 125 mtl::ImageNativeIndex(index, 0))); 126 } // if (emulatedChannels) 127 bool isDepthStencil = mFormat.hasDepthOrStencilBits(); 128 if (isDepthStencil) 129 { 130 gl::ImageIndex index; 131 if (mTexture->samples() > 1) 132 { 133 index = gl::ImageIndex::Make2DMultisample(); 134 } 135 else 136 { 137 index = gl::ImageIndex::Make2D(0); 138 } 139 ANGLE_TRY(mtl::InitializeDepthStencilTextureContentsGPU( 140 context, mTexture, mFormat, mtl::ImageNativeIndex(index, 0))); 141 } 142 } 143 144 return angle::Result::Continue; 145} 146 147angle::Result RenderbufferMtl::setStorage(const gl::Context *context, 148 GLenum internalformat, 149 GLsizei width, 150 GLsizei height) 151{ 152 return setStorageImpl(context, 0, internalformat, width, height, 153 gl::MultisamplingMode::Regular); 154} 155 156angle::Result RenderbufferMtl::setStorageMultisample(const gl::Context *context, 157 GLsizei samples, 158 GLenum internalformat, 159 GLsizei width, 160 GLsizei height, 161 gl::MultisamplingMode mode) 162{ 163 return setStorageImpl(context, samples, internalformat, width, height, mode); 164} 165 166angle::Result RenderbufferMtl::setStorageEGLImageTarget(const gl::Context *context, 167 egl::Image *image) 168{ 169 releaseTexture(); 170 171 ContextMtl *contextMtl = mtl::GetImpl(context); 172 173 ImageMtl *imageMtl = mtl::GetImpl(image); 174 mTexture = imageMtl->getTexture(); 175 176 const angle::FormatID angleFormatId = 177 angle::Format::InternalFormatToID(image->getFormat().info->sizedInternalFormat); 178 mFormat = contextMtl->getPixelFormat(angleFormatId); 179 180 mRenderTarget.set(mTexture, mtl::kZeroNativeMipLevel, 0, mFormat); 181 182 return angle::Result::Continue; 183} 184 185angle::Result RenderbufferMtl::getAttachmentRenderTarget(const gl::Context *context, 186 GLenum binding, 187 const gl::ImageIndex &imageIndex, 188 GLsizei samples, 189 FramebufferAttachmentRenderTarget **rtOut) 190{ 191 ASSERT(mTexture && mTexture->valid()); 192 *rtOut = &mRenderTarget; 193 return angle::Result::Continue; 194} 195 196angle::Result RenderbufferMtl::initializeContents(const gl::Context *context, 197 GLenum binding, 198 const gl::ImageIndex &imageIndex) 199{ 200 if (imageIndex.valid()) 201 return mtl::InitializeTextureContents( 202 context, mTexture, mFormat, mtl::ImageNativeIndex::FromBaseZeroGLIndex(imageIndex)); 203 else 204 return mtl::InitializeTextureContents( 205 context, mTexture, mFormat, 206 mtl::ImageNativeIndex::FromBaseZeroGLIndex(gl::ImageIndex::Make2D(0))); 207} 208} // namespace rx 209