blob: d65937e8b9f09e1bd67d8b8eb5fbc023549117d3 [file] [log] [blame]
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "impeller/renderer/backend/metal/texture_mtl.h"
#include <memory>
#include "impeller/base/validation.h"
#include "impeller/core/texture_descriptor.h"
namespace impeller {
std::shared_ptr<Texture> WrapperMTL(TextureDescriptor desc,
const void* mtl_texture,
std::function<void()> deletion_proc) {
return TextureMTL::Wrapper(desc, (__bridge id<MTLTexture>)mtl_texture,
std::move(deletion_proc));
}
TextureMTL::TextureMTL(TextureDescriptor p_desc,
const AcquireTextureProc& aquire_proc,
bool wrapped,
bool drawable)
: Texture(p_desc), aquire_proc_(aquire_proc), is_drawable_(drawable) {
const auto& desc = GetTextureDescriptor();
if (!desc.IsValid() || !aquire_proc) {
return;
}
if (desc.size != GetSize()) {
VALIDATION_LOG << "The texture and its descriptor disagree about its size.";
return;
}
is_wrapped_ = wrapped;
is_valid_ = true;
}
std::shared_ptr<TextureMTL> TextureMTL::Wrapper(
TextureDescriptor desc,
id<MTLTexture> texture,
std::function<void()> deletion_proc) {
if (deletion_proc) {
return std::shared_ptr<TextureMTL>(
new TextureMTL(
desc, [texture]() { return texture; }, true),
[deletion_proc = std::move(deletion_proc)](TextureMTL* t) {
deletion_proc();
delete t;
});
}
return std::shared_ptr<TextureMTL>(
new TextureMTL(desc, [texture]() { return texture; }, true));
}
std::shared_ptr<TextureMTL> TextureMTL::Create(TextureDescriptor desc,
id<MTLTexture> texture) {
return std::make_shared<TextureMTL>(desc, [texture]() { return texture; });
}
TextureMTL::~TextureMTL() = default;
void TextureMTL::SetLabel(std::string_view label) {
if (is_drawable_) {
return;
}
[aquire_proc_() setLabel:@(label.data())];
}
// |Texture|
bool TextureMTL::OnSetContents(std::shared_ptr<const fml::Mapping> mapping,
size_t slice) {
// Metal has no threading restrictions. So we can pass this data along to the
// client rendering API immediately.
return OnSetContents(mapping->GetMapping(), mapping->GetSize(), slice);
}
// |Texture|
bool TextureMTL::OnSetContents(const uint8_t* contents,
size_t length,
size_t slice) {
if (!IsValid() || !contents || is_wrapped_ || is_drawable_) {
return false;
}
const auto& desc = GetTextureDescriptor();
// Out of bounds access.
if (length != desc.GetByteSizeOfBaseMipLevel()) {
return false;
}
const auto region =
MTLRegionMake2D(0u, 0u, desc.size.width, desc.size.height);
[aquire_proc_() replaceRegion:region //
mipmapLevel:0u //
slice:slice //
withBytes:contents //
bytesPerRow:desc.GetBytesPerRow() //
bytesPerImage:desc.GetByteSizeOfBaseMipLevel() //
];
return true;
}
ISize TextureMTL::GetSize() const {
if (is_drawable_) {
return GetTextureDescriptor().size;
}
const auto& texture = aquire_proc_();
return {static_cast<ISize::Type>(texture.width),
static_cast<ISize::Type>(texture.height)};
}
id<MTLTexture> TextureMTL::GetMTLTexture() const {
return aquire_proc_();
}
bool TextureMTL::IsValid() const {
return is_valid_;
}
bool TextureMTL::IsWrapped() const {
return is_wrapped_;
}
bool TextureMTL::IsDrawable() const {
return is_drawable_;
}
bool TextureMTL::GenerateMipmap(id<MTLBlitCommandEncoder> encoder) {
if (is_drawable_) {
return false;
}
auto texture = aquire_proc_();
if (!texture) {
return false;
}
[encoder generateMipmapsForTexture:texture];
mipmap_generated_ = true;
return true;
}
} // namespace impeller