blob: b6ebdfa7f91c04199c0a8757c62c2cc0c1c9eacf [file] [log] [blame]
// Copyright 2017 The Dawn Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "dawn_native/metal/TextureMTL.h"
#include "dawn_native/metal/DeviceMTL.h"
namespace dawn_native { namespace metal {
MTLPixelFormat MetalPixelFormat(dawn::TextureFormat format) {
switch (format) {
case dawn::TextureFormat::R8G8B8A8Unorm:
return MTLPixelFormatRGBA8Unorm;
case dawn::TextureFormat::R8G8Unorm:
return MTLPixelFormatRG8Unorm;
case dawn::TextureFormat::R8Unorm:
return MTLPixelFormatR8Unorm;
case dawn::TextureFormat::R8G8B8A8Uint:
return MTLPixelFormatRGBA8Uint;
case dawn::TextureFormat::R8G8Uint:
return MTLPixelFormatRG8Uint;
case dawn::TextureFormat::R8Uint:
return MTLPixelFormatR8Uint;
case dawn::TextureFormat::B8G8R8A8Unorm:
return MTLPixelFormatBGRA8Unorm;
case dawn::TextureFormat::D32FloatS8Uint:
return MTLPixelFormatDepth32Float_Stencil8;
}
}
namespace {
bool UsageNeedsTextureView(dawn::TextureUsageBit usage) {
constexpr dawn::TextureUsageBit kUsageNeedsTextureView =
dawn::TextureUsageBit::Storage | dawn::TextureUsageBit::Sampled;
return usage & kUsageNeedsTextureView;
}
MTLTextureUsage MetalTextureUsage(dawn::TextureUsageBit usage) {
MTLTextureUsage result = MTLTextureUsageUnknown; // This is 0
if (usage & (dawn::TextureUsageBit::Storage)) {
result |= MTLTextureUsageShaderWrite | MTLTextureUsageShaderRead;
}
if (usage & (dawn::TextureUsageBit::Sampled)) {
result |= MTLTextureUsageShaderRead;
}
if (usage & (dawn::TextureUsageBit::OutputAttachment)) {
result |= MTLTextureUsageRenderTarget;
}
if (UsageNeedsTextureView(usage)) {
result |= MTLTextureUsagePixelFormatView;
}
return result;
}
MTLTextureType MetalTextureType(dawn::TextureDimension dimension,
unsigned int arrayLayers) {
switch (dimension) {
case dawn::TextureDimension::e2D:
return (arrayLayers > 1) ? MTLTextureType2DArray : MTLTextureType2D;
}
}
MTLTextureType MetalTextureViewType(dawn::TextureViewDimension dimension) {
switch (dimension) {
case dawn::TextureViewDimension::e2D:
return MTLTextureType2D;
case dawn::TextureViewDimension::e2DArray:
return MTLTextureType2DArray;
case dawn::TextureViewDimension::Cube:
return MTLTextureTypeCube;
case dawn::TextureViewDimension::CubeArray:
return MTLTextureTypeCubeArray;
default:
UNREACHABLE();
return MTLTextureType2D;
}
}
bool RequiresCreatingNewTextureView(const TextureBase* texture,
const TextureViewDescriptor* textureViewDescriptor) {
if (texture->GetFormat() != textureViewDescriptor->format) {
return true;
}
if (texture->GetArrayLayers() != textureViewDescriptor->layerCount) {
return true;
}
if (texture->GetNumMipLevels() != textureViewDescriptor->levelCount) {
return true;
}
switch (textureViewDescriptor->dimension) {
case dawn::TextureViewDimension::Cube:
case dawn::TextureViewDimension::CubeArray:
return true;
default:
break;
}
return false;
}
}
Texture::Texture(Device* device, const TextureDescriptor* descriptor)
: TextureBase(device, descriptor) {
auto desc = [MTLTextureDescriptor new];
[desc autorelease];
desc.textureType = MetalTextureType(GetDimension(), GetArrayLayers());
desc.usage = MetalTextureUsage(GetUsage());
desc.pixelFormat = MetalPixelFormat(GetFormat());
const Extent3D& size = GetSize();
desc.width = size.width;
desc.height = size.height;
desc.depth = size.depth;
desc.mipmapLevelCount = GetNumMipLevels();
desc.arrayLength = GetArrayLayers();
desc.storageMode = MTLStorageModePrivate;
auto mtlDevice = device->GetMTLDevice();
mMtlTexture = [mtlDevice newTextureWithDescriptor:desc];
}
Texture::Texture(Device* device, const TextureDescriptor* descriptor, id<MTLTexture> mtlTexture)
: TextureBase(device, descriptor), mMtlTexture(mtlTexture) {
[mMtlTexture retain];
}
Texture::~Texture() {
[mMtlTexture release];
}
id<MTLTexture> Texture::GetMTLTexture() {
return mMtlTexture;
}
TextureView::TextureView(TextureBase* texture, const TextureViewDescriptor* descriptor)
: TextureViewBase(texture, descriptor) {
id<MTLTexture> mtlTexture = ToBackend(texture)->GetMTLTexture();
if (!UsageNeedsTextureView(texture->GetUsage())) {
mMtlTextureView = nil;
} else if (!RequiresCreatingNewTextureView(texture, descriptor)) {
mMtlTextureView = [mtlTexture retain];
} else {
MTLPixelFormat format = MetalPixelFormat(descriptor->format);
MTLTextureType textureViewType = MetalTextureViewType(descriptor->dimension);
auto mipLevelRange = NSMakeRange(descriptor->baseMipLevel, descriptor->levelCount);
auto arrayLayerRange = NSMakeRange(descriptor->baseArrayLayer, descriptor->layerCount);
mMtlTextureView = [mtlTexture newTextureViewWithPixelFormat:format
textureType:textureViewType
levels:mipLevelRange
slices:arrayLayerRange];
}
}
TextureView::~TextureView() {
[mMtlTextureView release];
}
id<MTLTexture> TextureView::GetMTLTexture() {
ASSERT(mMtlTextureView != nil);
return mMtlTextureView;
}
}} // namespace dawn_native::metal